diff options
| author | おさむのひと <46447427+samunohito@users.noreply.github.com> | 2025-01-20 20:35:37 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-20 11:35:37 +0000 |
| commit | f9ad127aaf7875bad8fdf55f5ac98bff05997525 (patch) | |
| tree | cd8a4a3be870fee215e2940cb3c7571531c71385 /packages/frontend/src/components/MkRoleSelectDialog.vue | |
| parent | fix(client): MkSubNoteContentに対するnoteの指定が誤っていたの... (diff) | |
| download | misskey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.tar.gz misskey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.tar.bz2 misskey-f9ad127aaf7875bad8fdf55f5ac98bff05997525.zip | |
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>
Diffstat (limited to 'packages/frontend/src/components/MkRoleSelectDialog.vue')
| -rw-r--r-- | packages/frontend/src/components/MkRoleSelectDialog.vue | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/packages/frontend/src/components/MkRoleSelectDialog.vue b/packages/frontend/src/components/MkRoleSelectDialog.vue new file mode 100644 index 0000000000..67a7a3f752 --- /dev/null +++ b/packages/frontend/src/components/MkRoleSelectDialog.vue @@ -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> |