filter
Gitea Actions Demo / Deploy (push) Successful in 33s

This commit is contained in:
vadim committed 2026-09-25 18:55:11 +03:00
1 parent 0ce91bd0e5
commit 4c6f21ef78
4 files changed
+57 -14

No files matched your search

+13 -3
View File
@@ -63,6 +63,17 @@ async function loadMore({ done }: { done: (status: 'ok' | 'empty' | 'error') =>
} }
} }
const hover = (userId: string) => {
if (hoveredId.value === userId) {
return { zIndex: 2 }
}
if (props.selected.includes(userId)) {
return { zIndex: 1 }
}
return { zIndex: 0 }
}
onMounted(() => { onMounted(() => {
loadMore({ done: () => {} }) loadMore({ done: () => {} })
}) })
@@ -71,7 +82,7 @@ onMounted(() => {
<template> <template>
<div class="d-flex align-center"> <div class="d-flex align-center">
<v-avatar <v-avatar
v-for="(user, index) in avatarUsers" v-for="user in avatarUsers"
:key="user.id" :key="user.id"
rounded="circle" rounded="circle"
border border
@@ -80,7 +91,7 @@ onMounted(() => {
:text="initials(user)" :text="initials(user)"
class="stack-avatar cursor-pointer" class="stack-avatar cursor-pointer"
:class="{ 'bg-primary': isSelected(user.id) }" :class="{ 'bg-primary': isSelected(user.id) }"
:style="{ zIndex: hoveredId === user.id ? avatarUsers.length + 1 : avatarUsers.length - index }" :style="hover(user.id)"
@mouseenter="hoveredId = user.id" @mouseenter="hoveredId = user.id"
@mouseleave="hoveredId = null" @mouseleave="hoveredId = null"
@click="toggle(user.id)" @click="toggle(user.id)"
@@ -92,7 +103,6 @@ onMounted(() => {
rounded="circle" rounded="circle"
border border
density="compact" density="compact"
variant="tonal"
class="stack-avatar cursor-pointer" class="stack-avatar cursor-pointer"
:style="{ zIndex: hoveredId === 'more' ? avatarUsers.length + 1 : 0 }" :style="{ zIndex: hoveredId === 'more' ? avatarUsers.length + 1 : 0 }"
v-bind="activatorProps" v-bind="activatorProps"
+2 -2
View File
@@ -36,11 +36,11 @@ const cancel = () => {
</template> </template>
<template v-else> <template v-else>
<v-textarea class="mb-1" hide-details v-model="draft" variant="outlined" auto-grow rows="4" /> <v-textarea autofocus class="mb-1" hide-details v-model="draft" variant="outlined" auto-grow rows="4" />
<div class="d-flex justify-end ga-1"> <div class="d-flex justify-end ga-1">
<v-btn density="compact" variant="text" text="Cancel" @click="cancel" /> <v-btn density="compact" variant="text" text="Cancel" @click="cancel" />
<v-btn density="compact" color="primary" variant="tonal" text="Save" @click="save" /> <v-btn density="compact" color="primary" variant="flat" text="Save" @click="save" />
</div> </div>
</template> </template>
</div> </div>
+16 -8
View File
@@ -1,29 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'
import AssigneeFilter from '@/components/AssigneeFilter.vue' import AssigneeFilter from '@/components/AssigneeFilter.vue'
import TextFilter from '@/components/TextFilter.vue' import TextFilter from '@/components/TextFilter.vue'
interface Props { interface Props {
text?: string | null text?: string | null
assigneeId?: string | null
} }
withDefaults(defineProps<Props>(), { text: null }) const props = withDefaults(defineProps<Props>(), { text: null, assigneeId: null })
const emit = defineEmits<{ 'update:text': [value: string | null] }>() const emit = defineEmits<{
'update:text': [value: string | null]
'update:assigneeId': [value: string | null]
'update:clear': []
}>()
function onChanged(value: string[]) { const selectedAssignees = computed(() => (props.assigneeId ? [props.assigneeId] : []))
console.log(value)
function onAssigneeChanged(value: string[]) {
emit('update:assigneeId', value.at(-1) ?? null)
} }
</script> </script>
<template> <template>
<div class="u-grid2 ga-4 align-center"> <div class="filter-grid ga-4 align-center">
<text-filter :model-value="text" @update:model-value="emit('update:text', $event)" /> <text-filter :model-value="text" @update:model-value="emit('update:text', $event)" />
<assignee-filter @changed="onChanged" :selected="['4Jpoz4EgViFrMpl7jQ969mVyX2IFYg5H']" /> <assignee-filter :selected="selectedAssignees" @changed="onAssigneeChanged" />
<v-btn variant="text">clear filters</v-btn> <v-btn prepend-icon="mdi-close" variant="tonal" @click="emit('update:clear')">Clear Filters</v-btn>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.u-grid2 { .filter-grid {
display: grid; display: grid;
grid-template-columns: 1fr auto auto; grid-template-columns: 1fr auto auto;
} }
+26 -1
View File
@@ -26,6 +26,7 @@ const totalPages = ref(1)
const serverItems = ref<Issue[]>([]) const serverItems = ref<Issue[]>([])
const text = ref<string | null>(null) const text = ref<string | null>(null)
const assigneeId = ref<string | null>(null)
const selected = ref<[string] | []>([]) const selected = ref<[string] | []>([])
const batch = ref<number[]>([]) const batch = ref<number[]>([])
const deleting = ref(false) const deleting = ref(false)
@@ -35,6 +36,7 @@ async function fetch() {
page: page.value, page: page.value,
limit: itemsPerPage.value, limit: itemsPerPage.value,
text: text.value, text: text.value,
assigneeId: assigneeId.value,
projectId: currentProjectId.value, projectId: currentProjectId.value,
}) })
@@ -52,6 +54,7 @@ function syncQuery() {
const query: Record<string, string> = { page: String(page.value) } const query: Record<string, string> = { page: String(page.value) }
if (text.value) query.text = text.value if (text.value) query.text = text.value
if (assigneeId.value) query.assignee = assigneeId.value
if (selected.value.length) query.selected_issue = selected.value[0] if (selected.value.length) query.selected_issue = selected.value[0]
router.replace({ query }) router.replace({ query })
@@ -62,6 +65,7 @@ watch(
(query) => { (query) => {
page.value = query.page ? Number(query.page) : 1 page.value = query.page ? Number(query.page) : 1
text.value = query.text ? String(query.text) : null text.value = query.text ? String(query.text) : null
assigneeId.value = query.assignee ? String(query.assignee) : null
selected.value = query.selected_issue ? [String(query.selected_issue)] : [] selected.value = query.selected_issue ? [String(query.selected_issue)] : []
}, },
{ immediate: true }, { immediate: true },
@@ -92,6 +96,20 @@ async function onTextChanged(value: string | null) {
await load() await load()
} }
async function onAssigneeChanged(value: string | null) {
assigneeId.value = value
page.value = 1
await load()
}
async function onClear() {
text.value = null
assigneeId.value = null
page.value = 1
await load()
}
function close() { function close() {
selected.value = [] selected.value = []
} }
@@ -153,7 +171,14 @@ async function onDeleteBatch() {
<div class="d-flex flex-column ga-2"> <div class="d-flex flex-column ga-2">
<div class="u-grid ga-1"> <div class="u-grid ga-1">
<div class="u-height"> <div class="u-height">
<issue-filter class="mb-2" :text="text" @update:text="onTextChanged" /> <issue-filter
class="mb-2"
:text="text"
:assignee-id="assigneeId"
@update:text="onTextChanged"
@update:assignee-id="onAssigneeChanged"
@update:clear="onClear"
/>
<v-list class="pa-0" density="compact" v-model:selected="selected" mandatory> <v-list class="pa-0" density="compact" v-model:selected="selected" mandatory>
<v-list-item> <v-list-item>
<template #prepend> <template #prepend>