Add searchable assignee and creator filters on the routines manage toolbar.

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-14 20:45:37 +03:30
co-authored by Cursor
parent fb6aa77465
commit d282627af7
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed, inject, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { Select as ASelect } from 'ant-design-vue';
import type { RoutineCategoryDto, RoutineDto } from '@mento/shared';
import UiIcon from '@/components/UiIcon.vue';
import UserAvatar from '@/components/UserAvatar.vue';
@@ -28,7 +29,8 @@ const loading = ref(true);
const error = ref('');
const q = ref('');
const status = ref<'all' | 'active' | 'inactive'>('all');
const assignee = ref('');
const assignee = ref<string | undefined>(undefined);
const creator = ref<string | undefined>(undefined);
const busyId = ref<string | null>(null);
const menuFor = ref<string | null>(null);
@@ -60,6 +62,7 @@ const filtered = computed(() => {
if (status.value === 'active' && !r.isActive) return false;
if (status.value === 'inactive' && r.isActive) return false;
if (assignee.value && r.assignee?.id !== assignee.value && `team:${r.team?.id}` !== assignee.value) return false;
if (creator.value && (r.createdBy?.id ?? r.createdById) !== creator.value) return false;
if (term && !r.title.includes(term)) return false;
return true;
});
@@ -208,21 +211,53 @@ async function deleteCat(c: RoutineCategoryDto) {
const users = computed(() => shell.context.value?.users ?? []);
const teams = computed(() => shell.context.value?.teams ?? []);
const assigneeFilterOptions = computed(() => [
...users.value.map((u) => ({ value: u.id, label: u.fullName })),
...teams.value.map((t) => ({ value: `team:${t.id}`, label: `تیم ${t.name}` })),
]);
const creatorFilterOptions = computed(() =>
users.value.map((u) => ({ value: u.id, label: u.fullName })),
);
function filterSelectOption(input: string, option?: { label?: string }) {
const q = input.trim().toLocaleLowerCase('fa');
if (!q) return true;
return String(option?.label ?? '')
.toLocaleLowerCase('fa')
.includes(q);
}
</script>
<template>
<div class="manage">
<div class="toolbar">
<UiSearch v-model="q" placeholder="جستجوی عنوان…" class="search" />
<UiSelect v-model="assignee" size="sm" class="who">
<option value="">همه مسئول‌ها</option>
<optgroup label="کاربران">
<option v-for="u in users" :key="u.id" :value="u.id">{{ u.fullName }}</option>
</optgroup>
<optgroup v-if="teams.length" label="تیم‌ها">
<option v-for="t in teams" :key="t.id" :value="`team:${t.id}`">{{ t.name }}</option>
</optgroup>
</UiSelect>
<div class="who">
<ASelect
v-model:value="assignee"
allow-clear
show-search
placeholder="همه مسئول‌ها"
:options="assigneeFilterOptions"
:filter-option="filterSelectOption"
:get-popup-container="(node) => node.parentElement ?? document.body"
style="width: 100%"
/>
</div>
<div class="who">
<ASelect
v-model:value="creator"
allow-clear
show-search
placeholder="همه سازنده‌ها"
:options="creatorFilterOptions"
:filter-option="filterSelectOption"
:get-popup-container="(node) => node.parentElement ?? document.body"
style="width: 100%"
/>
</div>
<UiSegmented v-model="status" :options="statusOptions" />
<span class="spacer" />
<UiButton variant="ghost" size="sm" @click="catsOpen = true; editCat(null)">