Add activity priority desk filter and keep detail browsing inside the same column after stage changes.
When done/reopen/stage moves leave a column, advance to the next activity there or return to the list if empty. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -43,6 +43,7 @@ import type {
|
||||
ActivityBoardDto,
|
||||
ActivityDto,
|
||||
ActivityFilter,
|
||||
ActivityPriority,
|
||||
ActivityStageCountsDto,
|
||||
ActivityStageDto,
|
||||
ActivityStatus,
|
||||
@@ -51,7 +52,7 @@ import type {
|
||||
OrgUserDto,
|
||||
PaginatedResponse,
|
||||
} from '@mento/shared';
|
||||
import { brand } from '@mento/shared';
|
||||
import { ACTIVITY_PRIORITY_KEYS, brand } from '@mento/shared';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
import { canMutateActivity } from '@/lib/activity-access';
|
||||
import { canManageSettings, canViewAllRecords } from '@/lib/roles';
|
||||
@@ -95,6 +96,7 @@ const actGridStyle = computed(() => ({
|
||||
|
||||
/** 'all' یا شناسهٔ نوع فعالیت */
|
||||
type TypeFilter = string;
|
||||
type PriorityFilter = 'all' | ActivityPriority;
|
||||
type StatusFilter = 'all' | ActivityStatus;
|
||||
type UiStatus = 'done' | 'progress' | 'planned' | 'overdue' | 'canceled';
|
||||
type DeskScope = 'mine' | 'team';
|
||||
@@ -122,6 +124,18 @@ const STATUS_FILTERS: Array<{ key: StatusFilter; label: string }> = [
|
||||
{ key: 'canceled', label: 'لغو شده' },
|
||||
];
|
||||
|
||||
const activityPriorities = useActivityPriorities();
|
||||
const PRIORITY_FILTERS = computed<
|
||||
Array<{ key: PriorityFilter; label: string; color?: string }>
|
||||
>(() => [
|
||||
{ key: 'all', label: 'همه اولویتها' },
|
||||
...activityPriorities.items.value.map((row) => ({
|
||||
key: row.key as PriorityFilter,
|
||||
label: row.label,
|
||||
color: row.color,
|
||||
})),
|
||||
]);
|
||||
|
||||
const pageSize = usePageSize('activities', 10);
|
||||
|
||||
const route = useRoute();
|
||||
@@ -181,7 +195,7 @@ const boardDeleteOpen = ref(false);
|
||||
|
||||
async function onTypesChanged() {
|
||||
await activityTypes.load(true);
|
||||
await useActivityPriorities().load(true);
|
||||
await activityPriorities.load(true);
|
||||
kanbanReload.value += 1;
|
||||
await refreshAll();
|
||||
}
|
||||
@@ -245,6 +259,13 @@ const statusFilter = computed<StatusFilter>(() => {
|
||||
: 'all';
|
||||
});
|
||||
|
||||
const priorityFilter = computed<PriorityFilter>(() => {
|
||||
const value = typeof route.query.priority === 'string' ? route.query.priority : 'all';
|
||||
return ACTIVITY_PRIORITY_KEYS.includes(value as ActivityPriority)
|
||||
? (value as ActivityPriority)
|
||||
: 'all';
|
||||
});
|
||||
|
||||
const assigneeFilter = computed(() =>
|
||||
typeof route.query.assigneeId === 'string' ? route.query.assigneeId : '',
|
||||
);
|
||||
@@ -323,6 +344,7 @@ const sharedParams = computed<Record<string, string | undefined>>(() => ({
|
||||
? legacyBaseType.value
|
||||
: undefined,
|
||||
status: statusFilter.value === 'all' ? undefined : statusFilter.value,
|
||||
priority: priorityFilter.value === 'all' ? undefined : priorityFilter.value,
|
||||
assigneeId: assigneeFilter.value || undefined,
|
||||
title: titleFilter.value.trim() || undefined,
|
||||
customer: customerFilter.value.trim() || undefined,
|
||||
@@ -335,6 +357,7 @@ function stageDotStyle(s: ActivityStageDto) {
|
||||
const activeFacetCount = computed(() => {
|
||||
let n = 0;
|
||||
if (typeFilter.value !== 'all') n += 1;
|
||||
if (priorityFilter.value !== 'all') n += 1;
|
||||
if (statusFilter.value !== 'all') n += 1;
|
||||
if (assigneeFilter.value) n += 1;
|
||||
if (titleFilter.value.trim()) n += 1;
|
||||
@@ -437,6 +460,7 @@ function deskDetailQuery(columnStageId?: string): Record<string, string> {
|
||||
if (search) query.q = search;
|
||||
if (typeFilter.value !== 'all') query.typeDefId = typeFilter.value;
|
||||
if (statusFilter.value !== 'all') query.status = statusFilter.value;
|
||||
if (priorityFilter.value !== 'all') query.priority = priorityFilter.value;
|
||||
if (assigneeFilter.value) query.assigneeId = assigneeFilter.value;
|
||||
if (titleFilter.value.trim()) query.title = titleFilter.value.trim();
|
||||
if (customerFilter.value.trim()) query.customer = customerFilter.value.trim();
|
||||
@@ -775,6 +799,13 @@ function setStatusFilter(next: string) {
|
||||
patchFacetQuery({ status: value === 'all' ? undefined : value });
|
||||
}
|
||||
|
||||
function setPriorityFilter(next: string) {
|
||||
const value: PriorityFilter = ACTIVITY_PRIORITY_KEYS.includes(next as ActivityPriority)
|
||||
? (next as ActivityPriority)
|
||||
: 'all';
|
||||
patchFacetQuery({ priority: value === 'all' ? undefined : value });
|
||||
}
|
||||
|
||||
function setAssigneeFilter(next: string) {
|
||||
patchFacetQuery({
|
||||
assigneeId: next || undefined,
|
||||
@@ -799,6 +830,7 @@ function clearFacets() {
|
||||
type: undefined,
|
||||
typeDefId: undefined,
|
||||
status: undefined,
|
||||
priority: undefined,
|
||||
assigneeId: undefined,
|
||||
title: undefined,
|
||||
customer: undefined,
|
||||
@@ -1164,6 +1196,7 @@ onMounted(() => {
|
||||
mobileQuery.addEventListener('change', syncMobile);
|
||||
void loadUsers();
|
||||
void activityTypes.load(true);
|
||||
void activityPriorities.load();
|
||||
void loadBoards()
|
||||
.then(() => loadStages())
|
||||
.then(() => {
|
||||
@@ -1461,16 +1494,19 @@ onUnmounted(() => {
|
||||
:customer="customerFilter"
|
||||
:due="dueFilter"
|
||||
:type-key="typeFilter"
|
||||
:priority-key="priorityFilter"
|
||||
:status-key="statusFilter"
|
||||
:assignee-id="assigneeFilter"
|
||||
:show-assignee="showDeskTabs"
|
||||
:users="users"
|
||||
:types="TYPE_FILTERS"
|
||||
:priorities="PRIORITY_FILTERS"
|
||||
:statuses="STATUS_FILTERS"
|
||||
@title="setTitleFilter"
|
||||
@customer="setCustomerFilter"
|
||||
@due="setDueFilter"
|
||||
@type="setTypeFilter"
|
||||
@priority="setPriorityFilter"
|
||||
@status="setStatusFilter"
|
||||
@assignee="setAssigneeFilter"
|
||||
@clear="clearFacets"
|
||||
@@ -1680,16 +1716,19 @@ onUnmounted(() => {
|
||||
:customer="customerFilter"
|
||||
:due="dueFilter"
|
||||
:type-key="typeFilter"
|
||||
:priority-key="priorityFilter"
|
||||
:status-key="statusFilter"
|
||||
:assignee-id="assigneeFilter"
|
||||
:show-assignee="showDeskTabs"
|
||||
:users="users"
|
||||
:types="TYPE_FILTERS"
|
||||
:priorities="PRIORITY_FILTERS"
|
||||
:statuses="STATUS_FILTERS"
|
||||
@title="setTitleFilter"
|
||||
@customer="setCustomerFilter"
|
||||
@due="setDueFilter"
|
||||
@type="setTypeFilter"
|
||||
@priority="setPriorityFilter"
|
||||
@status="setStatusFilter"
|
||||
@assignee="setAssigneeFilter"
|
||||
@done="onFacetDone"
|
||||
|
||||
Reference in New Issue
Block a user