From adf3493af855cc23e3e4b82c2fa462e05c4a26c1 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Tue, 8 Feb 2022 23:12:37 +0900
Subject: [PATCH] =?UTF-8?q?feat:=20notes/instance/perUserNotes=E3=83=81?=
 =?UTF-8?q?=E3=83=A3=E3=83=BC=E3=83=88=E3=81=AB=E6=B7=BB=E4=BB=98=E3=83=95?=
 =?UTF-8?q?=E3=82=A1=E3=82=A4=E3=83=AB=E4=BB=98=E3=81=8D=E3=83=8E=E3=83=BC?=
 =?UTF-8?q?=E3=83=88=E3=81=AE=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CHANGELOG.md                                  |  3 ++-
 .../migration/1644328606241-chart-v12.js      | 27 +++++++++++++++++++
 .../chart/charts/entities/instance.ts         |  1 +
 .../services/chart/charts/entities/notes.ts   |  2 ++
 .../chart/charts/entities/per-user-notes.ts   |  1 +
 .../src/services/chart/charts/instance.ts     |  1 +
 .../src/services/chart/charts/notes.ts        |  1 +
 .../services/chart/charts/per-user-notes.ts   |  1 +
 packages/client/src/components/chart.vue      | 25 +++++++++++++++--
 9 files changed, 59 insertions(+), 3 deletions(-)
 create mode 100644 packages/backend/migration/1644328606241-chart-v12.js

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 225de735ac..8746328a5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,11 +14,12 @@ You should also include the user name that made the change.
 
 ### Note
 このリリースはマイグレーションの規模が大きいため、インスタンスによってはマイグレーションに時間がかかる可能性があります。
-マイグレーションが終わらない場合は、チャートの情報はリセットされてしまいますが`___chart___`で始まるテーブルの**レコード**を全て削除(テーブル自体は消さないでください)してから再度試す方法もあります。
+マイグレーションが終わらない場合は、チャートの情報はリセットされてしまいますが`__chart__`で始まるテーブルの**レコード**を全て削除(テーブル自体は消さないでください)してから再度試す方法もあります。
 
 ### Improvements
 - チャートエンジンの強化 @syuilo
 	- テーブルサイズの削減
+	- notes/instance/perUserNotesチャートに添付ファイル付きノートの数を追加
 	- activeUsersチャートに新しい項目を追加
 	- federationチャートに新しい項目を追加
 	- apRequestチャートを追加
diff --git a/packages/backend/migration/1644328606241-chart-v12.js b/packages/backend/migration/1644328606241-chart-v12.js
new file mode 100644
index 0000000000..226de6ece9
--- /dev/null
+++ b/packages/backend/migration/1644328606241-chart-v12.js
@@ -0,0 +1,27 @@
+const { MigrationInterface, QueryRunner } = require("typeorm");
+
+module.exports = class chartV121644328606241 {
+    name = 'chartV121644328606241'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "___local_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart__notes" ADD "___remote_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__notes" ADD "___local_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__notes" ADD "___remote_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart__instance" ADD "___notes_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__instance" ADD "___notes_diffs_withFile" integer NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" ADD "___diffs_withFile" smallint NOT NULL DEFAULT '0'`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" ADD "___diffs_withFile" smallint NOT NULL DEFAULT '0'`);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "__chart_day__per_user_notes" DROP COLUMN "___diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart__per_user_notes" DROP COLUMN "___diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__instance" DROP COLUMN "___notes_diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart__instance" DROP COLUMN "___notes_diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__notes" DROP COLUMN "___remote_diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart_day__notes" DROP COLUMN "___local_diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "___remote_diffs_withFile"`);
+        await queryRunner.query(`ALTER TABLE "__chart__notes" DROP COLUMN "___local_diffs_withFile"`);
+    }
+}
diff --git a/packages/backend/src/services/chart/charts/entities/instance.ts b/packages/backend/src/services/chart/charts/entities/instance.ts
index 0ff9e7b6b8..b98e1640c8 100644
--- a/packages/backend/src/services/chart/charts/entities/instance.ts
+++ b/packages/backend/src/services/chart/charts/entities/instance.ts
@@ -12,6 +12,7 @@ export const schema = {
 	'notes.diffs.normal': {},
 	'notes.diffs.reply': {},
 	'notes.diffs.renote': {},
+	'notes.diffs.withFile': {},
 	'users.total': { accumulate: true },
 	'users.inc': { range: 'small' },
 	'users.dec': { range: 'small' },
diff --git a/packages/backend/src/services/chart/charts/entities/notes.ts b/packages/backend/src/services/chart/charts/entities/notes.ts
index 296328f102..f9b9b20eed 100644
--- a/packages/backend/src/services/chart/charts/entities/notes.ts
+++ b/packages/backend/src/services/chart/charts/entities/notes.ts
@@ -9,12 +9,14 @@ export const schema = {
 	'local.diffs.normal': {},
 	'local.diffs.reply': {},
 	'local.diffs.renote': {},
+	'local.diffs.withFile': {},
 	'remote.total': { accumulate: true },
 	'remote.inc': {},
 	'remote.dec': {},
 	'remote.diffs.normal': {},
 	'remote.diffs.reply': {},
 	'remote.diffs.renote': {},
+	'remote.diffs.withFile': {},
 } as const;
 
 export const entity = Chart.schemaToEntity(name, schema);
diff --git a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts
index bf7e4422be..562cde9b00 100644
--- a/packages/backend/src/services/chart/charts/entities/per-user-notes.ts
+++ b/packages/backend/src/services/chart/charts/entities/per-user-notes.ts
@@ -9,6 +9,7 @@ export const schema = {
 	'diffs.normal': { range: 'small' },
 	'diffs.reply': { range: 'small' },
 	'diffs.renote': { range: 'small' },
+	'diffs.withFile': { range: 'small' },
 } as const;
 
 export const entity = Chart.schemaToEntity(name, schema, true);
diff --git a/packages/backend/src/services/chart/charts/instance.ts b/packages/backend/src/services/chart/charts/instance.ts
index 4f953cd690..5ea4d567e1 100644
--- a/packages/backend/src/services/chart/charts/instance.ts
+++ b/packages/backend/src/services/chart/charts/instance.ts
@@ -74,6 +74,7 @@ export default class InstanceChart extends Chart<typeof schema> {
 			'notes.diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0,
 			'notes.diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0,
 			'notes.diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0,
+			'notes.diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
 		}, toPuny(host));
 	}
 
