support sort

This commit is contained in:
samunohito 2024-02-14 22:10:42 +09:00
parent 9189117ef1
commit 089682c08d
5 changed files with 71 additions and 25 deletions

View file

@ -64,7 +64,7 @@ export type FetchEmojisParams = {
page?: number; page?: number;
sort?: { sort?: {
key : FetchEmojisSortKeys; key : FetchEmojisSortKeys;
order : 'ASC' | 'DESC'; direction : 'ASC' | 'DESC';
}[] }[]
} }
@ -508,7 +508,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
if (params?.sort) { if (params?.sort) {
for (const sort of params.sort) { for (const sort of params.sort) {
builder.addOrderBy(`emoji.${sort.key}`, sort.order); builder.addOrderBy(`emoji.${sort.key}`, sort.direction);
} }
} else { } else {
builder.addOrderBy('emoji.id', 'DESC'); builder.addOrderBy('emoji.id', 'DESC');

View file

@ -82,13 +82,13 @@ export const paramDef = {
], ],
default: 'id', default: 'id',
}, },
order: { direction: {
type: 'string', type: 'string',
enum: ['ASC', 'DESC'], enum: ['ASC', 'DESC'],
default: 'DESC', default: 'DESC',
}, },
}, },
required: ['key', 'order'], required: ['key', 'direction'],
}, },
}, },
}, },
@ -128,7 +128,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
params.page = ps.page; params.page = ps.page;
params.sort = ps.sort?.map(it => ({ params.sort = ps.sort?.map(it => ({
key: it.key, key: it.key,
order: it.order, direction: it.direction,
})); }));
const result = await this.customEmojiService.fetchEmojis(params); const result = await this.customEmojiService.fetchEmojis(params);

View file

@ -3,7 +3,7 @@
<span v-if="iconClass" :class="[$style.icon, iconClass]"/> <span v-if="iconClass" :class="[$style.icon, iconClass]"/>
<span :class="$style.content">{{ content }}</span> <span :class="$style.content">{{ content }}</span>
<MkButton v-if="exButtonIconClass" :class="$style.exButton" @click="(ev) => emit('exButtonClick', ev)"> <MkButton v-if="exButtonIconClass" :class="$style.exButton" @click="(ev) => emit('exButtonClick', ev)">
<span :class="exButtonIconClass"/> <span :class="[$style.exButtonIcon, exButtonIconClass]"/>
</MkButton> </MkButton>
</div> </div>
</template> </template>
@ -24,15 +24,15 @@ defineProps<{
</script> </script>
<style module lang="scss"> <style module lang="scss">
$buttonSize : 2em; $buttonSize : 1.8em;
.root { .root {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
border-radius: 9999px; border-radius: 9999px;
padding: 4px 4px; padding: 4px 6px;
gap: 4px; gap: 3px;
background-color: var(--buttonBg); background-color: var(--buttonBg);
@ -42,7 +42,10 @@ $buttonSize : 2em;
} }
.icon { .icon {
font-size: 0.80em; display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.70em;
} }
.exButton { .exButton {
@ -58,4 +61,11 @@ $buttonSize : 2em;
box-sizing: border-box; box-sizing: border-box;
font-size: 0.65em; font-size: 0.65em;
} }
.exButtonIcon {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 0.80em;
}
</style> </style>

View file

@ -65,13 +65,15 @@
<div :class="$style.sortOrderAreaTags"> <div :class="$style.sortOrderAreaTags">
<MkTagItem <MkTagItem
v-for="order in sortOrders" v-for="order in sortOrders"
:key="order.column" :key="order.key"
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'" :iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
:exButtonIconClass="'ti ti-x'" :exButtonIconClass="'ti ti-x'"
:content="order.column" :content="order.key"
@click="onToggleSortOrderButtonClicked(order)"
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
/> />
</div> </div>
<MkButton :class="$style.sortOrderAddButton"> <MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
<span class="ti ti-plus"/> <span class="ti ti-plus"/>
</MkButton> </MkButton>
</div> </div>
@ -152,6 +154,7 @@ import MkSelect from '@/components/MkSelect.vue';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/scripts/device-kind.js';
import { GridSetting } from '@/components/grid/grid.js'; import { GridSetting } from '@/components/grid/grid.js';
import MkTagItem from '@/components/MkTagItem.vue'; import MkTagItem from '@/components/MkTagItem.vue';
import { MenuItem } from '@/types/menu.js';
type GridItem = { type GridItem = {
checked: boolean; checked: boolean;
@ -171,18 +174,20 @@ type GridItem = {
originalUrl?: string | null; originalUrl?: string | null;
} }
type GridSortOrderKey = const gridSortOrderKeys = [
'name' | 'name',
'category' | 'category',
'aliases' | 'aliases',
'type' | 'type',
'license' | 'license',
'isSensitive' | 'isSensitive',
'localOnly' | 'localOnly',
'updatedAt'; 'updatedAt',
];
type GridSortOrderKey = typeof gridSortOrderKeys[number];
type GridSortOrder = { type GridSortOrder = {
column: GridSortOrderKey; key: GridSortOrderKey;
direction: 'ASC' | 'DESC'; direction: 'ASC' | 'DESC';
} }
@ -237,7 +242,6 @@ const querySensitive = ref<string | null>(null);
const queryLocalOnly = ref<string | null>(null); const queryLocalOnly = ref<string | null>(null);
const previousQuery = ref<string | undefined>(undefined); const previousQuery = ref<string | undefined>(undefined);
const sortOrders = ref<GridSortOrder[]>([]); const sortOrders = ref<GridSortOrder[]>([]);
sortOrders.value.push({ column: 'updatedAt', direction: 'DESC' }, { column: 'name', direction: 'ASC' });
const requestLogs = ref<RequestLogItem[]>([]); const requestLogs = ref<RequestLogItem[]>([]);
const gridItems = ref<GridItem[]>([]); const gridItems = ref<GridItem[]>([]);
@ -352,6 +356,36 @@ function onGridResetButtonClicked() {
refreshGridItems(); refreshGridItems();
} }
function onToggleSortOrderButtonClicked(order: GridSortOrder) {
console.log(order);
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);
}
async function onSearchButtonClicked() { async function onSearchButtonClicked() {
await refreshCustomEmojis(); await refreshCustomEmojis();
} }
@ -529,6 +563,7 @@ async function refreshCustomEmojis() {
query: query, query: query,
limit: limit, limit: limit,
page: currentPage.value, page: currentPage.value,
sort: sortOrders.value.map(({ key, direction }) => ({ key: key as any, direction })),
}), }),
() => { () => {
}, },
@ -654,6 +689,7 @@ onMounted(async () => {
flex-direction: row; flex-direction: row;
align-items: flex-start; align-items: flex-start;
justify-content: flex-start; justify-content: flex-start;
flex-wrap: wrap;
gap: 8px; gap: 8px;
} }

View file

@ -6981,7 +6981,7 @@ export type operations = {
* @default DESC * @default DESC
* @enum {string} * @enum {string}
*/ */
order: 'ASC' | 'DESC'; direction: 'ASC' | 'DESC';
})[]; })[];
}; };
}; };