From 22c4e9d7ecf5a659832ea32244e46a40627bfc8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?=
 <67428053+kakkokari-gtyih@users.noreply.github.com>
Date: Sat, 27 Jul 2024 18:09:57 +0900
Subject: [PATCH] =?UTF-8?q?fix(frontend):=20modal=E3=81=8C=E6=AD=A3?=
 =?UTF-8?q?=E3=81=97=E3=81=8F=E9=96=89=E3=81=98=E3=82=89=E3=82=8C=E3=81=A6?=
 =?UTF-8?q?=E3=81=84=E3=81=AA=E3=81=84=E3=81=AE=E3=82=92=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=20(#14307)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* fix(frontend): modalが正しく閉じられていないのを修正

* Update packages/frontend/src/components/MkSystemWebhookEditor.vue

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
---
 .../components/MkSystemWebhookEditor.impl.ts  | 13 +++++----
 .../src/components/MkSystemWebhookEditor.vue  | 22 +++++++++-----
 .../src/components/MkUserSelectDialog.vue     |  8 ++---
 .../notification-recipient.editor.vue         | 29 ++++++++++++-------
 .../abuse-report/notification-recipient.vue   | 15 +++++-----
 5 files changed, 53 insertions(+), 34 deletions(-)

diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts
index 76f54e8d37..69b8edd85a 100644
--- a/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts
+++ b/packages/frontend/src/components/MkSystemWebhookEditor.impl.ts
@@ -24,22 +24,23 @@ export type MkSystemWebhookResult = {
 };
 
 export async function showSystemWebhookEditorDialog(props: MkSystemWebhookEditorProps): Promise<MkSystemWebhookResult | null> {
-	const { dispose, result } = await new Promise<{ dispose: () => void, result: MkSystemWebhookResult | null }>(async resolve => {
-		const { dispose: _dispose } = os.popup(
+	const { result } = await new Promise<{ result: MkSystemWebhookResult | null }>(async resolve => {
+		const { dispose } = os.popup(
 			defineAsyncComponent(() => import('@/components/MkSystemWebhookEditor.vue')),
 			props,
 			{
 				submitted: (ev: MkSystemWebhookResult) => {
-					resolve({ dispose: _dispose, result: ev });
+					resolve({ result: ev });
+				},
+				canceled: () => {
+					resolve({ result: null });
 				},
 				closed: () => {
-					resolve({ dispose: _dispose, result: null });
+					dispose();
 				},
 			},
 		);
 	});
 
-	dispose();
-
 	return result;
 }
diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue
index 007d841f00..3e6a015018 100644
--- a/packages/frontend/src/components/MkSystemWebhookEditor.vue
+++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue
@@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <MkModalWindow
+	ref="dialogEl"
 	:width="450"
 	:height="590"
 	:canClose="true"
@@ -12,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	:okButtonDisabled="false"
 	@click="onCancelClicked"
 	@close="onCancelClicked"
-	@closed="onCancelClicked"
+	@closed="emit('closed')"
 >
 	<template #header>
 		{{ mode === 'create' ? i18n.ts._webhookSettings.createWebhook : i18n.ts._webhookSettings.modifyWebhook }}
@@ -59,8 +60,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script setup lang="ts">
-import { computed, onMounted, ref, toRefs } from 'vue';
-import FormSection from '@/components/form/section.vue';
+import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
 import MkInput from '@/components/MkInput.vue';
 import MkSwitch from '@/components/MkSwitch.vue';
 import {
@@ -82,9 +82,12 @@ type EventType = {
 
 const emit = defineEmits<{
 	(ev: 'submitted', result: MkSystemWebhookResult): void;
+	(ev: 'canceled'): void;
 	(ev: 'closed'): void;
 }>();
 
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
+
 const props = defineProps<MkSystemWebhookEditorProps>();
 
 const { mode, id, requiredEvents } = toRefs(props);
@@ -133,12 +136,14 @@ async function onSubmitClicked() {
 			switch (mode.value) {
 				case 'create': {
 					const result = await misskeyApi('admin/system-webhook/create', params);
+					dialogEl.value?.close();
 					emit('submitted', result);
 					break;
 				}
 				case 'edit': {
 					// eslint-disable-next-line
 					const result = await misskeyApi('admin/system-webhook/update', { id: id.value!, ...params });
+					dialogEl.value?.close();
 					emit('submitted', result);
 					break;
 				}
@@ -147,13 +152,15 @@ async function onSubmitClicked() {
 		} catch (ex: any) {
 			const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
 			await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
-			emit('closed');
+			dialogEl.value?.close();
+			emit('canceled');
 		}
 	});
 }
 
 function onCancelClicked() {
-	emit('closed');
+	dialogEl.value?.close();
+	emit('canceled');
 }
 
 async function loadingScope<T>(fn: () => Promise<T>): Promise<T> {
@@ -183,11 +190,12 @@ onMounted(async () => {
 					for (const ev of Object.keys(events.value)) {
 						events.value[ev] = res.on.includes(ev as SystemWebhookEventType);
 					}
-					// eslint-disable-next-line
+					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 				} catch (ex: any) {
 					const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
 					await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
-					emit('closed');
+					dialogEl.value?.close();
+					emit('canceled');
 				}
 				break;
 			}
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index cc3ea78ffe..cbb40924f6 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, shallowRef } from 'vue';
 import * as Misskey from 'misskey-js';
 import MkInput from '@/components/MkInput.vue';
 import FormSplit from '@/components/form/split.vue';
@@ -91,7 +91,7 @@ const host = ref('');
 const users = ref<Misskey.entities.UserLite[]>([]);
 const recentUsers = ref<Misskey.entities.UserDetailed[]>([]);
 const selected = ref<Misskey.entities.UserLite | null>(null);
-const dialogEl = ref();
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
 
 function search() {
 	if (username.value === '' && host.value === '') {
@@ -122,7 +122,7 @@ async function ok() {
 	});
 	emit('ok', user);
 
-	dialogEl.value.close();
+	dialogEl.value?.close();
 
 	// 最近使ったユーザー更新
 	let recents = defaultStore.state.recentlyUsedUsers;
@@ -133,7 +133,7 @@ async function ok() {
 
 function cancel() {
 	emit('cancel');
-	dialogEl.value.close();
+	dialogEl.value?.close();
 }
 
 onMounted(() => {
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
index ffe9c620d6..015109f54e 100644
--- a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.editor.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <MkModalWindow
-	ref="dialog"
+	ref="dialogEl"
 	:width="400"
 	:height="490"
 	:withOkButton="false"
@@ -71,7 +71,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 </template>
 
 <script lang="ts" setup>
-import { computed, onMounted, ref, toRefs } from 'vue';
+import { computed, onMounted, ref, shallowRef, toRefs } from 'vue';
 import { entities } from 'misskey-js';
 import MkButton from '@/components/MkButton.vue';
 import MkModalWindow from '@/components/MkModalWindow.vue';
@@ -88,6 +88,7 @@ type NotificationRecipientMethod = 'email' | 'webhook';
 
 const emit = defineEmits<{
 	(ev: 'submitted'): void;
+	(ev: 'canceled'): void;
 	(ev: 'closed'): void;
 }>();
 
@@ -98,6 +99,8 @@ const props = defineProps<{
 
 const { mode, id } = toRefs(props);
 
+const dialogEl = shallowRef<InstanceType<typeof MkModalWindow>>();
+
 const loading = ref<number>(0);
 
 const title = ref<string>('');
@@ -166,18 +169,21 @@ async function onSubmitClicked() {
 				}
 			}
 
+			dialogEl.value?.close();
 			emit('submitted');
-			// eslint-disable-next-line
+			// eslint-disable-next-line @typescript-eslint/no-explicit-any
 		} catch (ex: any) {
 			const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
 			await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
-			emit('closed');
+			dialogEl.value?.close();
+			emit('canceled');
 		}
 	});
 }
 
 function onCancelClicked() {
-	emit('closed');
+	dialogEl.value?.close();
+	emit('canceled');
 }
 
 async function onEditSystemWebhookClicked() {
@@ -262,7 +268,8 @@ onMounted(async () => {
 			} catch (ex: any) {
 				const msg = ex.message ?? i18n.ts.internalServerErrorDescription;
 				await os.alert({ type: 'error', title: i18n.ts.error, text: msg });
-				emit('closed');
+				dialogEl.value?.close();
+				emit('canceled');
 			}
 		} else {
 			userId.value = moderators.value[0]?.id ?? null;
@@ -296,11 +303,13 @@ onMounted(async () => {
 	gap: 8px;
 
 	button {
-		width: 2.5em;
-		height: 2.5em;
-		min-width: 2.5em;
-		min-height: 2.5em;
+		min-width: 0;
+		min-height: 0;
+		width: 34px;
+		height: 34px;
+		flex-shrink: 0;
 		box-sizing: border-box;
+		margin: 1px 0;
 		padding: 6px;
 	}
 }
diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue
index 93800873f9..f5249261be 100644
--- a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue
+++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue
@@ -108,26 +108,27 @@ async function onDeleteButtonClicked(id: string) {
 }
 
 async function showEditor(mode: 'create' | 'edit', id?: string) {
-	const { dispose, needLoad } = await new Promise<{ dispose: () => void, needLoad: boolean }>(async resolve => {
-		const { dispose: _dispose } = os.popup(
+	const { needLoad } = await new Promise<{ needLoad: boolean }>(async resolve => {
+		const { dispose } = os.popup(
 			defineAsyncComponent(() => import('./notification-recipient.editor.vue')),
 			{
 				mode,
 				id,
 			},
 			{
-				submitted: async () => {
-					resolve({ dispose: _dispose, needLoad: true });
+				submitted: () => {
+					resolve({ needLoad: true });
+				},
+				canceled: () => {
+					resolve({ needLoad: false });
 				},
 				closed: () => {
-					resolve({ dispose: _dispose, needLoad: false });
+					dispose();
 				},
 			},
 		);
 	});
 
-	dispose();
-
 	if (needLoad) {
 		await fetchRecipients();
 	}