separate sort order component
This commit is contained in:
parent
47ca0e6689
commit
cb136e635d
|
@ -5,6 +5,26 @@ export type RequestLogItem = {
|
|||
error?: string;
|
||||
};
|
||||
|
||||
export const gridSortOrderKeys = [
|
||||
'name',
|
||||
'category',
|
||||
'aliases',
|
||||
'type',
|
||||
'license',
|
||||
'host',
|
||||
'uri',
|
||||
'publicUrl',
|
||||
'isSensitive',
|
||||
'localOnly',
|
||||
'updatedAt',
|
||||
];
|
||||
export type GridSortOrderKey = typeof gridSortOrderKeys[number];
|
||||
|
||||
export type GridSortOrder = {
|
||||
key: GridSortOrderKey;
|
||||
direction: 'ASC' | 'DESC';
|
||||
}
|
||||
|
||||
export function emptyStrToUndefined(value: string | null) {
|
||||
return value ? value : undefined;
|
||||
}
|
||||
|
|
|
@ -118,26 +118,7 @@
|
|||
</MkInput>
|
||||
</div>
|
||||
|
||||
<MkFolder :spacerMax="8" :spacerMin="8">
|
||||
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
||||
<div :class="$style.sortOrderArea">
|
||||
<div :class="$style.sortOrderAreaTags">
|
||||
<MkTagItem
|
||||
v-for="order in sortOrders"
|
||||
:key="order.key"
|
||||
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
|
||||
:exButtonIconClass="'ti ti-x'"
|
||||
:content="order.key"
|
||||
@click="onToggleSortOrderButtonClicked(order)"
|
||||
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
|
||||
/>
|
||||
</div>
|
||||
<MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
|
||||
<span class="ti ti-plus"/>
|
||||
</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderUpdate"/>
|
||||
|
||||
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
||||
<MkButton primary @click="onSearchRequest">
|
||||
|
@ -150,15 +131,7 @@
|
|||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-notes"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.registrationLogs }}</template>
|
||||
<template #caption>
|
||||
{{ i18n.ts._customEmojisManager._gridCommon.registrationLogsCaption }}
|
||||
</template>
|
||||
|
||||
<XRegisterLogs :logs="requestLogs"/>
|
||||
</MkFolder>
|
||||
<XRegisterLogsFolder :logs="requestLogs"/>
|
||||
|
||||
<div :class="$style.gridArea">
|
||||
<MkGrid :data="gridItems" :settings="setupGrid()" @event="onGridEvent"/>
|
||||
|
@ -188,7 +161,7 @@ import * as os from '@/os.js';
|
|||
import {
|
||||
emptyStrToEmptyArray,
|
||||
emptyStrToNull,
|
||||
emptyStrToUndefined,
|
||||
emptyStrToUndefined, GridSortOrder,
|
||||
RequestLogItem,
|
||||
roleIdsParser,
|
||||
} from '@/pages/admin/custom-emojis-manager.impl.js';
|
||||
|
@ -200,13 +173,12 @@ import { validators } from '@/components/grid/cell-validators.js';
|
|||
import { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
||||
import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
|
||||
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
||||
import XSortOrderFolder from '@/pages/admin/custom-emojis-manager.sort-order-folder.vue';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import { deviceKind } from '@/scripts/device-kind.js';
|
||||
import { GridSetting } from '@/components/grid/grid.js';
|
||||
import MkTagItem from '@/components/MkTagItem.vue';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
import { selectFile } from '@/scripts/select-file.js';
|
||||
import { copyGridDataToClipboard, removeDataFromGrid } from '@/components/grid/grid-utils.js';
|
||||
|
||||
|
@ -228,23 +200,6 @@ type GridItem = {
|
|||
originalUrl?: string | null;
|
||||
}
|
||||
|
||||
const gridSortOrderKeys = [
|
||||
'name',
|
||||
'category',
|
||||
'aliases',
|
||||
'type',
|
||||
'license',
|
||||
'isSensitive',
|
||||
'localOnly',
|
||||
'updatedAt',
|
||||
];
|
||||
type GridSortOrderKey = typeof gridSortOrderKeys[number];
|
||||
|
||||
type GridSortOrder = {
|
||||
key: GridSortOrderKey;
|
||||
direction: 'ASC' | 'DESC';
|
||||
}
|
||||
|
||||
function setupGrid(): GridSetting {
|
||||
const required = validators.required();
|
||||
const regex = validators.regex(/^[a-zA-Z0-9_]+$/);
|
||||
|
@ -538,33 +493,8 @@ async function onQueryRolesEditClicked() {
|
|||
queryRoles.value = result.result;
|
||||
}
|
||||
|
||||
function onToggleSortOrderButtonClicked(order: GridSortOrder) {
|
||||
switch (order.direction) {
|
||||
case 'ASC':
|
||||
order.direction = 'DESC';
|
||||
break;
|
||||
case 'DESC':
|
||||
order.direction = 'ASC';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function onRemoveSortOrderButtonClicked(key: GridSortOrderKey) {
|
||||
sortOrders.value = sortOrders.value.filter(it => it.key !== key);
|
||||
}
|
||||
|
||||
function onAddSortOrderButtonClicked(ev: MouseEvent) {
|
||||
const menuItems: MenuItem[] = gridSortOrderKeys
|
||||
.filter(key => !sortOrders.value.map(it => it.key).includes(key))
|
||||
.map(it => {
|
||||
return {
|
||||
text: it,
|
||||
action: () => {
|
||||
sortOrders.value.push({ key: it, direction: 'ASC' });
|
||||
},
|
||||
};
|
||||
});
|
||||
os.contextMenu(menuItems, ev);
|
||||
function onSortOrderUpdate(_sortOrders: GridSortOrder[]) {
|
||||
sortOrders.value = _sortOrders;
|
||||
}
|
||||
|
||||
async function onSearchRequest() {
|
||||
|
@ -751,37 +681,6 @@ onMounted(async () => {
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
.sortOrderArea {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.sortOrderAreaTags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sortOrderAddButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
min-width: 2.0em;
|
||||
min-height: 2.0em;
|
||||
max-width: 2.0em;
|
||||
max-height: 2.0em;
|
||||
padding: 8px;
|
||||
margin-left: auto;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--buttonBg);
|
||||
}
|
||||
|
||||
.gridArea {
|
||||
overflow: scroll;
|
||||
padding-top: 8px;
|
||||
|
|
|
@ -25,15 +25,7 @@
|
|||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-notes"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.registrationLogs }}</template>
|
||||
<template #caption>
|
||||
{{ i18n.ts._customEmojisManager._gridCommon.registrationLogsCaption }}
|
||||
</template>
|
||||
|
||||
<XRegisterLogs :logs="requestLogs"/>
|
||||
</MkFolder>
|
||||
<XRegisterLogsFolder :logs="requestLogs"/>
|
||||
|
||||
<div
|
||||
:class="[$style.uploadBox, [isDragOver ? $style.dragOver : {}]]"
|
||||
|
@ -94,7 +86,7 @@ import { chooseFileFromDrive, chooseFileFromPc } from '@/scripts/select-file.js'
|
|||
import { uploadFile } from '@/scripts/upload.js';
|
||||
import { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
||||
import { DroppedFile, extractDroppedItems, flattenDroppedFiles } from '@/scripts/file-drop.js';
|
||||
import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
|
||||
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
||||
import { GridSetting } from '@/components/grid/grid.js';
|
||||
import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js';
|
||||
import { GridRow } from '@/components/grid/row.js';
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<template>
|
||||
<div>
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-notes"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.registrationLogs }}</template>
|
||||
<template #caption>
|
||||
{{ i18n.ts._customEmojisManager._gridCommon.registrationLogsCaption }}
|
||||
</template>
|
||||
|
||||
<div>
|
||||
<div v-if="logs.length > 0" style="display:flex; flex-direction: column; overflow-y: scroll; gap: 16px;">
|
||||
<MkSwitch v-model="showingSuccessLogs">
|
||||
<template #label>{{ i18n.ts._customEmojisManager._logs.showSuccessLogSwitch }}</template>
|
||||
|
@ -19,7 +26,8 @@
|
|||
<div v-else>
|
||||
{{ i18n.ts._customEmojisManager._logs.logNothing }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -31,6 +39,7 @@ import MkGrid from '@/components/grid/MkGrid.vue';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import { GridSetting } from '@/components/grid/grid.js';
|
||||
import { copyGridDataToClipboard } from '@/components/grid/grid-utils.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
|
||||
function setupGrid(): GridSetting {
|
||||
return {
|
|
@ -52,26 +52,7 @@
|
|||
</MkInput>
|
||||
</div>
|
||||
|
||||
<MkFolder :spacerMax="8" :spacerMin="8">
|
||||
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
||||
<div :class="$style.sortOrderArea">
|
||||
<div :class="$style.sortOrderAreaTags">
|
||||
<MkTagItem
|
||||
v-for="order in sortOrders"
|
||||
:key="order.key"
|
||||
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
|
||||
:exButtonIconClass="'ti ti-x'"
|
||||
:content="order.key"
|
||||
@click="onToggleSortOrderButtonClicked(order)"
|
||||
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
|
||||
/>
|
||||
</div>
|
||||
<MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
|
||||
<span class="ti ti-plus"/>
|
||||
</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderChanged"/>
|
||||
|
||||
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
||||
<MkButton primary @click="onSearchRequest">
|
||||
|
@ -84,15 +65,7 @@
|
|||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-notes"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.registrationLogs }}</template>
|
||||
<template #caption>
|
||||
{{ i18n.ts._customEmojisManager._gridCommon.registrationLogsCaption }}
|
||||
</template>
|
||||
|
||||
<XRegisterLogs :logs="requestLogs"/>
|
||||
</MkFolder>
|
||||
<XRegisterLogsFolder :logs="requestLogs"/>
|
||||
|
||||
<div v-if="gridItems.length > 0" :class="$style.gridArea">
|
||||
<MkGrid :data="gridItems" :settings="setupGrid()" @event="onGridEvent"/>
|
||||
|
@ -115,15 +88,14 @@ import { i18n } from '@/i18n.js';
|
|||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkGrid from '@/components/grid/MkGrid.vue';
|
||||
import { emptyStrToUndefined, RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
|
||||
import { emptyStrToUndefined, GridSortOrder, RequestLogItem } from '@/pages/admin/custom-emojis-manager.impl.js';
|
||||
import { GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import XRegisterLogs from '@/pages/admin/custom-emojis-manager.logs.vue';
|
||||
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
||||
import XSortOrderFolder from '@/pages/admin/custom-emojis-manager.sort-order-folder.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { GridSetting } from '@/components/grid/grid.js';
|
||||
import MkTagItem from '@/components/MkTagItem.vue';
|
||||
import { deviceKind } from '@/scripts/device-kind.js';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
||||
|
||||
type GridItem = {
|
||||
|
@ -134,19 +106,6 @@ type GridItem = {
|
|||
host: string;
|
||||
}
|
||||
|
||||
const gridSortOrderKeys = [
|
||||
'name',
|
||||
'host',
|
||||
'uri',
|
||||
'publicUrl',
|
||||
];
|
||||
type GridSortOrderKey = typeof gridSortOrderKeys[number];
|
||||
|
||||
type GridSortOrder = {
|
||||
key: GridSortOrderKey;
|
||||
direction: 'ASC' | 'DESC';
|
||||
}
|
||||
|
||||
function setupGrid(): GridSetting {
|
||||
return {
|
||||
row: {
|
||||
|
@ -206,33 +165,8 @@ const gridItems = ref<GridItem[]>([]);
|
|||
|
||||
const spMode = computed(() => ['smartphone', 'tablet'].includes(deviceKind));
|
||||
|
||||
function onToggleSortOrderButtonClicked(order: GridSortOrder) {
|
||||
switch (order.direction) {
|
||||
case 'ASC':
|
||||
order.direction = 'DESC';
|
||||
break;
|
||||
case 'DESC':
|
||||
order.direction = 'ASC';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function onRemoveSortOrderButtonClicked(key: GridSortOrderKey) {
|
||||
sortOrders.value = sortOrders.value.filter(it => it.key !== key);
|
||||
}
|
||||
|
||||
function onAddSortOrderButtonClicked(ev: MouseEvent) {
|
||||
const menuItems: MenuItem[] = gridSortOrderKeys
|
||||
.filter(key => !sortOrders.value.map(it => it.key).includes(key))
|
||||
.map(it => {
|
||||
return {
|
||||
text: it,
|
||||
action: () => {
|
||||
sortOrders.value.push({ key: it, direction: 'ASC' });
|
||||
},
|
||||
};
|
||||
});
|
||||
os.contextMenu(menuItems, ev);
|
||||
function onSortOrderChanged(_sortOrders: GridSortOrder[]) {
|
||||
sortOrders.value = _sortOrders;
|
||||
}
|
||||
|
||||
async function onSearchRequest() {
|
||||
|
@ -412,37 +346,6 @@ onMounted(async () => {
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
.sortOrderArea {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.sortOrderAreaTags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sortOrderAddButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
min-width: 2.0em;
|
||||
min-height: 2.0em;
|
||||
max-width: 2.0em;
|
||||
max-height: 2.0em;
|
||||
padding: 8px;
|
||||
margin-left: auto;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--buttonBg);
|
||||
}
|
||||
|
||||
.gridArea {
|
||||
overflow: scroll;
|
||||
padding-top: 8px;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<MkFolder :spacerMax="8" :spacerMin="8">
|
||||
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
||||
<div :class="$style.sortOrderArea">
|
||||
<div :class="$style.sortOrderAreaTags">
|
||||
<MkTagItem
|
||||
v-for="order in sortOrders"
|
||||
:key="order.key"
|
||||
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
|
||||
:exButtonIconClass="'ti ti-x'"
|
||||
:content="order.key"
|
||||
@click="onToggleSortOrderButtonClicked(order)"
|
||||
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
|
||||
/>
|
||||
</div>
|
||||
<MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
|
||||
<span class="ti ti-plus"/>
|
||||
</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { toRefs } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkTagItem from '@/components/MkTagItem.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { GridSortOrder, GridSortOrderKey, gridSortOrderKeys } from '@/pages/admin/custom-emojis-manager.impl.js';
|
||||
import { MenuItem } from '@/types/menu.js';
|
||||
import * as os from '@/os.js';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'update', sortOrders: GridSortOrder[]): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
sortOrders: GridSortOrder[];
|
||||
}>();
|
||||
|
||||
const { sortOrders } = toRefs(props);
|
||||
|
||||
function onToggleSortOrderButtonClicked(order: GridSortOrder) {
|
||||
switch (order.direction) {
|
||||
case 'ASC':
|
||||
order.direction = 'DESC';
|
||||
break;
|
||||
case 'DESC':
|
||||
order.direction = 'ASC';
|
||||
break;
|
||||
}
|
||||
|
||||
emitOrder(sortOrders.value);
|
||||
}
|
||||
|
||||
function onAddSortOrderButtonClicked(ev: MouseEvent) {
|
||||
const menuItems: MenuItem[] = gridSortOrderKeys
|
||||
.filter(key => !sortOrders.value.map(it => it.key).includes(key))
|
||||
.map(it => {
|
||||
return {
|
||||
text: it,
|
||||
action: () => {
|
||||
emitOrder([...sortOrders.value, { key: it, direction: 'ASC' }]);
|
||||
},
|
||||
};
|
||||
});
|
||||
os.contextMenu(menuItems, ev);
|
||||
}
|
||||
|
||||
function onRemoveSortOrderButtonClicked(key: GridSortOrderKey) {
|
||||
emitOrder(sortOrders.value.filter(it => it.key !== key));
|
||||
}
|
||||
|
||||
function emitOrder(sortOrders: GridSortOrder[]) {
|
||||
emit('update', sortOrders);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style module lang="scss">
|
||||
.sortOrderArea {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.sortOrderAreaTags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sortOrderAddButton {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
min-width: 2.0em;
|
||||
min-height: 2.0em;
|
||||
max-width: 2.0em;
|
||||
max-height: 2.0em;
|
||||
padding: 8px;
|
||||
margin-left: auto;
|
||||
border-radius: 9999px;
|
||||
background-color: var(--buttonBg);
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue