@@ -62,7 +62,7 @@ SPDX-License-Identifier: AGPL-3.0-only
6262 </span >
6363 </div >
6464 <div v-if =" iAmModerator" class =" moderationNote" >
65- <MkTextarea v-if =" editModerationNote || (moderationNote != null && moderationNote !== ' ' )" v-model =" moderationNote " manualSave>
65+ <MkTextarea v-if =" editModerationNote || (moderationNote != null && moderationNote !== ' ' )" v-model =" moderationNote " manualSave @ savingStateChange = " ( changed ) => { isModerationNoteDirty = changed ; } " >
6666 <template #label >{{ i18n.ts.moderationNote }}</template >
6767 <template #caption >{{ i18n.ts.moderationNoteDescription }}</template >
6868 </MkTextarea >
@@ -144,7 +144,7 @@ SPDX-License-Identifier: AGPL-3.0-only
144144 </template >
145145 <div v-if =" !disableNotes" >
146146 <MkLazy >
147- <XTimeline :user =" user " />
147+ <XTimeline ref="timelineEl" :user =" user " />
148148 </MkLazy >
149149 </div >
150150 </div >
@@ -187,6 +187,7 @@ import MkSparkle from '@/components/MkSparkle.vue';
187187import { prefer } from ' @/preferences.js' ;
188188import MkPullToRefresh from ' @/components/MkPullToRefresh.vue' ;
189189import { isBirthday } from ' @/utility/is-birthday.js' ;
190+ import type XTimeline_TypeReferenceOnly from ' ./index.timeline.vue' ;
190191
191192function calcAge(birthdate : string ): number {
192193 const date = new Date (birthdate );
@@ -209,9 +210,12 @@ const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue'));
209210
210211const props = withDefaults (defineProps <{
211212 user: Misskey .entities .UserDetailed ;
213+ /** Refetches the user in place. Supplied by the parent page. */
214+ refreshUser? : () => Promise <void >;
212215 /** Test only; MkNotesTimeline currently causes problems in vitest */
213216 disableNotes? : boolean ;
214217}>(), {
218+ refreshUser: undefined ,
215219 disableNotes: false ,
216220});
217221
@@ -226,13 +230,18 @@ const narrow = ref<null | boolean>(null);
226230const rootEl = useTemplateRef (' rootEl' );
227231const bannerEl = useTemplateRef (' bannerEl' );
228232const memoTextareaEl = useTemplateRef (' memoTextareaEl' );
233+ const timelineEl = useTemplateRef <InstanceType <typeof XTimeline_TypeReferenceOnly >>(' timelineEl' );
229234const memoDraft = ref (props .user .memo );
230235const isEditingMemo = ref (false );
231236const moderationNote = ref (props .user .moderationNote ?? ' ' );
232237const editModerationNote = ref (false );
238+ const isModerationNoteDirty = ref (false );
233239
234- watch (moderationNote , async () => {
235- await misskeyApi (' admin/update-user-note' , { userId: props .user .id , text: moderationNote .value });
240+ watch (moderationNote , async (newValue ) => {
241+ // 再取得した値を同期しただけの場合は保存しない
242+ if (newValue === (user .value .moderationNote ?? ' ' )) return ;
243+ await misskeyApi (' admin/update-user-note' , { userId: user .value .id , text: newValue });
244+ user .value = { ... user .value , moderationNote: newValue };
236245});
237246
238247const style = computed (() => {
@@ -278,12 +287,20 @@ async function updateMemo() {
278287 isEditingMemo .value = false ;
279288}
280289
281- watch ([props .user ], () => {
290+ watch (() => props .user , () => {
291+ user .value = props .user ;
292+ // 編集中は上書きしない (入力中の内容を消してしまう)
293+ if (! isModerationNoteDirty .value ) moderationNote .value = props .user .moderationNote ?? ' ' ;
294+ if (isEditingMemo .value ) return ;
282295 memoDraft .value = props .user .memo ;
283296});
284297
298+ // ここでは失敗は握りつぶす(Pull to Refreshがもどらなくなるので)
285299async function reload() {
286- // TODO
300+ await Promise .allSettled ([
301+ props .refreshUser ?.(),
302+ timelineEl .value ?.reload (),
303+ ]);
287304}
288305
289306let bannerParallaxResizeObserver: ResizeObserver | null = null ;
0 commit comments