diff --git a/worklenz-frontend/public/locales/alb/task-list-filters.json b/worklenz-frontend/public/locales/alb/task-list-filters.json index 3ce3c704..bfb76191 100644 --- a/worklenz-frontend/public/locales/alb/task-list-filters.json +++ b/worklenz-frontend/public/locales/alb/task-list-filters.json @@ -68,5 +68,7 @@ "clearing": "Duke pastruar...", "cancel": "Anulo", "search": "Kërko", - "groupedBy": "Grupuar sipas" + "groupedBy": "Grupuar sipas", + "manageStatuses": "Menaxho Statuset", + "managePhases": "Menaxho Fazat" } diff --git a/worklenz-frontend/public/locales/de/task-list-filters.json b/worklenz-frontend/public/locales/de/task-list-filters.json index 9197cb97..8c08037f 100644 --- a/worklenz-frontend/public/locales/de/task-list-filters.json +++ b/worklenz-frontend/public/locales/de/task-list-filters.json @@ -65,8 +65,10 @@ "filtersActive": "Filter aktiv", "filterActive": "Filter aktiv", "clearAll": "Alle löschen", - "clearing": "Löschen...", - "cancel": "Abbrechen", + "clearing": "Wird gelöscht...", + "cancel": "Stornieren", "search": "Suchen", - "groupedBy": "Gruppiert nach" + "groupedBy": "Gruppiert nach", + "manageStatuses": "Status verwalten", + "managePhases": "Phasen verwalten" } diff --git a/worklenz-frontend/public/locales/en/task-list-filters.json b/worklenz-frontend/public/locales/en/task-list-filters.json index 3941b0e0..cdfa00e9 100644 --- a/worklenz-frontend/public/locales/en/task-list-filters.json +++ b/worklenz-frontend/public/locales/en/task-list-filters.json @@ -68,5 +68,7 @@ "clearing": "Clearing...", "cancel": "Cancel", "search": "Search", - "groupedBy": "Grouped by" + "groupedBy": "Grouped by", + "manageStatuses": "Manage Statuses", + "managePhases": "Manage Phases" } diff --git a/worklenz-frontend/public/locales/es/task-list-filters.json b/worklenz-frontend/public/locales/es/task-list-filters.json index 5a1941e0..39aeadb0 100644 --- a/worklenz-frontend/public/locales/es/task-list-filters.json +++ b/worklenz-frontend/public/locales/es/task-list-filters.json @@ -64,5 +64,7 @@ "clearing": "Limpiando...", "cancel": "Cancelar", "search": "Buscar", - "groupedBy": "Agrupado por" + "groupedBy": "Agrupado por", + "manageStatuses": "Gestionar Estados", + "managePhases": "Gestionar Fases" } diff --git a/worklenz-frontend/public/locales/pt/task-list-filters.json b/worklenz-frontend/public/locales/pt/task-list-filters.json index 76e9287f..0bd8bc31 100644 --- a/worklenz-frontend/public/locales/pt/task-list-filters.json +++ b/worklenz-frontend/public/locales/pt/task-list-filters.json @@ -65,5 +65,7 @@ "clearing": "Limpando...", "cancel": "Cancelar", "search": "Pesquisar", - "groupedBy": "Agrupado por" + "groupedBy": "Agrupado por", + "manageStatuses": "Gerenciar Status", + "managePhases": "Gerenciar Fases" } diff --git a/worklenz-frontend/public/locales/zh/task-list-filters.json b/worklenz-frontend/public/locales/zh/task-list-filters.json index a3354305..f6a50e1e 100644 --- a/worklenz-frontend/public/locales/zh/task-list-filters.json +++ b/worklenz-frontend/public/locales/zh/task-list-filters.json @@ -62,5 +62,7 @@ "clearing": "清除中...", "cancel": "取消", "search": "搜索", - "groupedBy": "分组依据" + "groupedBy": "分组依据", + "manageStatuses": "管理状态", + "managePhases": "管理阶段" } \ No newline at end of file diff --git a/worklenz-frontend/src/components/project-task-filters/create-status-drawer/create-status-drawer.tsx b/worklenz-frontend/src/components/project-task-filters/create-status-drawer/create-status-drawer.tsx index 6945e578..f51925cf 100644 --- a/worklenz-frontend/src/components/project-task-filters/create-status-drawer/create-status-drawer.tsx +++ b/worklenz-frontend/src/components/project-task-filters/create-status-drawer/create-status-drawer.tsx @@ -14,7 +14,7 @@ import { toggleDrawer } from '@/features/projects/status/StatusSlice'; import './create-status-drawer.css'; -import { createStatus, fetchStatusesCategories } from '@/features/taskAttributes/taskStatusSlice'; +import { createStatus, fetchStatusesCategories, fetchStatuses } from '@/features/taskAttributes/taskStatusSlice'; import { ITaskStatusCategory } from '@/types/status.types'; import { useMixpanelTracking } from '@/hooks/useMixpanelTracking'; import useTabSearchParam from '@/hooks/useTabSearchParam'; @@ -56,6 +56,8 @@ const StatusDrawer: React.FC = () => { dispatch(toggleDrawer()); refreshTasks(); dispatch(fetchStatusesCategories()); + // Refetch task statuses to ensure UI reflects the new status + dispatch(fetchStatuses(projectId)); } }; diff --git a/worklenz-frontend/src/components/task-list-v2/TaskListV2Table.tsx b/worklenz-frontend/src/components/task-list-v2/TaskListV2Table.tsx index 0859270b..ac5227fe 100644 --- a/worklenz-frontend/src/components/task-list-v2/TaskListV2Table.tsx +++ b/worklenz-frontend/src/components/task-list-v2/TaskListV2Table.tsx @@ -476,8 +476,8 @@ const TaskListV2Section: React.FC = () => { ); })} -
-
+
+
{t('noTasksInGroup')}
diff --git a/worklenz-frontend/src/components/task-list-v2/constants/columns.ts b/worklenz-frontend/src/components/task-list-v2/constants/columns.ts index d8b229fe..5f8add14 100644 --- a/worklenz-frontend/src/components/task-list-v2/constants/columns.ts +++ b/worklenz-frontend/src/components/task-list-v2/constants/columns.ts @@ -18,16 +18,16 @@ export const BASE_COLUMNS = [ { id: 'taskKey', label: 'keyColumn', width: '100px', key: COLUMN_KEYS.KEY, minWidth: '100px', maxWidth: '150px' }, { id: 'title', label: 'taskColumn', width: '470px', isSticky: true, key: COLUMN_KEYS.NAME }, { id: 'description', label: 'descriptionColumn', width: '260px', key: COLUMN_KEYS.DESCRIPTION }, - { id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS }, - { id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES }, - { id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY }, - { id: 'dueDate', label: 'dueDateColumn', width: '140px', key: COLUMN_KEYS.DUE_DATE }, { id: 'progress', label: 'progressColumn', width: '120px', key: COLUMN_KEYS.PROGRESS }, + { id: 'assignees', label: 'assigneesColumn', width: '150px', key: COLUMN_KEYS.ASSIGNEES }, { id: 'labels', label: 'labelsColumn', width: 'auto', key: COLUMN_KEYS.LABELS }, { id: 'phase', label: 'phaseColumn', width: '120px', key: COLUMN_KEYS.PHASE }, + { id: 'status', label: 'statusColumn', width: '120px', key: COLUMN_KEYS.STATUS }, + { id: 'priority', label: 'priorityColumn', width: '120px', key: COLUMN_KEYS.PRIORITY }, { id: 'timeTracking', label: 'timeTrackingColumn', width: '120px', key: COLUMN_KEYS.TIME_TRACKING }, { id: 'estimation', label: 'estimationColumn', width: '120px', key: COLUMN_KEYS.ESTIMATION }, { id: 'startDate', label: 'startDateColumn', width: '140px', key: COLUMN_KEYS.START_DATE }, + { id: 'dueDate', label: 'dueDateColumn', width: '140px', key: COLUMN_KEYS.DUE_DATE }, { id: 'dueTime', label: 'dueTimeColumn', width: '120px', key: COLUMN_KEYS.DUE_TIME }, { id: 'completedDate', label: 'completedDateColumn', width: '140px', key: COLUMN_KEYS.COMPLETED_DATE }, { id: 'createdDate', label: 'createdDateColumn', width: '140px', key: COLUMN_KEYS.CREATED_DATE }, diff --git a/worklenz-frontend/src/components/task-management/improved-task-filters.tsx b/worklenz-frontend/src/components/task-management/improved-task-filters.tsx index b14d27e3..6e6669c0 100644 --- a/worklenz-frontend/src/components/task-management/improved-task-filters.tsx +++ b/worklenz-frontend/src/components/task-management/improved-task-filters.tsx @@ -82,7 +82,9 @@ import useIsProjectManager from '@/hooks/useIsProjectManager'; // Performance constants const FILTER_DEBOUNCE_DELAY = 300; // ms const SEARCH_DEBOUNCE_DELAY = 500; // ms -const MAX_FILTER_OPTIONS = 100; // Limit options to prevent UI lag +const MAX_FILTER_OPTIONS = 100; + + // Limit options to prevent UI lag // Optimized selectors with proper transformation logic const selectFilterData = createSelector( @@ -364,6 +366,7 @@ const FilterDropdown: React.FC<{ themeClasses: any; isDarkMode: boolean; className?: string; + dispatch?: any; }> = ({ section, onSelectionChange, @@ -372,6 +375,7 @@ const FilterDropdown: React.FC<{ themeClasses, isDarkMode, className = '', + dispatch, }) => { const { t } = useTranslation('task-list-filters'); // Add permission checks for groupBy section @@ -480,8 +484,34 @@ const FilterDropdown: React.FC<{ {/* Configuration Buttons for GroupBy section */} {section.id === 'groupBy' && canConfigure && (
- {section.selectedValues[0] === 'phase' && } - {section.selectedValues[0] === 'status' && } + {section.selectedValues[0] === 'phase' && ( + + )} + {section.selectedValues[0] === 'status' && ( + + )}
)} @@ -1265,6 +1295,7 @@ const ImprovedTaskFilters: React.FC = ({ position, cla onToggle={() => handleDropdownToggle(section.id)} themeClasses={themeClasses} isDarkMode={isDarkMode} + dispatch={dispatch} /> )) ) : ( diff --git a/worklenz-frontend/src/components/task-templates/import-task-template.tsx b/worklenz-frontend/src/components/task-templates/import-task-template.tsx index 6bfef851..5fb8729a 100644 --- a/worklenz-frontend/src/components/task-templates/import-task-template.tsx +++ b/worklenz-frontend/src/components/task-templates/import-task-template.tsx @@ -23,6 +23,7 @@ import { fetchBoardTaskGroups } from '@/features/board/board-slice'; import { setImportTaskTemplateDrawerOpen } from '@/features/project/project.slice'; import useTabSearchParam from '@/hooks/useTabSearchParam'; import { fetchTaskGroups } from '@/features/tasks/tasks.slice'; +import { fetchTasksV3 } from '@/features/task-management/task-management.slice'; const ImportTaskTemplate = () => { const dispatch = useAppDispatch(); @@ -90,7 +91,8 @@ const ImportTaskTemplate = () => { const res = await taskTemplatesApiService.importTemplate(projectId, tasks); if (res.done) { if (tab === 'board') dispatch(fetchBoardTaskGroups(projectId)); - if (tab === 'tasks-list') dispatch(fetchTaskGroups(projectId)); + if (tab === 'tasks-list') dispatch(fetchTasksV3(projectId)); + dispatch(setImportTaskTemplateDrawerOpen(false)); } } catch (error) { diff --git a/worklenz-frontend/src/hooks/useFilterDataLoader.ts b/worklenz-frontend/src/hooks/useFilterDataLoader.ts index 13a05f38..6165e018 100644 --- a/worklenz-frontend/src/hooks/useFilterDataLoader.ts +++ b/worklenz-frontend/src/hooks/useFilterDataLoader.ts @@ -4,6 +4,7 @@ import { useAppSelector } from '@/hooks/useAppSelector'; import { fetchPriorities } from '@/features/taskAttributes/taskPrioritySlice'; import { fetchLabelsByProject, fetchTaskAssignees } from '@/features/tasks/tasks.slice'; import { getTeamMembers } from '@/features/team-members/team-members.slice'; +import { fetchStatuses } from '@/features/taskAttributes/taskStatusSlice'; /** * Hook to manage filter data loading independently of main task list loading @@ -15,6 +16,9 @@ export const useFilterDataLoader = () => { // Memoize the priorities selector to prevent unnecessary re-renders const priorities = useAppSelector(state => state.priorityReducer.priorities); + // Memoize the statuses selector to prevent unnecessary re-renders + const statuses = useAppSelector(state => state.taskStatusReducer.status); + // Memoize the projectId selector to prevent unnecessary re-renders const projectId = useAppSelector(state => state.projectReducer.projectId); @@ -32,6 +36,11 @@ export const useFilterDataLoader = () => { // They will update the UI when ready, but won't block initial render dispatch(fetchLabelsByProject(projectId)); dispatch(fetchTaskAssignees(projectId)); + + // Load statuses if not already loaded + if (!statuses.length) { + dispatch(fetchStatuses(projectId)); + } } // Load team members for member filters @@ -49,7 +58,7 @@ export const useFilterDataLoader = () => { console.error('Error loading filter data:', error); // Don't throw - filter loading errors shouldn't break the main UI } - }, [dispatch, priorities.length, projectId]); + }, [dispatch, priorities.length, statuses.length, projectId]); // Load filter data on mount and when dependencies change useEffect(() => { diff --git a/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx b/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx index 4132f0c7..cb4fabae 100644 --- a/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/project-view-header.tsx @@ -66,6 +66,7 @@ import { fetchPhasesByProjectId } from '@/features/projects/singleProject/phase/ import { fetchEnhancedKanbanGroups } from '@/features/enhanced-kanban/enhanced-kanban.slice'; import { fetchTasksV3 } from '@/features/task-management/task-management.slice'; import { ShareAltOutlined } from '@ant-design/icons'; +import { fetchStatuses } from '@/features/taskAttributes/taskStatusSlice'; const ProjectViewHeader = memo(() => { const navigate = useNavigate(); @@ -101,9 +102,9 @@ const ProjectViewHeader = memo(() => { switch (tab) { case 'tasks-list': + dispatch(fetchStatuses(projectId)); dispatch(fetchTaskListColumns(projectId)); dispatch(fetchPhasesByProjectId(projectId)); - dispatch(fetchTaskGroups(projectId)); dispatch(fetchTasksV3(projectId)); break; case 'board':