This commit is contained in:
vadim committed 2026-09-28 15:43:50 +03:00
1 parent baf0fa186e
commit 6f651eeaeb
5 files changed
+67 -4

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ const { data } = useEventSource<string[], IssueSseEvent>(
console.log('Failed to connect EventSource after 3 retries') console.log('Failed to connect EventSource after 3 retries')
}, },
}, },
autoConnect: true, autoConnect: false,
}, },
) )
+9 -1
View File
@@ -2,16 +2,19 @@
import { computed } from 'vue' 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'
import StatusFilter from '@/components/StatusFilter.vue'
interface Props { interface Props {
text?: string | null text?: string | null
assigneeId?: string | null assigneeId?: string | null
status?: string | null
} }
const props = withDefaults(defineProps<Props>(), { text: null, assigneeId: null }) const props = withDefaults(defineProps<Props>(), { text: null, assigneeId: null })
const emit = defineEmits<{ const emit = defineEmits<{
'update:text': [value: string | null] 'update:text': [value: string | null]
'update:assigneeId': [value: string | null] 'update:assigneeId': [value: string | null]
'update:status': [value: string | null]
'update:clear': [] 'update:clear': []
}>() }>()
@@ -20,11 +23,16 @@ const selectedAssignees = computed(() => (props.assigneeId ? [props.assigneeId]
function onAssigneeChanged(value: string[]) { function onAssigneeChanged(value: string[]) {
emit('update:assigneeId', value.at(-1) ?? null) emit('update:assigneeId', value.at(-1) ?? null)
} }
function onStatusChanged(alias: string) {
emit('update:status', alias)
}
</script> </script>
<template> <template>
<div class="filter-grid 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)" />
<status-filter :status="status" @changed="onStatusChanged" />
<assignee-filter :selected="selectedAssignees" @changed="onAssigneeChanged" /> <assignee-filter :selected="selectedAssignees" @changed="onAssigneeChanged" />
<v-btn prepend-icon="mdi-close" variant="tonal" @click="emit('update:clear')">Clear Filters</v-btn> <v-btn prepend-icon="mdi-close" variant="tonal" @click="emit('update:clear')">Clear Filters</v-btn>
</div> </div>
@@ -33,6 +41,6 @@ function onAssigneeChanged(value: string[]) {
<style scoped lang="scss"> <style scoped lang="scss">
.filter-grid { .filter-grid {
display: grid; display: grid;
grid-template-columns: 1fr auto auto; grid-template-columns: 1fr auto auto auto;
} }
</style> </style>
+40
View File
@@ -0,0 +1,40 @@
<script setup lang="ts">
import { useStatusStore } from '@/stores/status.ts'
import { ref } from 'vue'
interface Props {
status?: string | null
}
const { status } = defineProps<Props>()
const emit = defineEmits<{ changed: [value: string] }>()
const statusStore = useStatusStore()
const selected = ref(status)
const onUpdate = (val: unknown) => emit('changed', val as string)
</script>
<template>
<v-btn-toggle
v-model="selected"
class="border-opacity-25"
border
divided
size="default"
density="compact"
variant="text"
@update:model-value="onUpdate"
>
<v-btn
slim
v-for="status in statusStore.statuses"
:color="status.color"
:value="status.alias"
:key="status.alias"
rounded="0"
>
<div class="text-default">{{ status.name }}</div>
</v-btn>
</v-btn-toggle>
</template>
<style scoped lang="scss"></style>
+2 -2
View File
@@ -129,7 +129,7 @@ function openProject(project: Project) {
<v-row density="compact"> <v-row density="compact">
<v-col cols="12" md="8"> <v-col cols="12" md="8">
<v-card> <v-card border>
<v-card-title class="d-flex align-center justify-space-between"> <v-card-title class="d-flex align-center justify-space-between">
<span>Мои задачи</span> <span>Мои задачи</span>
<v-btn size="small" variant="text" to="/issues">Все задачи</v-btn> <v-btn size="small" variant="text" to="/issues">Все задачи</v-btn>
@@ -177,7 +177,7 @@ function openProject(project: Project) {
</v-col> </v-col>
<v-col cols="12" md="4"> <v-col cols="12" md="4">
<v-card> <v-card border>
<v-card-title class="d-flex align-center justify-space-between"> <v-card-title class="d-flex align-center justify-space-between">
<span>Проекты</span> <span>Проекты</span>
<v-btn size="small" variant="text" to="/settings/projects">Все проекты</v-btn> <v-btn size="small" variant="text" to="/settings/projects">Все проекты</v-btn>
+15
View File
@@ -27,6 +27,7 @@ const serverItems = ref<Issue[]>([])
const text = ref<string | null>(null) const text = ref<string | null>(null)
const assigneeId = ref<string | null>(null) const assigneeId = ref<string | null>(null)
const status = 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)
@@ -36,6 +37,7 @@ async function fetch() {
page: page.value, page: page.value,
limit: itemsPerPage.value, limit: itemsPerPage.value,
text: text.value, text: text.value,
status: status.value,
assigneeId: assigneeId.value, assigneeId: assigneeId.value,
projectId: currentProjectId.value, projectId: currentProjectId.value,
}) })
@@ -55,6 +57,7 @@ function syncQuery() {
if (text.value) query.text = text.value if (text.value) query.text = text.value
if (assigneeId.value) query.assignee = assigneeId.value if (assigneeId.value) query.assignee = assigneeId.value
if (status.value) query.status = status.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 })
@@ -66,6 +69,7 @@ watch(
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 assigneeId.value = query.assignee ? String(query.assignee) : null
status.value = query.status ? String(query.status) : null
selected.value = query.selected_issue ? [String(query.selected_issue)] : [] selected.value = query.selected_issue ? [String(query.selected_issue)] : []
}, },
{ immediate: true }, { immediate: true },
@@ -102,6 +106,12 @@ async function onAssigneeChanged(value: string | null) {
await load() await load()
} }
async function onStatusChanged(value: string | null) {
status.value = value
page.value = 1
await load()
}
async function onClear() { async function onClear() {
text.value = null text.value = null
assigneeId.value = null assigneeId.value = null
@@ -175,8 +185,10 @@ async function onDeleteBatch() {
class="mb-2" class="mb-2"
:text="text" :text="text"
:assignee-id="assigneeId" :assignee-id="assigneeId"
:status="status"
@update:text="onTextChanged" @update:text="onTextChanged"
@update:assignee-id="onAssigneeChanged" @update:assignee-id="onAssigneeChanged"
@update:status="onStatusChanged"
@update:clear="onClear" @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>
@@ -198,7 +210,10 @@ async function onDeleteBatch() {
</template> </template>
<template #append> <template #append>
<div class="d-flex ga-4 align-center">
<issue-stats /> <issue-stats />
<v-btn density="compact" icon="mdi-dots-horizontal"></v-btn>
</div>
</template> </template>
</v-list-item> </v-list-item>