カスタム絵文字のリクエスト承認用画面の追加
(cherry picked from commit 94451c380458b459791fc2bb6864a3255aca03c4)
This commit is contained in:
parent
bf9089209d
commit
21bee2ffde
|
@ -260,6 +260,7 @@ export interface Locale {
|
||||||
"removed": string;
|
"removed": string;
|
||||||
"removeAreYouSure": string;
|
"removeAreYouSure": string;
|
||||||
"deleteAreYouSure": string;
|
"deleteAreYouSure": string;
|
||||||
|
"undraftAreYouSure": string;
|
||||||
"resetAreYouSure": string;
|
"resetAreYouSure": string;
|
||||||
"saved": string;
|
"saved": string;
|
||||||
"messaging": string;
|
"messaging": string;
|
||||||
|
@ -1023,6 +1024,7 @@ export interface Locale {
|
||||||
"notesSearchNotAvailable": string;
|
"notesSearchNotAvailable": string;
|
||||||
"license": string;
|
"license": string;
|
||||||
"draft": string;
|
"draft": string;
|
||||||
|
"undrafted": string;
|
||||||
"unfavoriteConfirm": string;
|
"unfavoriteConfirm": string;
|
||||||
"myClips": string;
|
"myClips": string;
|
||||||
"drivecleaner": string;
|
"drivecleaner": string;
|
||||||
|
|
|
@ -257,6 +257,7 @@ remove: "削除"
|
||||||
removed: "削除しました"
|
removed: "削除しました"
|
||||||
removeAreYouSure: "「{x}」を削除しますか?"
|
removeAreYouSure: "「{x}」を削除しますか?"
|
||||||
deleteAreYouSure: "「{x}」を削除しますか?"
|
deleteAreYouSure: "「{x}」を削除しますか?"
|
||||||
|
undraftAreYouSure: "「{x}」をドラフト解除しますか?"
|
||||||
resetAreYouSure: "リセットしますか?"
|
resetAreYouSure: "リセットしますか?"
|
||||||
saved: "保存しました"
|
saved: "保存しました"
|
||||||
messaging: "チャット"
|
messaging: "チャット"
|
||||||
|
@ -1022,6 +1023,7 @@ sensitiveWordsDescription2: "スペースで区切るとAND指定になり、キ
|
||||||
notesSearchNotAvailable: "ノート検索は利用できません。"
|
notesSearchNotAvailable: "ノート検索は利用できません。"
|
||||||
license: "ライセンス"
|
license: "ライセンス"
|
||||||
draft: "ドラフト"
|
draft: "ドラフト"
|
||||||
|
undrafted: "ドラフト解除"
|
||||||
unfavoriteConfirm: "お気に入り解除しますか?"
|
unfavoriteConfirm: "お気に入り解除しますか?"
|
||||||
myClips: "自分のクリップ"
|
myClips: "自分のクリップ"
|
||||||
drivecleaner: "ドライブクリーナー"
|
drivecleaner: "ドライブクリーナー"
|
||||||
|
|
|
@ -64,6 +64,7 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
query: { type: 'string', nullable: true, default: null },
|
query: { type: 'string', nullable: true, default: null },
|
||||||
|
draft: { type: 'boolean', nullable: true, default: null },
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
@ -86,6 +87,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
let emojis: MiEmoji[];
|
let emojis: MiEmoji[];
|
||||||
|
|
||||||
|
if (ps.draft !== null) {
|
||||||
|
if (ps.draft) {
|
||||||
|
q.andWhere('emoji.draft = TRUE');
|
||||||
|
} else {
|
||||||
|
q.andWhere('emoji.draft = FALSE');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.query) {
|
if (ps.query) {
|
||||||
//q.andWhere('emoji.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
|
//q.andWhere('emoji.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` });
|
||||||
//const emojis = await q.limit(ps.limit).getMany();
|
//const emojis = await q.limit(ps.limit).getMany();
|
||||||
|
|
|
@ -51,6 +51,41 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="tab === 'draft'" class="draft">
|
||||||
|
<MkPagination ref="emojisDraftPaginationComponent" :pagination="paginationDraft">
|
||||||
|
<template #empty><span>{{ i18n.ts.noCustomEmojis }}</span></template>
|
||||||
|
<template #default="{items}">
|
||||||
|
<div class="ldhfsamy">
|
||||||
|
<template v-for="emoji in items" :key="emoji.id">
|
||||||
|
<div class="emoji _panel">
|
||||||
|
<div class="img">
|
||||||
|
<div class="imgLight"><img :src="emoji.url" :alt="emoji.name"/></div>
|
||||||
|
<div class="imgDark"><img :src="emoji.url" :alt="emoji.name"/></div>
|
||||||
|
</div>
|
||||||
|
<div class="info">
|
||||||
|
<div class="name _monospace">{{ i18n.ts.name }}: {{ emoji.name }}</div>
|
||||||
|
<div class="category">{{ i18n.ts.category }}:{{ emoji.category }}</div>
|
||||||
|
<div class="aliases">{{ i18n.ts.tags }}:{{ emoji.aliases.join(' ') }}</div>
|
||||||
|
<div class="license">{{ i18n.ts.license }}:{{ emoji.license }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="edit-button">
|
||||||
|
<button class="edit _button" @click="editDraft(emoji)">
|
||||||
|
{{ i18n.ts.edit }}
|
||||||
|
</button>
|
||||||
|
<button class="draft _button" @click="undrafted(emoji)">
|
||||||
|
{{ i18n.ts.undrafted }}
|
||||||
|
</button>
|
||||||
|
<button class="delete _button" @click="deleteDraft(emoji)">
|
||||||
|
{{ i18n.ts.delete }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MkPagination>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-else-if="tab === 'remote'" class="remote">
|
<div v-else-if="tab === 'remote'" class="remote">
|
||||||
<FormSplit>
|
<FormSplit>
|
||||||
<MkInput v-model="queryRemote" :debounce="true" type="search">
|
<MkInput v-model="queryRemote" :debounce="true" type="search">
|
||||||
|
@ -89,14 +124,15 @@ import MkInput from '@/components/MkInput.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import FormSplit from '@/components/form/split.vue';
|
import FormSplit from '@/components/form/split.vue';
|
||||||
import { selectFile, selectFiles } from '@/scripts/select-file.js';
|
import { selectFile } from '@/scripts/select-file.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
const emojisDraftPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
const tab = ref('local');
|
const tab = ref('draft');
|
||||||
const query = ref(null);
|
const query = ref(null);
|
||||||
const queryRemote = ref(null);
|
const queryRemote = ref(null);
|
||||||
const host = ref(null);
|
const host = ref(null);
|
||||||
|
@ -111,6 +147,15 @@ const pagination = {
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const paginationDraft = {
|
||||||
|
endpoint: 'admin/emoji/list' as const,
|
||||||
|
limit: 30,
|
||||||
|
params: computed(() => ({
|
||||||
|
query: (query.value && query.value !== '') ? query.value : null,
|
||||||
|
draft: true,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
const remotePagination = {
|
const remotePagination = {
|
||||||
endpoint: 'admin/emoji/list-remote' as const,
|
endpoint: 'admin/emoji/list-remote' as const,
|
||||||
limit: 30,
|
limit: 30,
|
||||||
|
@ -166,6 +211,61 @@ const edit = (emoji) => {
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editDraft = (emoji) => {
|
||||||
|
os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
|
||||||
|
emoji: emoji,
|
||||||
|
isRequest: false,
|
||||||
|
}, {
|
||||||
|
done: result => {
|
||||||
|
if (result.updated) {
|
||||||
|
emojisDraftPaginationComponent.value.updateItem(result.updated.id, (oldEmoji: any) => ({
|
||||||
|
...oldEmoji,
|
||||||
|
...result.updated,
|
||||||
|
}));
|
||||||
|
emojisDraftPaginationComponent.value.reload();
|
||||||
|
} else if (result.deleted) {
|
||||||
|
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}, 'closed');
|
||||||
|
};
|
||||||
|
|
||||||
|
async function undrafted(emoji) {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'warning',
|
||||||
|
text: i18n.t('undraftAreYouSure', { x: emoji.name }),
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
await os.api('admin/emoji/update', {
|
||||||
|
id: emoji.id,
|
||||||
|
name: emoji.name,
|
||||||
|
category: emoji.category,
|
||||||
|
aliases: emoji.aliases,
|
||||||
|
license: emoji.license,
|
||||||
|
draft: false,
|
||||||
|
isSensitive: emoji.isSensitive,
|
||||||
|
localOnly: emoji.localOnly,
|
||||||
|
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction,
|
||||||
|
});
|
||||||
|
|
||||||
|
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteDraft(emoji) {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'warning',
|
||||||
|
text: i18n.t('removeAreYouSure', { x: emoji.name }),
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
os.api('admin/emoji/delete', {
|
||||||
|
id: emoji.id,
|
||||||
|
}).then(() => {
|
||||||
|
emojisDraftPaginationComponent.value.removeItem((item) => item.id === emoji.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const im = (emoji) => {
|
const im = (emoji) => {
|
||||||
os.apiWithDialog('admin/emoji/copy', {
|
os.apiWithDialog('admin/emoji/copy', {
|
||||||
emojiId: emoji.id,
|
emojiId: emoji.id,
|
||||||
|
@ -308,6 +408,9 @@ const headerActions = $computed(() => [{
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
const headerTabs = $computed(() => [{
|
const headerTabs = $computed(() => [{
|
||||||
|
key: 'draft',
|
||||||
|
title: i18n.ts.draftEmojis,
|
||||||
|
}, {
|
||||||
key: 'local',
|
key: 'local',
|
||||||
title: i18n.ts.local,
|
title: i18n.ts.local,
|
||||||
}, {
|
}, {
|
||||||
|
@ -374,6 +477,122 @@ definePageMetadata(computed(() => ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
> .draft {
|
||||||
|
.empty {
|
||||||
|
margin: var(--margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldhfsamy {
|
||||||
|
> .emoji {
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 40px 1fr;
|
||||||
|
grid-template-columns: 1fr 150px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 11px;
|
||||||
|
text-align: left;
|
||||||
|
border: solid 1px var(--panel);
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
> .img {
|
||||||
|
display: grid;
|
||||||
|
grid-row: 1;
|
||||||
|
grid-column: 1/ span 2;
|
||||||
|
grid-template-columns: 50% 50%;
|
||||||
|
place-content: center;
|
||||||
|
place-items: center;
|
||||||
|
|
||||||
|
> .imgLight {
|
||||||
|
display: grid;
|
||||||
|
grid-column: 1;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
> img {
|
||||||
|
max-height: 30px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .imgDark {
|
||||||
|
display: grid;
|
||||||
|
grid-column: 2;
|
||||||
|
background-color: #000;
|
||||||
|
|
||||||
|
> img {
|
||||||
|
max-height: 30px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .info {
|
||||||
|
display: grid;
|
||||||
|
grid-row: 2;
|
||||||
|
grid-template-rows: 30px 30px 30px;
|
||||||
|
|
||||||
|
> .name {
|
||||||
|
grid-row: 1;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .category {
|
||||||
|
grid-row: 2;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .aliases {
|
||||||
|
grid-row: 3;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .license {
|
||||||
|
grid-row: 4;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .edit-button {
|
||||||
|
display: grid;
|
||||||
|
grid-row: 2;
|
||||||
|
grid-template-rows: 30px 30px 30px;
|
||||||
|
|
||||||
|
> .edit {
|
||||||
|
grid-row: 1;
|
||||||
|
background-color: var(--buttonBg);
|
||||||
|
margin: 2px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .draft {
|
||||||
|
grid-row: 2;
|
||||||
|
background-color: var(--buttonBg);
|
||||||
|
margin: 2px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .delete {
|
||||||
|
background-color: var(--buttonBg);
|
||||||
|
grid-row: 3;
|
||||||
|
margin: 2px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .remote {
|
> .remote {
|
||||||
.empty {
|
.empty {
|
||||||
|
|
Loading…
Reference in New Issue