diff --git a/packages/backend/src/services/chart/charts/notes.ts b/packages/backend/src/services/chart/charts/notes.ts
index 4bbfa6704f..5c56a9a718 100644
--- a/packages/backend/src/services/chart/charts/notes.ts
+++ b/packages/backend/src/services/chart/charts/notes.ts
@@ -38,6 +38,7 @@ export default class NotesChart extends Chart<typeof schema> {
 			[`${prefix}.diffs.normal`]: note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0,
 			[`${prefix}.diffs.renote`]: note.renoteId != null ? (isAdditional ? 1 : -1) : 0,
 			[`${prefix}.diffs.reply`]: note.replyId != null ? (isAdditional ? 1 : -1) : 0,
+			[`${prefix}.diffs.withFile`]: note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
 		});
 	}
 }
diff --git a/packages/backend/src/services/chart/charts/per-user-notes.ts b/packages/backend/src/services/chart/charts/per-user-notes.ts
index ead353139b..6a4f0363b2 100644
--- a/packages/backend/src/services/chart/charts/per-user-notes.ts
+++ b/packages/backend/src/services/chart/charts/per-user-notes.ts
@@ -34,6 +34,7 @@ export default class PerUserNotesChart extends Chart<typeof schema> {
 			'diffs.normal': note.replyId == null && note.renoteId == null ? (isAdditional ? 1 : -1) : 0,
 			'diffs.renote': note.renoteId != null ? (isAdditional ? 1 : -1) : 0,
 			'diffs.reply': note.replyId != null ? (isAdditional ? 1 : -1) : 0,
+			'diffs.withFile': note.fileIds.length > 0 ? (isAdditional ? 1 : -1) : 0,
 		}, user.id);
 	}
 }
diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue
index a0a4755d12..5e96429e80 100644
--- a/packages/client/src/components/chart.vue
+++ b/packages/client/src/components/chart.vue
@@ -63,9 +63,16 @@ const alpha = (hex, a) => {
 	return `rgba(${r}, ${g}, ${b}, ${a})`;
 };
 
-const colors = ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#e300db'];
+const colors = {
+	blue: '#008FFB',
+	green: '#00E396',
+	yellow: '#FEB019',
+	red: '#FF4560',
+	purple: '#e300db',
+};
+const colorSets = [colors.blue, colors.green, colors.yellow, colors.red, colors.purple];
 const getColor = (i) => {
-	return colors[i % colors.length];
+	return colorSets[i % colorSets.length];
 };
 
 export default defineComponent({
@@ -251,6 +258,7 @@ export default defineComponent({
 							ticks: {
 								display: props.detailed,
 								maxRotation: 0,
+								autoSkipPadding: 16,
 							},
 							adapters: {
 								date: {
@@ -268,6 +276,7 @@ export default defineComponent({
 							},
 							ticks: {
 								display: props.detailed,
+								//mirror: true,
 							},
 						},
 					},
@@ -412,6 +421,7 @@ export default defineComponent({
 						? sum(raw.local.inc, negate(raw.local.dec), raw.remote.inc, negate(raw.remote.dec))
 						: sum(raw[type].inc, negate(raw[type].dec))
 					),
+					color: '#888888',
 				}, {
 					name: 'Renotes',
 					type: 'area',
@@ -419,6 +429,7 @@ export default defineComponent({
 						? sum(raw.local.diffs.renote, raw.remote.diffs.renote)
 						: raw[type].diffs.renote
 					),
+					color: colors.green,
 				}, {
 					name: 'Replies',
 					type: 'area',
@@ -426,6 +437,7 @@ export default defineComponent({
 						? sum(raw.local.diffs.reply, raw.remote.diffs.reply)
 						: raw[type].diffs.reply
 					),
+					color: colors.yellow,
 				}, {
 					name: 'Normal',
 					type: 'area',
@@ -433,6 +445,15 @@ export default defineComponent({
 						? sum(raw.local.diffs.normal, raw.remote.diffs.normal)
 						: raw[type].diffs.normal
 					),
+					color: colors.blue,
+				}, {
+					name: 'With file',
+					type: 'area',
+					data: format(type == 'combined'
+						? sum(raw.local.diffs.withFile, raw.remote.diffs.withFile)
+						: raw[type].diffs.withFile
+					),
+					color: colors.purple,
 				}],
 			};
 		};