@hed-hog/operations 0.0.329 → 0.0.331
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/controllers/operations-collaborators.controller.d.ts +7 -216
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-contracts.controller.d.ts +6 -6
- package/dist/controllers/operations-projects.controller.d.ts +25 -0
- package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
- package/dist/controllers/operations-projects.controller.js +48 -0
- package/dist/controllers/operations-projects.controller.js.map +1 -1
- package/dist/controllers/operations-reports.controller.d.ts +1 -1
- package/dist/controllers/operations-tasks.controller.d.ts +30 -5
- package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
- package/dist/controllers/operations-tasks.controller.js +43 -32
- package/dist/controllers/operations-tasks.controller.js.map +1 -1
- package/dist/controllers/operations-timesheets.controller.d.ts +9 -9
- package/dist/dashboard/components/DashboardLayout.d.ts +30 -0
- package/dist/dashboard/components/DashboardLayout.d.ts.map +1 -0
- package/dist/dashboard/components/DashboardLayout.js +87 -0
- package/dist/dashboard/components/DashboardLayout.js.map +1 -0
- package/dist/dashboard/components/widget-registry.d.ts +23 -0
- package/dist/dashboard/components/widget-registry.d.ts.map +1 -0
- package/dist/dashboard/components/widget-registry.js +245 -0
- package/dist/dashboard/components/widget-registry.js.map +1 -0
- package/dist/dashboard/hooks/useDashboardData.d.ts +20 -0
- package/dist/dashboard/hooks/useDashboardData.d.ts.map +1 -0
- package/dist/dashboard/hooks/useDashboardData.js +24 -0
- package/dist/dashboard/hooks/useDashboardData.js.map +1 -0
- package/dist/dashboard/types/widgets.types.d.ts +233 -0
- package/dist/dashboard/types/widgets.types.d.ts.map +1 -0
- package/dist/dashboard/types/widgets.types.js +6 -0
- package/dist/dashboard/types/widgets.types.js.map +1 -0
- package/dist/dashboard/widgets/CapacityDistribution.d.ts +23 -0
- package/dist/dashboard/widgets/CapacityDistribution.d.ts.map +1 -0
- package/dist/dashboard/widgets/CapacityDistribution.js +11 -0
- package/dist/dashboard/widgets/CapacityDistribution.js.map +1 -0
- package/dist/dashboard/widgets/EffortByProject.d.ts +22 -0
- package/dist/dashboard/widgets/EffortByProject.d.ts.map +1 -0
- package/dist/dashboard/widgets/EffortByProject.js +11 -0
- package/dist/dashboard/widgets/EffortByProject.js.map +1 -0
- package/dist/dashboard/widgets/HeadcountByArea.d.ts +24 -0
- package/dist/dashboard/widgets/HeadcountByArea.d.ts.map +1 -0
- package/dist/dashboard/widgets/HeadcountByArea.js +11 -0
- package/dist/dashboard/widgets/HeadcountByArea.js.map +1 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts +18 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts.map +1 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.js +12 -0
- package/dist/dashboard/widgets/ManagedProjectsStatus.js.map +1 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts +22 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.js +12 -0
- package/dist/dashboard/widgets/MyHoursPeriodKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts +19 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.js +17 -0
- package/dist/dashboard/widgets/MyOpenRequestsKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.d.ts +23 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.js +14 -0
- package/dist/dashboard/widgets/MyPendingRequestsList.js.map +1 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts +22 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.js +11 -0
- package/dist/dashboard/widgets/MyProjectAllocationsKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyQuickActions.d.ts +23 -0
- package/dist/dashboard/widgets/MyQuickActions.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyQuickActions.js +18 -0
- package/dist/dashboard/widgets/MyQuickActions.js.map +1 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts +23 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.js +22 -0
- package/dist/dashboard/widgets/MyRelevantDeadlines.js.map +1 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts +17 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.js +11 -0
- package/dist/dashboard/widgets/MyTimesheetStatusKpi.js.map +1 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.d.ts +21 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.d.ts.map +1 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.js +19 -0
- package/dist/dashboard/widgets/MyWeeklyJourney.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts +19 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.js +12 -0
- package/dist/dashboard/widgets/PortfolioCostsKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts +18 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.js +8 -0
- package/dist/dashboard/widgets/PortfolioEffortKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts +22 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.js +56 -0
- package/dist/dashboard/widgets/PortfolioProjectsKpi.js.map +1 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts +19 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.js +11 -0
- package/dist/dashboard/widgets/PortfolioRiskKpi.js.map +1 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.d.ts +19 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.d.ts.map +1 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.js +18 -0
- package/dist/dashboard/widgets/ProjectStatusOverview.js.map +1 -0
- package/dist/dashboard/widgets/StrategicDeadlines.d.ts +24 -0
- package/dist/dashboard/widgets/StrategicDeadlines.d.ts.map +1 -0
- package/dist/dashboard/widgets/StrategicDeadlines.js +22 -0
- package/dist/dashboard/widgets/StrategicDeadlines.js.map +1 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.d.ts +24 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.js +12 -0
- package/dist/dashboard/widgets/TeamApprovalQueue.js.map +1 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.d.ts +18 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.js +19 -0
- package/dist/dashboard/widgets/TeamCapacityKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts +22 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.js +56 -0
- package/dist/dashboard/widgets/TeamHeadcountKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamHoursKpi.d.ts +19 -0
- package/dist/dashboard/widgets/TeamHoursKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamHoursKpi.js +13 -0
- package/dist/dashboard/widgets/TeamHoursKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts +20 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js +11 -0
- package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js.map +1 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts +18 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.js +17 -0
- package/dist/dashboard/widgets/TeamUtilizationOverview.js.map +1 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts +24 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts.map +1 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.js +19 -0
- package/dist/dashboard/widgets/TeamWorkloadAlerts.js.map +1 -0
- package/dist/dashboard/widgets/index.d.ts +24 -0
- package/dist/dashboard/widgets/index.d.ts.map +1 -0
- package/dist/dashboard/widgets/index.js +54 -0
- package/dist/dashboard/widgets/index.js.map +1 -0
- package/dist/dto/create-collaborator.dto.d.ts +0 -1
- package/dist/dto/create-collaborator.dto.d.ts.map +1 -1
- package/dist/dto/create-collaborator.dto.js +0 -6
- package/dist/dto/create-collaborator.dto.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/operations.controller.d.ts +42 -0
- package/dist/operations.controller.d.ts.map +1 -1
- package/dist/operations.service.d.ts +178 -264
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +2170 -1340
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +345 -174
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/dashboard_component.yaml +66 -0
- package/hedhog/data/dashboard_component_role.yaml +8 -8
- package/hedhog/data/dashboard_item.yaml +25 -25
- package/hedhog/data/dashboard_role.yaml +1 -1
- package/hedhog/data/menu.yaml +6 -16
- package/hedhog/data/role.yaml +1 -1
- package/hedhog/data/route.yaml +116 -55
- package/hedhog/frontend/app/_components/async-options-combobox.tsx.ejs +15 -9
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +39 -99
- package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +314 -116
- package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +434 -449
- package/hedhog/frontend/app/_components/project-costs-section.tsx.ejs +51 -81
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +328 -423
- package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +446 -377
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
- package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +14 -9
- package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
- package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
- package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
- package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
- package/hedhog/frontend/app/_lib/api.ts.ejs +480 -476
- package/hedhog/frontend/app/_lib/hooks/use-values-visibility.ts.ejs +61 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +66 -5
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
- package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +43 -0
- package/hedhog/frontend/app/approvals/page.tsx.ejs +11 -2
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +127 -42
- package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
- package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
- package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
- package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
- package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
- package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
- package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
- package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
- package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
- package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
- package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
- package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
- package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
- package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
- package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
- package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
- package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
- package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
- package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/my-projects/page.tsx.ejs +59 -16
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +329 -106
- package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
- package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
- package/hedhog/frontend/app/projects/page.tsx.ejs +436 -35
- package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +65 -52
- package/hedhog/frontend/app/reports/projects/page.tsx.ejs +80 -82
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +13 -2
- package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
- package/hedhog/frontend/messages/en.json +460 -61
- package/hedhog/frontend/messages/operations/en.json +61 -52
- package/hedhog/frontend/messages/operations/pt.json +59 -43
- package/hedhog/frontend/messages/pt.json +460 -61
- package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/index.ts.ejs +25 -0
- package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
- package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
- package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
- package/hedhog/table/operations_collaborator.yaml +8 -13
- package/hedhog/table/operations_project.yaml +1 -1
- package/hedhog/table/operations_project_file.yaml +23 -0
- package/hedhog/table/operations_task.yaml +76 -69
- package/hedhog/table/operations_task_activity.yaml +51 -0
- package/package.json +7 -6
- package/src/controllers/operations-projects.controller.ts +41 -8
- package/src/controllers/operations-tasks.controller.ts +156 -166
- package/src/dashboard/README.md +214 -0
- package/src/dashboard/components/DashboardLayout.tsx +131 -0
- package/src/dashboard/components/widget-registry.ts +255 -0
- package/src/dashboard/hooks/useDashboardData.ts +29 -0
- package/src/dashboard/types/widgets.types.ts +237 -0
- package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
- package/src/dashboard/widgets/EffortByProject.tsx +51 -0
- package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
- package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
- package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
- package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
- package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
- package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
- package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
- package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
- package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
- package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
- package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
- package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
- package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
- package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
- package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
- package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
- package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
- package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
- package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
- package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
- package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
- package/src/dashboard/widgets/index.ts +26 -0
- package/src/dto/create-collaborator.dto.ts +4 -11
- package/src/index.ts +3 -0
- package/src/operations.service.spec.ts +988 -764
- package/src/operations.service.ts +4300 -2538
|
@@ -6,52 +6,55 @@ import {
|
|
|
6
6
|
PaginationFooter,
|
|
7
7
|
SearchBar,
|
|
8
8
|
} from '@/components/entity-list';
|
|
9
|
-
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
10
9
|
import { Button } from '@/components/ui/button';
|
|
11
10
|
import { Card, CardContent } from '@/components/ui/card';
|
|
12
|
-
import {
|
|
13
|
-
Dialog,
|
|
14
|
-
DialogContent,
|
|
11
|
+
import {
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogDescription,
|
|
15
15
|
DialogFooter,
|
|
16
16
|
DialogHeader,
|
|
17
|
-
DialogTitle,
|
|
18
|
-
} from '@/components/ui/dialog';
|
|
19
|
-
import { Input } from '@/components/ui/input';
|
|
20
|
-
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
21
|
-
import { Label } from '@/components/ui/label';
|
|
22
|
-
import { Progress } from '@/components/ui/progress';
|
|
23
|
-
import {
|
|
24
|
-
Select,
|
|
25
|
-
SelectContent,
|
|
26
|
-
SelectItem,
|
|
27
|
-
SelectTrigger,
|
|
28
|
-
SelectValue,
|
|
29
|
-
} from '@/components/ui/select';
|
|
30
|
-
import {
|
|
31
|
-
Sheet,
|
|
32
|
-
SheetContent,
|
|
33
|
-
SheetHeader,
|
|
34
|
-
SheetTitle,
|
|
35
|
-
} from '@/components/ui/sheet';
|
|
36
|
-
import {
|
|
37
|
-
Table,
|
|
38
|
-
TableBody,
|
|
39
|
-
TableCell,
|
|
17
|
+
DialogTitle,
|
|
18
|
+
} from '@/components/ui/dialog';
|
|
19
|
+
import { Input } from '@/components/ui/input';
|
|
20
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
21
|
+
import { Label } from '@/components/ui/label';
|
|
22
|
+
import { Progress } from '@/components/ui/progress';
|
|
23
|
+
import {
|
|
24
|
+
Select,
|
|
25
|
+
SelectContent,
|
|
26
|
+
SelectItem,
|
|
27
|
+
SelectTrigger,
|
|
28
|
+
SelectValue,
|
|
29
|
+
} from '@/components/ui/select';
|
|
30
|
+
import {
|
|
31
|
+
Sheet,
|
|
32
|
+
SheetContent,
|
|
33
|
+
SheetHeader,
|
|
34
|
+
SheetTitle,
|
|
35
|
+
} from '@/components/ui/sheet';
|
|
36
|
+
import {
|
|
37
|
+
Table,
|
|
38
|
+
TableBody,
|
|
39
|
+
TableCell,
|
|
40
40
|
TableHead,
|
|
41
41
|
TableHeader,
|
|
42
|
-
TableRow,
|
|
43
|
-
} from '@/components/ui/table';
|
|
44
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
45
|
-
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
|
42
|
+
TableRow,
|
|
43
|
+
} from '@/components/ui/table';
|
|
44
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
45
|
+
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
|
46
|
+
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
46
47
|
import {
|
|
47
48
|
closestCenter,
|
|
48
49
|
DndContext,
|
|
50
|
+
DragOverlay,
|
|
49
51
|
PointerSensor,
|
|
50
52
|
useDraggable,
|
|
51
53
|
useDroppable,
|
|
52
54
|
useSensor,
|
|
53
55
|
useSensors,
|
|
54
56
|
type DragEndEvent,
|
|
57
|
+
type DragStartEvent,
|
|
55
58
|
type UniqueIdentifier,
|
|
56
59
|
} from '@dnd-kit/core';
|
|
57
60
|
import { CSS } from '@dnd-kit/utilities';
|
|
@@ -73,6 +76,7 @@ import {
|
|
|
73
76
|
Pencil,
|
|
74
77
|
PlayCircle,
|
|
75
78
|
Plus,
|
|
79
|
+
Send,
|
|
76
80
|
Timer,
|
|
77
81
|
Trash2,
|
|
78
82
|
} from 'lucide-react';
|
|
@@ -81,15 +85,18 @@ import Link from 'next/link';
|
|
|
81
85
|
import { useCallback, useMemo, useState } from 'react';
|
|
82
86
|
import { OperationsHeader } from '../_components/operations-header';
|
|
83
87
|
import { StatusBadge } from '../_components/status-badge';
|
|
84
|
-
import {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
type TaskDetailSheetData,
|
|
88
|
-
} from '../_components/task-detail-sheet';
|
|
89
|
-
import { TaskFileAttachments } from '../_components/task-file-attachments';
|
|
90
|
-
import {
|
|
91
|
-
import {
|
|
88
|
+
import {
|
|
89
|
+
TaskDetailSheet,
|
|
90
|
+
TaskCommentsSection,
|
|
91
|
+
type TaskDetailSheetData,
|
|
92
|
+
} from '../_components/task-detail-sheet';
|
|
93
|
+
import { TaskFileAttachments } from '../_components/task-file-attachments';
|
|
94
|
+
import { TimesheetEntryCreateSheet } from '../_components/timesheet-entry-create-sheet';
|
|
95
|
+
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
96
|
+
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
97
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
92
98
|
import type {
|
|
99
|
+
OperationsCollaborator,
|
|
93
100
|
OperationsProjectOption,
|
|
94
101
|
OperationsTaskOption,
|
|
95
102
|
PaginatedResponse,
|
|
@@ -114,11 +121,20 @@ type TaskFormState = {
|
|
|
114
121
|
description: string;
|
|
115
122
|
priority: 'low' | 'medium' | 'high';
|
|
116
123
|
status: BoardColumnId;
|
|
124
|
+
assigneeCollaboratorId: string;
|
|
117
125
|
dueDate: string;
|
|
118
126
|
estimateHours: string;
|
|
119
127
|
tags: string;
|
|
120
128
|
};
|
|
121
129
|
|
|
130
|
+
type TimesheetEntryPrefill = {
|
|
131
|
+
projectId: number;
|
|
132
|
+
projectAssignmentId?: number | null;
|
|
133
|
+
projectLabel: string;
|
|
134
|
+
taskId: number;
|
|
135
|
+
taskLabel: string;
|
|
136
|
+
};
|
|
137
|
+
|
|
122
138
|
const KANBAN_COLUMNS: Array<{ id: BoardColumnId; label: string }> = [
|
|
123
139
|
{ id: 'todo', label: 'Backlog' },
|
|
124
140
|
{ id: 'doing', label: 'Em execução' },
|
|
@@ -132,6 +148,7 @@ const EMPTY_TASK_FORM: TaskFormState = {
|
|
|
132
148
|
description: '',
|
|
133
149
|
priority: 'medium',
|
|
134
150
|
status: 'todo',
|
|
151
|
+
assigneeCollaboratorId: 'none',
|
|
135
152
|
dueDate: '',
|
|
136
153
|
estimateHours: '',
|
|
137
154
|
tags: '',
|
|
@@ -151,17 +168,25 @@ function parseTaskId(value: UniqueIdentifier | null | undefined) {
|
|
|
151
168
|
return match ? Number(match[1]) : null;
|
|
152
169
|
}
|
|
153
170
|
|
|
154
|
-
function parseColumnId(
|
|
155
|
-
value: UniqueIdentifier | null | undefined
|
|
156
|
-
): BoardColumnId | null {
|
|
157
|
-
if (!value) return null;
|
|
158
|
-
const match = String(value).match(/^col-(.+)$/);
|
|
159
|
-
const id = match?.[1];
|
|
160
|
-
return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function
|
|
164
|
-
return
|
|
171
|
+
function parseColumnId(
|
|
172
|
+
value: UniqueIdentifier | null | undefined
|
|
173
|
+
): BoardColumnId | null {
|
|
174
|
+
if (!value) return null;
|
|
175
|
+
const match = String(value).match(/^col-(.+)$/);
|
|
176
|
+
const id = match?.[1];
|
|
177
|
+
return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function normalizeDateInputValue(value?: string | null) {
|
|
181
|
+
if (!value) return '';
|
|
182
|
+
const match = String(value)
|
|
183
|
+
.trim()
|
|
184
|
+
.match(/^\d{4}-\d{2}-\d{2}/);
|
|
185
|
+
return match?.[0] ?? '';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
|
|
189
|
+
return {
|
|
165
190
|
todo: tasks.filter((t) => t.status === 'todo'),
|
|
166
191
|
doing: tasks.filter((t) => t.status === 'doing'),
|
|
167
192
|
review: tasks.filter((t) => t.status === 'review'),
|
|
@@ -169,6 +194,30 @@ function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
|
|
|
169
194
|
};
|
|
170
195
|
}
|
|
171
196
|
|
|
197
|
+
function getTaskColumnId(status?: string | null): BoardColumnId {
|
|
198
|
+
return KANBAN_COLUMNS.some((column) => column.id === status)
|
|
199
|
+
? (status as BoardColumnId)
|
|
200
|
+
: 'todo';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function replaceTaskInColumns(
|
|
204
|
+
columns: BoardColumns,
|
|
205
|
+
task: OperationsTaskOption
|
|
206
|
+
): BoardColumns {
|
|
207
|
+
const targetColumn = getTaskColumnId(task.status);
|
|
208
|
+
const nextColumns = {
|
|
209
|
+
todo: columns.todo.filter((item) => item.id !== task.id),
|
|
210
|
+
doing: columns.doing.filter((item) => item.id !== task.id),
|
|
211
|
+
review: columns.review.filter((item) => item.id !== task.id),
|
|
212
|
+
done: columns.done.filter((item) => item.id !== task.id),
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
...nextColumns,
|
|
217
|
+
[targetColumn]: [task, ...nextColumns[targetColumn]],
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
172
221
|
function getTaskPriorityLabel(value?: string | null) {
|
|
173
222
|
const labels: Record<string, string> = {
|
|
174
223
|
low: 'Baixa',
|
|
@@ -242,26 +291,6 @@ function getUserPhotoUrl(photoId?: number | null) {
|
|
|
242
291
|
: null;
|
|
243
292
|
}
|
|
244
293
|
|
|
245
|
-
function normalizeDateInputValue(value?: string | null) {
|
|
246
|
-
if (!value) {
|
|
247
|
-
return '';
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const normalizedValue = String(value).trim();
|
|
251
|
-
const directMatch = normalizedValue.match(/^\d{4}-\d{2}-\d{2}/);
|
|
252
|
-
|
|
253
|
-
if (directMatch?.[0]) {
|
|
254
|
-
return directMatch[0];
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const parsedDate = new Date(normalizedValue);
|
|
258
|
-
if (Number.isNaN(parsedDate.getTime())) {
|
|
259
|
-
return '';
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return parsedDate.toISOString().slice(0, 10);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
294
|
function DraggableTaskCard({
|
|
266
295
|
task,
|
|
267
296
|
children,
|
|
@@ -276,10 +305,12 @@ function DraggableTaskCard({
|
|
|
276
305
|
return (
|
|
277
306
|
<div
|
|
278
307
|
ref={setNodeRef}
|
|
279
|
-
style={{
|
|
308
|
+
style={{
|
|
309
|
+
transform: CSS.Translate.toString(transform),
|
|
310
|
+
...(isDragging ? { opacity: 0, pointerEvents: 'none' } : {}),
|
|
311
|
+
}}
|
|
280
312
|
{...listeners}
|
|
281
313
|
{...attributes}
|
|
282
|
-
className={isDragging ? 'z-20' : undefined}
|
|
283
314
|
>
|
|
284
315
|
{children(isDragging)}
|
|
285
316
|
</div>
|
|
@@ -303,13 +334,17 @@ export default function OperationsMyTasksPage() {
|
|
|
303
334
|
const t = useTranslations('operations.MyTasksPage');
|
|
304
335
|
const commonT = useTranslations('operations.Common');
|
|
305
336
|
const detailT = useTranslations('operations.ProjectDetailsPage');
|
|
306
|
-
|
|
307
|
-
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
308
|
-
const mentionItems = useMentionItems(request);
|
|
309
|
-
const [search, setSearch] = useState('');
|
|
337
|
+
|
|
338
|
+
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
339
|
+
const mentionItems = useMentionItems(request);
|
|
340
|
+
const [search, setSearch] = useState('');
|
|
310
341
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
311
342
|
const [page, setPage] = useState(1);
|
|
312
|
-
const [pageSize, setPageSize] =
|
|
343
|
+
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
344
|
+
storageKey: 'pagination:operations-my-tasks:pageSize',
|
|
345
|
+
defaultValue: 20,
|
|
346
|
+
allowedValues: [10, 20, 50],
|
|
347
|
+
});
|
|
313
348
|
const [taskCollection, setTaskCollection] =
|
|
314
349
|
useState<TaskCollection>('active');
|
|
315
350
|
const [viewMode, setViewMode] = useState<TaskViewMode>(() => {
|
|
@@ -331,11 +366,17 @@ export default function OperationsMyTasksPage() {
|
|
|
331
366
|
const [deletePromptTask, setDeletePromptTask] =
|
|
332
367
|
useState<OperationsTaskOption | null>(null);
|
|
333
368
|
const [taskFormOpen, setTaskFormOpen] = useState(false);
|
|
334
|
-
const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
|
|
335
|
-
const [
|
|
336
|
-
const [
|
|
337
|
-
const [taskFormData, setTaskFormData] =
|
|
338
|
-
useState<TaskFormState>(EMPTY_TASK_FORM);
|
|
369
|
+
const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
|
|
370
|
+
const [archivingTaskId, setArchivingTaskId] = useState<number | null>(null);
|
|
371
|
+
const [taskFormLoading, setTaskFormLoading] = useState(false);
|
|
372
|
+
const [taskFormData, setTaskFormData] =
|
|
373
|
+
useState<TaskFormState>(EMPTY_TASK_FORM);
|
|
374
|
+
const [activeDragTask, setActiveDragTask] =
|
|
375
|
+
useState<OperationsTaskOption | null>(null);
|
|
376
|
+
const [isTimesheetEntrySheetOpen, setIsTimesheetEntrySheetOpen] =
|
|
377
|
+
useState(false);
|
|
378
|
+
const [timesheetPrefill, setTimesheetPrefill] =
|
|
379
|
+
useState<TimesheetEntryPrefill | null>(null);
|
|
339
380
|
const [inlineCreateColumn, setInlineCreateColumn] =
|
|
340
381
|
useState<BoardColumnId | null>(null);
|
|
341
382
|
const [inlineCreateName, setInlineCreateName] = useState('');
|
|
@@ -396,16 +437,57 @@ export default function OperationsMyTasksPage() {
|
|
|
396
437
|
),
|
|
397
438
|
placeholderData: (previous) => previous,
|
|
398
439
|
});
|
|
440
|
+
const { data: collaboratorsResponse } = useQuery<
|
|
441
|
+
PaginatedResponse<OperationsCollaborator>
|
|
442
|
+
>({
|
|
443
|
+
queryKey: ['operations-my-task-collaborator-options', currentLocaleCode],
|
|
444
|
+
queryFn: () =>
|
|
445
|
+
fetchOperations<PaginatedResponse<OperationsCollaborator>>(
|
|
446
|
+
request,
|
|
447
|
+
'/operations/collaborators?pageSize=200&sortField=displayName&sortOrder=asc'
|
|
448
|
+
),
|
|
449
|
+
placeholderData: (previous) => previous,
|
|
450
|
+
});
|
|
399
451
|
|
|
400
452
|
const tasks = tasksResponse?.data ?? [];
|
|
401
453
|
const boardApiTasks = boardTasksResponse?.data ?? [];
|
|
402
454
|
const projectOptions = projectOptionsResponse?.data ?? [];
|
|
455
|
+
const assigneeOptions = useMemo(() => {
|
|
456
|
+
const seen = new Set<number>();
|
|
457
|
+
return (collaboratorsResponse?.data ?? [])
|
|
458
|
+
.filter((collaborator) => {
|
|
459
|
+
if (!collaborator.id || seen.has(collaborator.id)) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
seen.add(collaborator.id);
|
|
463
|
+
return true;
|
|
464
|
+
})
|
|
465
|
+
.map((collaborator) => ({
|
|
466
|
+
id: String(collaborator.id),
|
|
467
|
+
label:
|
|
468
|
+
collaborator.displayName ||
|
|
469
|
+
collaborator.personName ||
|
|
470
|
+
collaborator.code,
|
|
471
|
+
}));
|
|
472
|
+
}, [collaboratorsResponse]);
|
|
403
473
|
|
|
404
474
|
const boardColumns: BoardColumns = useMemo(() => {
|
|
405
475
|
if (boardOverride) return boardOverride.columns;
|
|
406
476
|
return splitTasksByColumn(boardApiTasks);
|
|
407
477
|
}, [boardOverride, boardApiTasks]);
|
|
408
478
|
|
|
479
|
+
const editingTask = useMemo(() => {
|
|
480
|
+
if (!editingTaskId) return null;
|
|
481
|
+
return (
|
|
482
|
+
Object.values(boardColumns)
|
|
483
|
+
.flat()
|
|
484
|
+
.find((task) => task.id === editingTaskId) ??
|
|
485
|
+
boardApiTasks.find((task) => task.id === editingTaskId) ??
|
|
486
|
+
tasks.find((task) => task.id === editingTaskId) ??
|
|
487
|
+
null
|
|
488
|
+
);
|
|
489
|
+
}, [boardApiTasks, boardColumns, editingTaskId, tasks]);
|
|
490
|
+
|
|
409
491
|
const statsCards = useMemo(
|
|
410
492
|
() => [
|
|
411
493
|
{
|
|
@@ -494,23 +576,56 @@ export default function OperationsMyTasksPage() {
|
|
|
494
576
|
},
|
|
495
577
|
});
|
|
496
578
|
|
|
497
|
-
mutateOperations(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
579
|
+
mutateOperations<OperationsTaskOption>(
|
|
580
|
+
request,
|
|
581
|
+
`/operations/tasks/${taskId}`,
|
|
582
|
+
'PATCH',
|
|
583
|
+
{
|
|
584
|
+
status: targetColumn,
|
|
585
|
+
}
|
|
586
|
+
)
|
|
587
|
+
.then((updatedTask) => {
|
|
588
|
+
if (!updatedTask) {
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
setBoardOverride((current) => ({
|
|
593
|
+
columns: replaceTaskInColumns(current?.columns ?? boardColumns, {
|
|
594
|
+
...sourceTask,
|
|
595
|
+
...updatedTask,
|
|
596
|
+
}),
|
|
597
|
+
}));
|
|
598
|
+
})
|
|
599
|
+
.catch(() => {
|
|
600
|
+
setBoardOverride(null);
|
|
601
|
+
void refetchBoard();
|
|
602
|
+
});
|
|
503
603
|
},
|
|
504
604
|
[boardColumns, findColumnByTask, request, refetchBoard]
|
|
505
605
|
);
|
|
506
606
|
|
|
507
607
|
const onBoardDragEnd = (event: DragEndEvent) => {
|
|
608
|
+
setActiveDragTask(null);
|
|
508
609
|
const taskId = parseTaskId(event.active.id);
|
|
509
610
|
const targetColumn = parseColumnId(event.over?.id);
|
|
510
611
|
if (!taskId || !targetColumn) return;
|
|
511
612
|
moveTaskToColumn(taskId, targetColumn);
|
|
512
613
|
};
|
|
513
614
|
|
|
615
|
+
const onBoardDragStart = (event: DragStartEvent) => {
|
|
616
|
+
const taskId = parseTaskId(event.active.id);
|
|
617
|
+
if (!taskId) {
|
|
618
|
+
setActiveDragTask(null);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const task = KANBAN_COLUMNS.map((column) => boardColumns[column.id])
|
|
623
|
+
.find((items) => items.some((item) => item.id === taskId))
|
|
624
|
+
?.find((item) => item.id === taskId);
|
|
625
|
+
|
|
626
|
+
setActiveDragTask(task ?? null);
|
|
627
|
+
};
|
|
628
|
+
|
|
514
629
|
const refetchAll = useCallback(async () => {
|
|
515
630
|
await Promise.all([refetch(), refetchBoard()]);
|
|
516
631
|
}, [refetch, refetchBoard]);
|
|
@@ -592,7 +707,6 @@ export default function OperationsMyTasksPage() {
|
|
|
592
707
|
|
|
593
708
|
const openCreateTaskForm = useCallback(() => {
|
|
594
709
|
setEditingTaskId(null);
|
|
595
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
596
710
|
setSelectedTask(null);
|
|
597
711
|
setTaskFormOpen(true);
|
|
598
712
|
}, []);
|
|
@@ -607,6 +721,9 @@ export default function OperationsMyTasksPage() {
|
|
|
607
721
|
status: KANBAN_COLUMNS.some((column) => column.id === task.status)
|
|
608
722
|
? (task.status as BoardColumnId)
|
|
609
723
|
: 'todo',
|
|
724
|
+
assigneeCollaboratorId: task.assigneeCollaboratorId
|
|
725
|
+
? String(task.assigneeCollaboratorId)
|
|
726
|
+
: 'none',
|
|
610
727
|
dueDate: normalizeDateInputValue(task.dueDate),
|
|
611
728
|
estimateHours:
|
|
612
729
|
task.estimateHours != null ? String(task.estimateHours) : '',
|
|
@@ -628,6 +745,10 @@ export default function OperationsMyTasksPage() {
|
|
|
628
745
|
const payload = {
|
|
629
746
|
projectId: selectedProject.id,
|
|
630
747
|
projectAssignmentId: selectedProject.projectAssignmentId ?? null,
|
|
748
|
+
assigneeCollaboratorId:
|
|
749
|
+
taskFormData.assigneeCollaboratorId !== 'none'
|
|
750
|
+
? Number(taskFormData.assigneeCollaboratorId)
|
|
751
|
+
: null,
|
|
631
752
|
name: normalizedName,
|
|
632
753
|
description: taskFormData.description.trim() || null,
|
|
633
754
|
priority: taskFormData.priority,
|
|
@@ -661,6 +782,29 @@ export default function OperationsMyTasksPage() {
|
|
|
661
782
|
}
|
|
662
783
|
}, [editingTaskId, projectOptions, request, refetchAll, taskFormData]);
|
|
663
784
|
|
|
785
|
+
const openTimesheetEntrySheet = useCallback(
|
|
786
|
+
(task: TaskDetailSheetData) => {
|
|
787
|
+
if (!task.projectId) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const projectLabel = [task.projectName, task.projectCode]
|
|
792
|
+
.filter(Boolean)
|
|
793
|
+
.join(' • ');
|
|
794
|
+
|
|
795
|
+
setTimesheetPrefill({
|
|
796
|
+
projectId: task.projectId,
|
|
797
|
+
projectAssignmentId: task.projectAssignmentId ?? null,
|
|
798
|
+
projectLabel: projectLabel || commonT('labels.notAssigned'),
|
|
799
|
+
taskId: task.id,
|
|
800
|
+
taskLabel: task.name,
|
|
801
|
+
});
|
|
802
|
+
setSelectedTask(null);
|
|
803
|
+
setIsTimesheetEntrySheetOpen(true);
|
|
804
|
+
},
|
|
805
|
+
[commonT]
|
|
806
|
+
);
|
|
807
|
+
|
|
664
808
|
return (
|
|
665
809
|
<Page>
|
|
666
810
|
<OperationsHeader
|
|
@@ -779,6 +923,8 @@ export default function OperationsMyTasksPage() {
|
|
|
779
923
|
<DndContext
|
|
780
924
|
sensors={sensors}
|
|
781
925
|
collisionDetection={closestCenter}
|
|
926
|
+
onDragStart={onBoardDragStart}
|
|
927
|
+
onDragCancel={() => setActiveDragTask(null)}
|
|
782
928
|
onDragEnd={onBoardDragEnd}
|
|
783
929
|
>
|
|
784
930
|
<div className="grid gap-4 xl:grid-cols-4">
|
|
@@ -787,7 +933,7 @@ export default function OperationsMyTasksPage() {
|
|
|
787
933
|
{(isOver) => (
|
|
788
934
|
<div
|
|
789
935
|
className={[
|
|
790
|
-
'flex min-h-
|
|
936
|
+
'flex min-h-128 flex-col overflow-hidden rounded-3xl border bg-linear-to-b p-3 transition-all',
|
|
791
937
|
getColumnClassName(column.id),
|
|
792
938
|
isOver
|
|
793
939
|
? 'border-primary shadow-lg ring-2 ring-primary/15'
|
|
@@ -945,7 +1091,7 @@ export default function OperationsMyTasksPage() {
|
|
|
945
1091
|
|
|
946
1092
|
<div className="mt-3 space-y-1.5">
|
|
947
1093
|
<div className="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
948
|
-
<span>
|
|
1094
|
+
<span>{t('labels.progress')}</span>
|
|
949
1095
|
<span>
|
|
950
1096
|
{getTaskProgress(task.status)}%
|
|
951
1097
|
</span>
|
|
@@ -1080,6 +1226,19 @@ export default function OperationsMyTasksPage() {
|
|
|
1080
1226
|
</DroppableColumn>
|
|
1081
1227
|
))}
|
|
1082
1228
|
</div>
|
|
1229
|
+
<DragOverlay zIndex={1200}>
|
|
1230
|
+
{activeDragTask ? (
|
|
1231
|
+
<div className="w-76 cursor-grabbing rounded-2xl border border-primary/60 bg-card p-3 text-left shadow-2xl ring-2 ring-primary/20 opacity-95">
|
|
1232
|
+
<p className="line-clamp-2 text-sm font-semibold leading-snug">
|
|
1233
|
+
{activeDragTask.name}
|
|
1234
|
+
</p>
|
|
1235
|
+
<p className="mt-1 truncate text-xs text-muted-foreground">
|
|
1236
|
+
{activeDragTask.assigneeName ||
|
|
1237
|
+
commonT('labels.notAssigned')}
|
|
1238
|
+
</p>
|
|
1239
|
+
</div>
|
|
1240
|
+
) : null}
|
|
1241
|
+
</DragOverlay>
|
|
1083
1242
|
</DndContext>
|
|
1084
1243
|
) : (
|
|
1085
1244
|
<EmptyState
|
|
@@ -1248,12 +1407,12 @@ export default function OperationsMyTasksPage() {
|
|
|
1248
1407
|
}}
|
|
1249
1408
|
footer={
|
|
1250
1409
|
selectedTask ? (
|
|
1251
|
-
<div className="grid grid-cols-
|
|
1410
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
1252
1411
|
{taskCollection === 'archived' ? (
|
|
1253
1412
|
<>
|
|
1254
1413
|
<Button
|
|
1255
1414
|
variant="outline"
|
|
1256
|
-
className="gap-2"
|
|
1415
|
+
className="gap-2 sm:col-span-2"
|
|
1257
1416
|
onClick={() => void handleRestoreTask(selectedTask.id)}
|
|
1258
1417
|
>
|
|
1259
1418
|
<ArchiveRestore className="size-4" />
|
|
@@ -1272,6 +1431,15 @@ export default function OperationsMyTasksPage() {
|
|
|
1272
1431
|
</>
|
|
1273
1432
|
) : (
|
|
1274
1433
|
<>
|
|
1434
|
+
<Button
|
|
1435
|
+
variant="outline"
|
|
1436
|
+
className="gap-2"
|
|
1437
|
+
disabled={!selectedTask.projectId}
|
|
1438
|
+
onClick={() => openTimesheetEntrySheet(selectedTask)}
|
|
1439
|
+
>
|
|
1440
|
+
<Send className="size-4" />
|
|
1441
|
+
{commonT('actions.logHours')}
|
|
1442
|
+
</Button>
|
|
1275
1443
|
<Button
|
|
1276
1444
|
variant="outline"
|
|
1277
1445
|
className="gap-2"
|
|
@@ -1297,6 +1465,36 @@ export default function OperationsMyTasksPage() {
|
|
|
1297
1465
|
}
|
|
1298
1466
|
/>
|
|
1299
1467
|
|
|
1468
|
+
<TimesheetEntryCreateSheet
|
|
1469
|
+
open={isTimesheetEntrySheetOpen}
|
|
1470
|
+
onOpenChange={(open) => {
|
|
1471
|
+
setIsTimesheetEntrySheetOpen(open);
|
|
1472
|
+
if (!open) {
|
|
1473
|
+
setTimesheetPrefill(null);
|
|
1474
|
+
}
|
|
1475
|
+
}}
|
|
1476
|
+
project={
|
|
1477
|
+
timesheetPrefill
|
|
1478
|
+
? {
|
|
1479
|
+
id: timesheetPrefill.projectId,
|
|
1480
|
+
label: timesheetPrefill.projectLabel,
|
|
1481
|
+
projectAssignmentId: timesheetPrefill.projectAssignmentId,
|
|
1482
|
+
}
|
|
1483
|
+
: null
|
|
1484
|
+
}
|
|
1485
|
+
task={
|
|
1486
|
+
timesheetPrefill
|
|
1487
|
+
? {
|
|
1488
|
+
id: timesheetPrefill.taskId,
|
|
1489
|
+
label: timesheetPrefill.taskLabel,
|
|
1490
|
+
}
|
|
1491
|
+
: null
|
|
1492
|
+
}
|
|
1493
|
+
onCreated={() => {
|
|
1494
|
+
void refetchAll();
|
|
1495
|
+
}}
|
|
1496
|
+
/>
|
|
1497
|
+
|
|
1300
1498
|
<Dialog
|
|
1301
1499
|
open={deletePromptTask !== null}
|
|
1302
1500
|
onOpenChange={(open) => {
|
|
@@ -1306,10 +1504,10 @@ export default function OperationsMyTasksPage() {
|
|
|
1306
1504
|
<DialogContent className="sm:max-w-sm">
|
|
1307
1505
|
<DialogHeader>
|
|
1308
1506
|
<DialogTitle>{t('dialogs.deleteTitle')}</DialogTitle>
|
|
1507
|
+
<DialogDescription>
|
|
1508
|
+
{t('dialogs.deleteDescription')}
|
|
1509
|
+
</DialogDescription>
|
|
1309
1510
|
</DialogHeader>
|
|
1310
|
-
<p className="text-sm text-muted-foreground">
|
|
1311
|
-
{t('dialogs.deleteDescription')}
|
|
1312
|
-
</p>
|
|
1313
1511
|
<DialogFooter className="mt-4">
|
|
1314
1512
|
<Button variant="outline" onClick={() => setDeletePromptTask(null)}>
|
|
1315
1513
|
{commonT('actions.cancel')}
|
|
@@ -1328,16 +1526,12 @@ export default function OperationsMyTasksPage() {
|
|
|
1328
1526
|
</DialogContent>
|
|
1329
1527
|
</Dialog>
|
|
1330
1528
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
setEditingTaskId(null);
|
|
1338
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1529
|
+
|
|
1530
|
+
<Sheet
|
|
1531
|
+
open={taskFormOpen}
|
|
1532
|
+
onOpenChange={(open) => {
|
|
1533
|
+
setTaskFormOpen(open);
|
|
1534
|
+
if (!open) setEditingTaskId(null);
|
|
1341
1535
|
}}
|
|
1342
1536
|
>
|
|
1343
1537
|
<SheetContent className="flex w-full flex-col overflow-hidden sm:max-w-xl">
|
|
@@ -1481,6 +1675,35 @@ export default function OperationsMyTasksPage() {
|
|
|
1481
1675
|
</div>
|
|
1482
1676
|
</div>
|
|
1483
1677
|
|
|
1678
|
+
<div className="space-y-2">
|
|
1679
|
+
<Label>{commonT('responsible')}</Label>
|
|
1680
|
+
<Select
|
|
1681
|
+
value={taskFormData.assigneeCollaboratorId}
|
|
1682
|
+
onValueChange={(value) =>
|
|
1683
|
+
setTaskFormData((prev) => ({
|
|
1684
|
+
...prev,
|
|
1685
|
+
assigneeCollaboratorId: value,
|
|
1686
|
+
}))
|
|
1687
|
+
}
|
|
1688
|
+
>
|
|
1689
|
+
<SelectTrigger className="w-full">
|
|
1690
|
+
<SelectValue
|
|
1691
|
+
placeholder={commonT('labels.notAssigned')}
|
|
1692
|
+
/>
|
|
1693
|
+
</SelectTrigger>
|
|
1694
|
+
<SelectContent>
|
|
1695
|
+
<SelectItem value="none">
|
|
1696
|
+
{commonT('labels.notAssigned')}
|
|
1697
|
+
</SelectItem>
|
|
1698
|
+
{assigneeOptions.map((option) => (
|
|
1699
|
+
<SelectItem key={option.id} value={option.id}>
|
|
1700
|
+
{option.label}
|
|
1701
|
+
</SelectItem>
|
|
1702
|
+
))}
|
|
1703
|
+
</SelectContent>
|
|
1704
|
+
</Select>
|
|
1705
|
+
</div>
|
|
1706
|
+
|
|
1484
1707
|
<div className="grid grid-cols-2 gap-3">
|
|
1485
1708
|
<div className="space-y-2">
|
|
1486
1709
|
<Label htmlFor="task-due-date">
|