enhance(frontend): 노트를 편집한 시간이 개별적으로 표시됨

This commit is contained in:
NoriDev 2023-10-19 18:48:59 +09:00
commit 526565db72
8 changed files with 51 additions and 2 deletions

View file

@ -32,6 +32,7 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE
- Feat: 노트 편집 시 토스트 알림을 표시하고 사운드를 재생 - Feat: 노트 편집 시 토스트 알림을 표시하고 사운드를 재생
- Enhance: 노트를 편집할 때 편집 중인 노트임을 강조함 - Enhance: 노트를 편집할 때 편집 중인 노트임을 강조함
- Enhance: 타임라인에서 새 노트가 20개 이상이면 '20+'로 표기 - Enhance: 타임라인에서 새 노트가 20개 이상이면 '20+'로 표기
- Enhance: 노트를 편집한 시간이 개별적으로 표시됨
- Fix: '새 노트 알림'을 '노트 수 표시'로 설정했을 때 한국어 이외의 언어에서 내용이 표시되지 않음 - Fix: '새 노트 알림'을 '노트 수 표시'로 설정했을 때 한국어 이외의 언어에서 내용이 표시되지 않음
### Server ### Server

View file

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey, cherrypick contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class NoteUpdateAtHistory1696318192428 {
name = 'NoteUpdateAtHistory1696318192428'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" ADD "updatedAtHistory" TIMESTAMP WITH TIME ZONE array`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" DROP "updatedAtHistory"`);
}
}

View file

@ -339,6 +339,7 @@ export class NoteEntityService implements OnModuleInit {
id: note.id, id: note.id,
createdAt: this.idService.parse(note.id).date.toISOString(), createdAt: this.idService.parse(note.id).date.toISOString(),
updatedAt: note.updatedAt ? note.updatedAt.toISOString() : undefined, updatedAt: note.updatedAt ? note.updatedAt.toISOString() : undefined,
updatedAtHistory: note.updatedAtHistory ? note.updatedAtHistory.map(x => x.toISOString()) : undefined,
noteEditHistory: note.noteEditHistory.length ? note.noteEditHistory : undefined, noteEditHistory: note.noteEditHistory.length ? note.noteEditHistory : undefined,
userId: note.userId, userId: note.userId,
user: this.userEntityService.pack(note.user ?? note.userId, me, { user: this.userEntityService.pack(note.user ?? note.userId, me, {

View file

@ -23,6 +23,12 @@ export class MiNote {
}) })
public updatedAt: Date | null; public updatedAt: Date | null;
@Column('timestamp with time zone', {
array: true,
default: null,
})
public updatedAtHistory: Date[] | null;
@Column('varchar', { @Column('varchar', {
length: 3000, length: 3000,
array: true, array: true,

View file

@ -22,6 +22,15 @@ export const packedNoteSchema = {
optional: true, nullable: true, optional: true, nullable: true,
format: 'date-time', format: 'date-time',
}, },
updatedAtHistory: {
type: 'array',
optional: true, nullable: true,
items: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
},
noteEditHistory: { noteEditHistory: {
type: 'array', type: 'array',
optional: true, nullable: false, optional: true, nullable: false,

View file

@ -74,10 +74,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.noSuchNote); throw new ApiError(meta.errors.noSuchNote);
} }
const updatedAtHistory = note.updatedAtHistory ? note.updatedAtHistory : [];
await this.notesRepository.update({ id: note.id }, { await this.notesRepository.update({ id: note.id }, {
updatedAt: new Date(), updatedAt: new Date(),
cw: ps.cw, cw: ps.cw,
text: ps.text, text: ps.text,
updatedAtHistory: [...updatedAtHistory, new Date()],
noteEditHistory: [...note.noteEditHistory, note.text!], noteEditHistory: [...note.noteEditHistory, note.text!],
}); });

View file

@ -181,6 +181,7 @@ export type Note = {
id: ID; id: ID;
createdAt: DateString; createdAt: DateString;
updatedAt?: DateString | null; updatedAt?: DateString | null;
updatedAtHistory: DateString[] | null;
noteEditHistory: string[]; noteEditHistory: string[];
text: string | null; text: string | null;
cw: string | null; cw: string | null;

View file

@ -221,6 +221,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.historyMain"> <div :class="$style.historyMain">
<div :class="$style.historyHeader"> <div :class="$style.historyHeader">
<MkUserName :user="appearNote.user" :nowrap="true"/> <MkUserName :user="appearNote.user" :nowrap="true"/>
<MkTime :class="$style.updatedAt" :time="appearNote.updatedAtHistory![index]"/>
</div> </div>
<div> <div>
<div> <div>
@ -236,6 +237,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</div> </div>
</div> </div>
<div v-if="appearNote.noteEditHistory == null" class="_fullinfo">
<img :src="infoImageUrl" class="_ghost"/>
<div>{{ i18n.ts.nothing }}</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -289,7 +294,7 @@ import MkPagination, { Paging } from '@/components/MkPagination.vue';
import MkReactionIcon from '@/components/MkReactionIcon.vue'; import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { instance } from '@/instance.js'; import { infoImageUrl, instance } from '@/instance.js';
import MkPostForm from '@/components/MkPostFormSimple.vue'; import MkPostForm from '@/components/MkPostFormSimple.vue';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/scripts/device-kind.js';
@ -1082,11 +1087,12 @@ onMounted(() => {
} }
.historyHeader { .historyHeader {
display: flex;
margin-bottom: 2px; margin-bottom: 2px;
font-weight: bold; font-weight: bold;
width: 100%; width: 100%;
overflow: clip; overflow: clip;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.avatar { .avatar {
flex-shrink: 0 !important; flex-shrink: 0 !important;
@ -1098,6 +1104,12 @@ onMounted(() => {
pointer-events: none !important; pointer-events: none !important;
} }
.updatedAt {
flex-shrink: 0;
margin-left: auto;
font-size: 0.9em;
}
.muted { .muted {
padding: 8px; padding: 8px;
text-align: center; text-align: center;