feat: 新カスタム絵文字管理画面(β)の追加 (#13473)

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* fix

* fix

* fix size

* fix register logs

* fix img autosize

* fix row selection

* support delete

* fix border rendering

* fix display:none

* tweak comments

* support choose pc file and drive file

* support directory drag-drop

* fix

* fix comment

* support context menu on data area

* fix autogen

* wip イベント整理

* イベントの整理

* refactor grid

* fix cell re-render bugs

* fix row remove

* fix comment

* fix validation

* fix utils

* list maximum

* add mimetype check

* fix

* fix number cell focus

* fix over 100 file drop

* remove log

* fix patchData

* fix performance

* fix

* support update and delete

* support remote import

* fix layout

* heightやめる

* fix performance

* add list v2 endpoint

* support pagination

* fix api call

* fix no clickable input text

* fix limit

* fix paging

* fix

* fix

* support search

* tweak logs

* tweak cell selection

* fix range select

* block delete

* add comment

* fix

* support import log

* fix dialog

* refactor

* add confirm dialog

* fix name

* fix autogen

* wip

* support image change and highlight row

* add columns

* wip

* support sort

* add role name

* add index to emoji

* refine context menu setting

* support role select

* remove unused buttons

* fix url

* fix MkRoleSelectDialog.vue

* add route

* refine remote page

* enter key search

* fix paste bugs

* fix copy/paste

* fix keyEvent

* fix copy/paste and delete

* fix comment

* fix MkRoleSelectDialog.vue and storybook scenario

* fix MkRoleSelectDialog.vue and storybook scenario

* add MkGrid.stories.impl.ts

* fix

* [wip] add custom-emojis-manager2.stories.impl.ts

* [wip] add custom-emojis-manager2.stories.impl.ts

* wip

* 課題はまだ残っているが、ひとまず完了

* fix validation and register roles

* fix upload

* optimize import

* patch from dev

* i18n

* revert excess fixes

* separate sort order component

* add SPDX

* revert excess fixes

* fix pre test

* fix bugs

* add type column

* fix types

* fix CHANGELOG.md

* fix lit

* lint

* tweak style

* refactor

* fix ci

* autogen

* Update types.ts

* CSS Module化

* fix log

* 縦スクロールを無効化

* MkStickyContainer化

* regenerate locales index.d.ts

* fix

* fix

* テスト

* ランダム値によるUI変更の抑制

* テスト

* tableタグやめる

* fix last-child css

* fix overflow css

* fix endpoint.ts

* tweak css

* 最新への追従とレイアウト微調整

* ソートキーの指定方法を他と合わせた

* fix focus

* fix layout

* v2エンドポイントのルールに対応

* 表示条件などを微調整

* fix MkDataCell.vue

* fix error code

* fix error

* add comment to MkModal.vue

* Update index.d.ts

* fix CHANGELOG.md

* fix color theme

* fix CHANGELOG.md

* fix CHANGELOG.md

* fix center

* fix: テーブルにフォーカスがあり、通常状態であるときはキーイベントの伝搬を止める

* fix: ロール選択用のダイアログにてコンディショナルロールを×ボタンで除外できなかったのを修正

* fix remote list folder

* sticky footers

* chore: fix ci error(just single line-break diff)

* fix loading

* fix like

* comma to space

* fix ci

* fix ci

* removed align-center

---------

Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com>
This commit is contained in:
おさむのひと 2025-01-20 20:35:37 +09:00 committed by GitHub
parent b41e78090d
commit f9ad127aaf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 8275 additions and 58 deletions

View file

@ -0,0 +1,200 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkModalWindow
ref="windowEl"
:withOkButton="false"
:okButtonDisabled="false"
:width="400"
:height="500"
@close="onCloseModalWindow"
@closed="console.log('MkRoleSelectDialog: closed') ; $emit('dispose')"
>
<template #header>{{ title }}</template>
<MkSpacer :marginMin="20" :marginMax="28">
<MkLoading v-if="fetching"/>
<div v-else class="_gaps" :class="$style.root">
<div :class="$style.header">
<MkButton rounded @click="addRole"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
</div>
<div v-if="selectedRoles.length > 0" class="_gaps" :class="$style.roleItemArea">
<div v-for="role in selectedRoles" :key="role.id" :class="$style.roleItem">
<MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false" style="pointer-events: none;"/>
<button class="_button" :class="$style.roleUnAssign" @click="removeRole(role.id)"><i class="ti ti-x"></i></button>
</div>
</div>
<div v-else :class="$style.roleItemArea" style="text-align: center">
{{ i18n.ts._roleSelectDialog.notSelected }}
</div>
<MkInfo v-if="infoMessage">{{ infoMessage }}</MkInfo>
<div :class="$style.buttons">
<MkButton primary @click="onOkClicked">{{ i18n.ts.ok }}</MkButton>
<MkButton @click="onCancelClicked">{{ i18n.ts.cancel }}</MkButton>
</div>
</div>
</MkSpacer>
</MkModalWindow>
</template>
<script setup lang="ts">
import { computed, defineProps, ref, toRefs } from 'vue';
import * as Misskey from 'misskey-js';
import { i18n } from '@/i18n.js';
import MkButton from '@/components/MkButton.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkRolePreview from '@/components/MkRolePreview.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import * as os from '@/os.js';
import MkSpacer from '@/components/global/MkSpacer.vue';
import MkModalWindow from '@/components/MkModalWindow.vue';
import MkLoading from '@/components/global/MkLoading.vue';
const emit = defineEmits<{
(ev: 'done', value: Misskey.entities.Role[]),
(ev: 'close'),
(ev: 'dispose'),
}>();
const props = withDefaults(defineProps<{
initialRoleIds?: string[],
infoMessage?: string,
title?: string,
publicOnly: boolean,
}>(), {
initialRoleIds: undefined,
infoMessage: undefined,
title: undefined,
publicOnly: true,
});
const { initialRoleIds, infoMessage, title, publicOnly } = toRefs(props);
const windowEl = ref<InstanceType<typeof MkModalWindow>>();
const roles = ref<Misskey.entities.Role[]>([]);
const selectedRoleIds = ref<string[]>(initialRoleIds.value ?? []);
const fetching = ref(false);
const selectedRoles = computed(() => {
const r = roles.value.filter(role => selectedRoleIds.value.includes(role.id));
r.sort((a, b) => {
if (a.displayOrder !== b.displayOrder) {
return b.displayOrder - a.displayOrder;
}
return a.id.localeCompare(b.id);
});
return r;
});
async function fetchRoles() {
fetching.value = true;
const result = await misskeyApi('admin/roles/list', {});
roles.value = result.filter(it => publicOnly.value ? it.isPublic : true);
fetching.value = false;
}
async function addRole() {
const items = roles.value
.filter(r => r.isPublic)
.filter(r => !selectedRoleIds.value.includes(r.id))
.map(r => ({ text: r.name, value: r }));
const { canceled, result: role } = await os.select({ items });
if (canceled) {
return;
}
selectedRoleIds.value.push(role.id);
}
async function removeRole(roleId: string) {
selectedRoleIds.value = selectedRoleIds.value.filter(x => x !== roleId);
}
function onOkClicked() {
emit('done', selectedRoles.value);
windowEl.value?.close();
}
function onCancelClicked() {
emit('close');
windowEl.value?.close();
}
function onCloseModalWindow() {
emit('close');
windowEl.value?.close();
}
fetchRoles();
</script>
<style module lang="scss">
.root {
max-height: 410px;
height: 410px;
display: flex;
flex-direction: column;
}
.roleItemArea {
background-color: var(--MI_THEME-acrylicBg);
border-radius: var(--MI-radius);
padding: 12px;
overflow-y: auto;
}
.roleItem {
display: flex;
}
.role {
flex: 1;
}
.roleUnAssign {
width: 32px;
height: 32px;
margin-left: 8px;
align-self: center;
}
.header {
display: flex;
align-items: center;
justify-content: flex-start;
}
.title {
flex: 1;
}
.addRoleButton {
min-width: 32px;
min-height: 32px;
max-width: 32px;
max-height: 32px;
margin-left: 8px;
align-self: center;
padding: 0;
}
.buttons {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-top: auto;
}
.divider {
border-top: solid 0.5px var(--MI_THEME-divider);
}
</style>