feat(localization): add new translation keys for task management
- Updated localization JSON files for Albanian, German, English, Spanish, Portuguese, and Chinese to include new keys for managing statuses and phases. - Enhanced existing translations for clarity and consistency across multiple languages. - Ensured that new keys align with recent UI changes to improve user experience in task management features.
This commit is contained in:
@@ -68,5 +68,7 @@
|
||||
"clearing": "Duke pastruar...",
|
||||
"cancel": "Anulo",
|
||||
"search": "Kërko",
|
||||
"groupedBy": "Grupuar sipas"
|
||||
"groupedBy": "Grupuar sipas",
|
||||
"manageStatuses": "Menaxho Statuset",
|
||||
"managePhases": "Menaxho Fazat"
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -68,5 +68,7 @@
|
||||
"clearing": "Clearing...",
|
||||
"cancel": "Cancel",
|
||||
"search": "Search",
|
||||
"groupedBy": "Grouped by"
|
||||
"groupedBy": "Grouped by",
|
||||
"manageStatuses": "Manage Statuses",
|
||||
"managePhases": "Manage Phases"
|
||||
}
|
||||
|
||||
@@ -64,5 +64,7 @@
|
||||
"clearing": "Limpiando...",
|
||||
"cancel": "Cancelar",
|
||||
"search": "Buscar",
|
||||
"groupedBy": "Agrupado por"
|
||||
"groupedBy": "Agrupado por",
|
||||
"manageStatuses": "Gestionar Estados",
|
||||
"managePhases": "Gestionar Fases"
|
||||
}
|
||||
|
||||
@@ -65,5 +65,7 @@
|
||||
"clearing": "Limpando...",
|
||||
"cancel": "Cancelar",
|
||||
"search": "Pesquisar",
|
||||
"groupedBy": "Agrupado por"
|
||||
"groupedBy": "Agrupado por",
|
||||
"manageStatuses": "Gerenciar Status",
|
||||
"managePhases": "Gerenciar Fases"
|
||||
}
|
||||
|
||||
@@ -62,5 +62,7 @@
|
||||
"clearing": "清除中...",
|
||||
"cancel": "取消",
|
||||
"search": "搜索",
|
||||
"groupedBy": "分组依据"
|
||||
"groupedBy": "分组依据",
|
||||
"manageStatuses": "管理状态",
|
||||
"managePhases": "管理阶段"
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -476,8 +476,8 @@ const TaskListV2Section: React.FC = () => {
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="text-sm italic text-gray-400 dark:text-gray-500 bg-white dark:bg-gray-900 px-4 py-1 rounded-md border border-gray-200 dark:border-gray-700">
|
||||
<div className="absolute left-4 top-1/2 transform -translate-y-1/2 flex items-center">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-900 px-3 py-1.5 rounded-md border border-gray-200 dark:border-gray-700 shadow-sm">
|
||||
{t('noTasksInGroup')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 && (
|
||||
<div className="inline-flex items-center gap-1 ml-2">
|
||||
{section.selectedValues[0] === 'phase' && <ConfigPhaseButton />}
|
||||
{section.selectedValues[0] === 'status' && <CreateStatusButton />}
|
||||
{section.selectedValues[0] === 'phase' && (
|
||||
<button
|
||||
onClick={() => {
|
||||
import('@/features/projects/singleProject/phase/phases.slice').then(({ toggleDrawer }) => {
|
||||
dispatch(toggleDrawer());
|
||||
});
|
||||
}}
|
||||
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 ease-in-out hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${
|
||||
isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'
|
||||
}`}
|
||||
>
|
||||
{t('managePhases')}
|
||||
</button>
|
||||
)}
|
||||
{section.selectedValues[0] === 'status' && (
|
||||
<button
|
||||
onClick={() => {
|
||||
import('@/features/projects/status/StatusSlice').then(({ toggleDrawer }) => {
|
||||
dispatch(toggleDrawer());
|
||||
});
|
||||
}}
|
||||
className={`inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md border transition-all duration-200 ease-in-out hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2 ${themeClasses.buttonBg} ${themeClasses.buttonBorder} ${themeClasses.buttonText} ${
|
||||
isDarkMode ? 'focus:ring-offset-gray-900' : 'focus:ring-offset-white'
|
||||
}`}
|
||||
>
|
||||
{t('manageStatuses')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1265,6 +1295,7 @@ const ImprovedTaskFilters: React.FC<ImprovedTaskFiltersProps> = ({ position, cla
|
||||
onToggle={() => handleDropdownToggle(section.id)}
|
||||
themeClasses={themeClasses}
|
||||
isDarkMode={isDarkMode}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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':
|
||||
|
||||
Reference in New Issue
Block a user