enhance(frontend): エラー発生時のダイアログに詳細情報を載せる (MisskeyIO#543)
This commit is contained in:
parent
41ea486881
commit
daf297c9c0
|
@ -389,12 +389,10 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
id: err.id,
|
id: err.id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
e: {
|
|
||||||
message: err.message,
|
message: err.message,
|
||||||
code: err.name,
|
code: err.name,
|
||||||
id: err.id,
|
id: err.id,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const errId = randomUUID();
|
const errId = randomUUID();
|
||||||
|
@ -416,12 +414,10 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
kind: 'server',
|
kind: 'server',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
e: {
|
|
||||||
message: err.message,
|
message: err.message,
|
||||||
code: err.name,
|
code: err.name,
|
||||||
id: errId,
|
id: errId,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,7 +63,7 @@ export abstract class Endpoint<T extends IEndpointMeta, Ps extends Schema> {
|
||||||
id: '3d81ceae-475f-4600-b2a8-2bc116157532',
|
id: '3d81ceae-475f-4600-b2a8-2bc116157532',
|
||||||
}, {
|
}, {
|
||||||
param: errors[0].schemaPath,
|
param: errors[0].schemaPath,
|
||||||
reason: errors[0].message,
|
reason: errors[0].message ?? 'Invalid',
|
||||||
});
|
});
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,11 +85,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: '5c77c4d7-0f68-48f9-8694-8453a2294840',
|
id: '5c77c4d7-0f68-48f9-8694-8453a2294840',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
e: {
|
|
||||||
message: err.message,
|
message: err.message,
|
||||||
code: err.name,
|
code: err.name,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,11 +191,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: '6708863c-6791-4487-aa01-2d682c6e7db0',
|
id: '6708863c-6791-4487-aa01-2d682c6e7db0',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
e: {
|
|
||||||
message: err.message,
|
message: err.message,
|
||||||
code: err.name,
|
code: err.name,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
if (cleanup) cleanup();
|
if (cleanup) cleanup();
|
||||||
|
|
|
@ -11,15 +11,15 @@ export class ApiError extends Error {
|
||||||
public id: string;
|
public id: string;
|
||||||
public kind: string;
|
public kind: string;
|
||||||
public httpStatusCode?: number;
|
public httpStatusCode?: number;
|
||||||
public info?: any;
|
public info?: Record<string, string>;
|
||||||
|
|
||||||
constructor(err: E, info?: any | null | undefined) {
|
constructor(err: E, info?: Record<string, string> | null | undefined) {
|
||||||
super(err.message);
|
super(err.message);
|
||||||
this.message = err.message;
|
this.message = err.message;
|
||||||
this.code = err.code;
|
this.code = err.code;
|
||||||
this.id = err.id;
|
this.id = err.id;
|
||||||
this.kind = err.kind ?? 'client';
|
this.kind = err.kind ?? 'client';
|
||||||
this.httpStatusCode = err.httpStatusCode;
|
this.httpStatusCode = err.httpStatusCode;
|
||||||
this.info = info;
|
this.info = info ?? undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,15 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
||||||
</template>
|
</template>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
<details v-if="details" class="_acrylic" style="margin: 1em 0;">
|
||||||
|
<summary>{{ i18n.ts.details }}</summary>
|
||||||
|
<div class="_gaps_s" style="text-align: initial;">
|
||||||
|
<MkKeyValue v-for="(value, key) in details" :key="key" :value="value">
|
||||||
|
<template #key>{{ key }}</template>
|
||||||
|
<template #value>{{ value }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
|
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
|
||||||
<MkButton v-if="showOkButton" data-cy-modal-dialog-ok inline primary rounded :autofocus="!input && !select" :disabled="okButtonDisabledReason" @click="ok">{{ okText ?? ((showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt) }}</MkButton>
|
<MkButton v-if="showOkButton" data-cy-modal-dialog-ok inline primary rounded :autofocus="!input && !select" :disabled="okButtonDisabledReason" @click="ok">{{ okText ?? ((showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt) }}</MkButton>
|
||||||
<MkButton v-if="showCancelButton || input || select" data-cy-modal-dialog-cancel inline rounded @click="cancel">{{ cancelText ?? i18n.ts.cancel }}</MkButton>
|
<MkButton v-if="showCancelButton || input || select" data-cy-modal-dialog-cancel inline rounded @click="cancel">{{ cancelText ?? i18n.ts.cancel }}</MkButton>
|
||||||
|
@ -66,6 +75,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
type Input = {
|
type Input = {
|
||||||
|
@ -89,11 +99,12 @@ type Result = string | number | true | null;
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
type?: 'success' | 'error' | 'warning' | 'info' | 'question' | 'waiting';
|
type?: 'success' | 'error' | 'warning' | 'info' | 'question' | 'waiting';
|
||||||
|
icon?: string;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
input?: Input;
|
input?: Input;
|
||||||
select?: Select;
|
select?: Select;
|
||||||
icon?: string;
|
details?: Record<string, string>;
|
||||||
actions?: {
|
actions?: {
|
||||||
text: string;
|
text: string;
|
||||||
primary?: boolean,
|
primary?: boolean,
|
||||||
|
@ -107,11 +118,12 @@ const props = withDefaults(defineProps<{
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
}>(), {
|
}>(), {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
icon: undefined,
|
||||||
title: undefined,
|
title: undefined,
|
||||||
text: undefined,
|
text: undefined,
|
||||||
input: undefined,
|
input: undefined,
|
||||||
select: undefined,
|
select: undefined,
|
||||||
icon: undefined,
|
details: undefined,
|
||||||
actions: undefined,
|
actions: undefined,
|
||||||
showOkButton: true,
|
showOkButton: true,
|
||||||
showCancelButton: false,
|
showCancelButton: false,
|
||||||
|
|
|
@ -47,6 +47,7 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints = keyof Misskey
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title,
|
title,
|
||||||
text,
|
text,
|
||||||
|
details: err.info,
|
||||||
actions: [{
|
actions: [{
|
||||||
value: 'ok',
|
value: 'ok',
|
||||||
text: i18n.ts.gotIt,
|
text: i18n.ts.gotIt,
|
||||||
|
@ -81,6 +82,7 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints = keyof Misskey
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title,
|
title,
|
||||||
text,
|
text,
|
||||||
|
details: err.info,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -113,7 +115,9 @@ export function promiseDialog<T>(
|
||||||
} else {
|
} else {
|
||||||
alert({
|
alert({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: err,
|
title: err.message,
|
||||||
|
text: err.id,
|
||||||
|
details: err.info,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -217,6 +221,7 @@ export function alert(props: {
|
||||||
type?: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
type?: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
|
details?: Record<string, string>;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
popup(MkDialog, props, {
|
popup(MkDialog, props, {
|
||||||
|
@ -231,6 +236,7 @@ export function confirm(props: {
|
||||||
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
|
details?: Record<string, string>;
|
||||||
okText?: string;
|
okText?: string;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
}): Promise<{ canceled: boolean }> {
|
}): Promise<{ canceled: boolean }> {
|
||||||
|
@ -257,6 +263,7 @@ export function actions<T extends {
|
||||||
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
text?: string | null;
|
text?: string | null;
|
||||||
|
details?: Record<string, string>;
|
||||||
actions: T;
|
actions: T;
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
canceled: true; result: undefined;
|
canceled: true; result: undefined;
|
||||||
|
|
Loading…
Reference in a new issue