enhance: タイムラインからRenoteを除外するオプションを追加

This commit is contained in:
syuilo 2023-09-28 15:32:47 +09:00 committed by Insert5StarName
parent 0e7a1ac44e
commit 408def474b
6 changed files with 78 additions and 2 deletions

View file

@ -4,6 +4,7 @@
*/ */
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Brackets } from 'typeorm';
import type { NotesRepository } from '@/models/_.js'; import type { NotesRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js'; import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js'; import { QueryService } from '@/core/QueryService.js';
@ -40,6 +41,7 @@ export const paramDef = {
properties: { properties: {
withFiles: { type: 'boolean', default: false }, withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false }, withReplies: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' }, sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' },
@ -88,6 +90,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) { if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\''); query.andWhere('note.fileIds != \'{}\'');
} }
if (ps.withRenotes === false) {
query.andWhere(new Brackets(qb => {
qb.orWhere('note.renoteId IS NULL');
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
}));
}));
}
//#endregion //#endregion
const timeline = await query.limit(ps.limit).getMany(); const timeline = await query.limit(ps.limit).getMany();

View file

@ -52,6 +52,7 @@ export const paramDef = {
includeLocalRenotes: { type: 'boolean', default: true }, includeLocalRenotes: { type: 'boolean', default: true },
withFiles: { type: 'boolean', default: false }, withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false }, withReplies: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
}, },
required: [], required: [],
} as const; } as const;
@ -137,6 +138,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) { if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\''); query.andWhere('note.fileIds != \'{}\'');
} }
if (ps.withRenotes === false) {
query.andWhere(new Brackets(qb => {
qb.orWhere('note.renoteId IS NULL');
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
}));
}));
}
//#endregion //#endregion
const timeline = await query.limit(ps.limit).getMany(); const timeline = await query.limit(ps.limit).getMany();

View file

@ -42,6 +42,7 @@ export const paramDef = {
properties: { properties: {
withFiles: { type: 'boolean', default: false }, withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false }, withReplies: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
fileType: { type: 'array', items: { fileType: { type: 'array', items: {
type: 'string', type: 'string',
} }, } },
@ -110,6 +111,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)'); query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)');
} }
} }
if (ps.withRenotes === false) {
query.andWhere(new Brackets(qb => {
qb.orWhere('note.renoteId IS NULL');
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
}));
}));
}
//#endregion //#endregion
const timeline = await query.limit(ps.limit).getMany(); const timeline = await query.limit(ps.limit).getMany();

View file

@ -42,6 +42,7 @@ export const paramDef = {
includeLocalRenotes: { type: 'boolean', default: true }, includeLocalRenotes: { type: 'boolean', default: true },
withFiles: { type: 'boolean', default: false }, withFiles: { type: 'boolean', default: false },
withReplies: { type: 'boolean', default: false }, withReplies: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
}, },
required: [], required: [],
} as const; } as const;
@ -126,6 +127,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withFiles) { if (ps.withFiles) {
query.andWhere('note.fileIds != \'{}\''); query.andWhere('note.fileIds != \'{}\'');
} }
if (ps.withRenotes === false) {
query.andWhere(new Brackets(qb => {
qb.orWhere('note.renoteId IS NULL');
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
}));
}));
}
//#endregion //#endregion
const timeline = await query.limit(ps.limit).getMany(); const timeline = await query.limit(ps.limit).getMany();

View file

@ -30,6 +30,8 @@ export type Column = {
roleId?: string; roleId?: string;
includingTypes?: typeof notificationTypes[number][]; includingTypes?: typeof notificationTypes[number][];
tl?: 'home' | 'local' | 'social' | 'global'; tl?: 'home' | 'local' | 'social' | 'global';
withRenotes?: boolean;
withReplies?: boolean;
}; };
export const deckStore = markRaw(new Storage('deck', { export const deckStore = markRaw(new Storage('deck', {

View file

@ -20,12 +20,19 @@ SPDX-License-Identifier: AGPL-3.0-only
</p> </p>
<p :class="$style.disabledDescription">{{ i18n.ts._disabledTimeline.description }}</p> <p :class="$style.disabledDescription">{{ i18n.ts._disabledTimeline.description }}</p>
</div> </div>
<MkTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl"/> <MkTimeline
v-else-if="column.tl"
ref="timeline"
:key="column.tl + withRenotes + withReplies"
:src="column.tl"
:withRenotes="withRenotes"
:withReplies="withReplies"
/>
</XColumn> </XColumn>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted } from 'vue'; import { onMounted, watch } from 'vue';
import XColumn from './column.vue'; import XColumn from './column.vue';
import { removeColumn, updateColumn, Column } from './deck-store.js'; import { removeColumn, updateColumn, Column } from './deck-store.js';
import MkTimeline from '@/components/MkTimeline.vue'; import MkTimeline from '@/components/MkTimeline.vue';
@ -43,6 +50,20 @@ let disabled = $ref(false);
const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable)); const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable)); const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
const withRenotes = $ref(props.column.withRenotes ?? true);
const withReplies = $ref(props.column.withReplies ?? false);
watch($$(withRenotes), v => {
updateColumn(props.column.id, {
withRenotes: v,
});
});
watch($$(withReplies), v => {
updateColumn(props.column.id, {
withReplies: v,
});
});
onMounted(() => { onMounted(() => {
if (props.column.tl == null) { if (props.column.tl == null) {
@ -82,6 +103,14 @@ const menu = [{
icon: 'ti ti-pencil', icon: 'ti ti-pencil',
text: i18n.ts.timeline, text: i18n.ts.timeline,
action: setType, action: setType,
}, {
type: 'switch',
text: i18n.ts.showRenotes,
ref: $$(withRenotes),
}, {
type: 'switch',
text: i18n.ts.withReplies,
ref: $$(withReplies),
}]; }];
</script> </script>