diff --git a/packages/frontend/src/components/MkEditForm.vue b/packages/frontend/src/components/MkEditForm.vue index d339183f03..6ba08c1f88 100644 --- a/packages/frontend/src/components/MkEditForm.vue +++ b/packages/frontend/src/components/MkEditForm.vue @@ -108,7 +108,6 @@ const props = withDefaults(defineProps<{ initialFiles?: Misskey.entities.DriveFile[]; initialLocalOnly?: boolean; initialVisibleUsers?: Misskey.entities.UserDetailed[]; - initialNote?: Misskey.entities.Note; instant?: boolean; fixed?: boolean; autofocus?: boolean; @@ -162,9 +161,9 @@ const draftKey = computed((): string => { } else if (props.reply) { key += `reply:${props.reply.id}`; } else { - key += `note:${$i.id}`; + key += `note:${props.target.id}`; } - + key += ':edit'; return key; }); @@ -498,20 +497,9 @@ async function post(ev?: MouseEvent) { let postData = { noteId: props.target.id, text: text.value === '' ? '' : text.value, - fileIds: files.value.length > 0 ? files.value.map(f => f.id) : null, + fileIds: files.value.length > 0 ? files.value.map(f => f.id) : undefined, poll: poll.value ?? null, cw: useCw.value ? cw.value ?? '' : null, - } as { - noteId: string; - text: string; - cw: string | null; - fileIds?: string[]; - poll?: ({ - choices: string[]; - multiple?: boolean; - expiresAt?: number | null; - expiredAfter?: number | null; - }) | null; }; if (withHashtags.value && hashtags.value && hashtags.value.trim() !== '') { @@ -695,6 +683,21 @@ onMounted(() => { if (hashtagsInputEl.value) new Autocomplete(hashtagsInputEl.value, hashtags); nextTick(() => { + const init = props.target; + text.value = init.text ? init.text : ''; + files.value = init.files ?? []; + cw.value = init.cw ?? null; + useCw.value = init.cw != null; + if (init.poll) { + poll.value = { + choices: init.poll.choices.map(x => x.text), + multiple: init.poll.multiple, + expiresAt: init.poll.expiresAt ? (new Date(init.poll.expiresAt)).getTime() : null, + expiredAfter: null, + }; + } + quoteId.value = init.renote ? init.renote.id : null; + // 書きかけの投稿を復元 if (!props.instant && !props.mention && !props.specified && !props.mock) { const draft = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}')[draftKey.value]; @@ -709,24 +712,6 @@ onMounted(() => { } } - // 削除して編集 - if (props.initialNote) { - const init = props.initialNote; - text.value = init.text ? init.text : ''; - files.value = init.files ?? []; - cw.value = init.cw ?? null; - useCw.value = init.cw != null; - if (init.poll) { - poll.value = { - choices: init.poll.choices.map(x => x.text), - multiple: init.poll.multiple, - expiresAt: init.poll.expiresAt ? (new Date(init.poll.expiresAt)).getTime() : null, - expiredAfter: null, - }; - } - quoteId.value = init.renote ? init.renote.id : null; - } - nextTick(() => watchForDraft()); }); }); diff --git a/packages/frontend/src/components/MkEditFormDialog.vue b/packages/frontend/src/components/MkEditFormDialog.vue new file mode 100644 index 0000000000..b8df7bc15a --- /dev/null +++ b/packages/frontend/src/components/MkEditFormDialog.vue @@ -0,0 +1,59 @@ + + + + + + + diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 6457b811be..c47334feda 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -4,14 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> +
+ + + +
@@ -204,6 +195,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue'; import * as mfm from 'mfm-js'; import * as Misskey from 'misskey-js'; +import MkNoteHistory from '@/components/MkNoteHistory.vue'; import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue'; import MkReactionsViewer from '@/components/MkReactionsViewer.vue'; @@ -355,6 +347,14 @@ const reactionsPagination = computed(() => ({ }, })); +const historiesPagination = computed(() => ({ + endpoint: 'notes/histories', + limit: 10, + params: { + noteId: appearNote.value.id, + }, +})); + useNoteCapture({ rootEl: rootEl, note: appearNote, @@ -806,6 +806,10 @@ function loadConversation() { padding: 16px; } +.tab_histories { + padding: 16px; +} + .reactionTabs { display: flex; gap: 8px; diff --git a/packages/frontend/src/components/MkNoteHistory.vue b/packages/frontend/src/components/MkNoteHistory.vue new file mode 100644 index 0000000000..8645be9a32 --- /dev/null +++ b/packages/frontend/src/components/MkNoteHistory.vue @@ -0,0 +1,145 @@ + + + + + + + diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index 3085f33e21..e3205a3b7e 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -13,6 +13,7 @@ import type { Form, GetFormResultType } from '@/scripts/form.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; import MkPostFormDialog from '@/components/MkPostFormDialog.vue'; +import MkEditFormDialog from '@/components/MkEditFormDialog.vue'; import MkWaitingDialog from '@/components/MkWaitingDialog.vue'; import MkPageWindow from '@/components/MkPageWindow.vue'; import MkToast from '@/components/MkToast.vue'; @@ -696,6 +697,27 @@ export function post(props: Record = {}): Promise { }); } +export function edit(props: Record = {}): Promise { + pleaseLogin(undefined, (props.initialText || props.initialNote ? { + type: 'share', + params: { + text: props.initialText ?? props.initialNote.text, + visibility: props.initialVisibility ?? props.initialNote?.visibility, + localOnly: (props.initialLocalOnly || props.initialNote?.localOnly) ? '1' : '0', + }, + } : undefined)); + + showMovedDialog(); + return new Promise(resolve => { + const { dispose } = popup(MkEditFormDialog, props, { + closed: () => { + resolve(); + dispose(); + }, + }); + }); +} + export const deckGlobalEvents = new EventEmitter(); /* diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index ebb96d1746..1837b16bd3 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -288,6 +288,10 @@ export function getNoteMenu(props: { props.translation.value = res; } + function edit() { + os.edit({ target: appearNote, renote: appearNote.renote, reply: appearNote.reply, channel: appearNote.channel }); + } + let menu: MenuItem[]; if ($i) { const statePromise = misskeyApi('notes/state', { @@ -427,6 +431,11 @@ export function getNoteMenu(props: { ), ...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [ { type: 'divider' }, + $i.policies.canEditNote || $i.isModerator || $i.isAdmin ? { + icon: 'ti ti-edit', + text: i18n.ts.edit, + action: edit, + } : undefined, appearNote.userId === $i.id ? { icon: 'ti ti-edit', text: i18n.ts.deleteAndEdit,