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;
sort?: {
key : FetchEmojisSortKeys;
order : 'ASC' | 'DESC';
direction : 'ASC' | 'DESC';
}[]
}
@ -508,7 +508,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
if (params?.sort) {
for (const sort of params.sort) {
builder.addOrderBy(`emoji.${sort.key}`, sort.order);
builder.addOrderBy(`emoji.${sort.key}`, sort.direction);
}
} else {
builder.addOrderBy('emoji.id', 'DESC');

View file

@ -82,13 +82,13 @@ export const paramDef = {
],
default: 'id',
},
order: {
direction: {
type: 'string',
enum: ['ASC', '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.sort = ps.sort?.map(it => ({
key: it.key,
order: it.order,
direction: it.direction,
}));
const result = await this.customEmojiService.fetchEmojis(params);

View file

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

View file

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

View file

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