@hed-hog/operations 0.0.330 → 0.0.332
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 +58 -213
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-collaborators.controller.js +100 -0
- package/dist/controllers/operations-collaborators.controller.js.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 +34 -9
- 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-invoice.dto.d.ts +11 -0
- package/dist/dto/create-collaborator-invoice.dto.d.ts.map +1 -0
- package/dist/dto/create-collaborator-invoice.dto.js +55 -0
- package/dist/dto/create-collaborator-invoice.dto.js.map +1 -0
- package/dist/dto/create-collaborator-payment.dto.d.ts +10 -0
- package/dist/dto/create-collaborator-payment.dto.d.ts.map +1 -0
- package/dist/dto/create-collaborator-payment.dto.js +50 -0
- package/dist/dto/create-collaborator-payment.dto.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/dto/list-collaborator-invoice.dto.d.ts +4 -0
- package/dist/dto/list-collaborator-invoice.dto.d.ts.map +1 -0
- package/dist/dto/list-collaborator-invoice.dto.js +8 -0
- package/dist/dto/list-collaborator-invoice.dto.js.map +1 -0
- package/dist/dto/list-collaborator-payment.dto.d.ts +4 -0
- package/dist/dto/list-collaborator-payment.dto.d.ts.map +1 -0
- package/dist/dto/list-collaborator-payment.dto.js +8 -0
- package/dist/dto/list-collaborator-payment.dto.js.map +1 -0
- package/dist/dto/update-collaborator-invoice.dto.d.ts +6 -0
- package/dist/dto/update-collaborator-invoice.dto.d.ts.map +1 -0
- package/dist/dto/update-collaborator-invoice.dto.js +9 -0
- package/dist/dto/update-collaborator-invoice.dto.js.map +1 -0
- package/dist/dto/update-collaborator-payment.dto.d.ts +6 -0
- package/dist/dto/update-collaborator-payment.dto.d.ts.map +1 -0
- package/dist/dto/update-collaborator-payment.dto.js +9 -0
- package/dist/dto/update-collaborator-payment.dto.js.map +1 -0
- 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 +258 -268
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +2381 -1341
- 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_item.yaml +25 -25
- package/hedhog/data/menu.yaml +27 -8
- package/hedhog/data/route.yaml +133 -0
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +78 -102
- package/hedhog/frontend/app/_components/collaborator-invoices-tab.tsx.ejs +443 -0
- package/hedhog/frontend/app/_components/collaborator-payment-history-tab.tsx.ejs +429 -0
- package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +247 -50
- package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +643 -450
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +992 -431
- package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +558 -386
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +383 -157
- package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +4 -1
- 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 +155 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +62 -0
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
- package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +61 -0
- package/hedhog/frontend/app/approvals/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +59 -8
- 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 +30 -12
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +286 -125
- 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 +415 -33
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +6 -1
- package/hedhog/frontend/app/tasks-gantt/page.tsx.ejs +953 -0
- 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 +332 -46
- package/hedhog/frontend/messages/operations/en.json +61 -52
- package/hedhog/frontend/messages/operations/pt.json +59 -43
- package/hedhog/frontend/messages/pt.json +332 -46
- 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_collaborator_invoice.yaml +35 -0
- package/hedhog/table/operations_collaborator_payment.yaml +32 -0
- 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 +6 -5
- package/src/controllers/operations-collaborators.controller.ts +117 -8
- 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-invoice.dto.ts +39 -0
- package/src/dto/create-collaborator-payment.dto.ts +35 -0
- package/src/dto/create-collaborator.dto.ts +4 -11
- package/src/dto/list-collaborator-invoice.dto.ts +3 -0
- package/src/dto/list-collaborator-payment.dto.ts +3 -0
- package/src/dto/update-collaborator-invoice.dto.ts +6 -0
- package/src/dto/update-collaborator-payment.dto.ts +6 -0
- package/src/index.ts +3 -0
- package/src/operations.service.spec.ts +988 -764
- package/src/operations.service.ts +4689 -2624
|
@@ -12,6 +12,7 @@ import { Card, CardContent } from '@/components/ui/card';
|
|
|
12
12
|
import {
|
|
13
13
|
Dialog,
|
|
14
14
|
DialogContent,
|
|
15
|
+
DialogDescription,
|
|
15
16
|
DialogFooter,
|
|
16
17
|
DialogHeader,
|
|
17
18
|
DialogTitle,
|
|
@@ -43,15 +44,18 @@ import {
|
|
|
43
44
|
} from '@/components/ui/table';
|
|
44
45
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
45
46
|
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
|
47
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
46
48
|
import {
|
|
47
49
|
closestCenter,
|
|
48
50
|
DndContext,
|
|
51
|
+
DragOverlay,
|
|
49
52
|
PointerSensor,
|
|
50
53
|
useDraggable,
|
|
51
54
|
useDroppable,
|
|
52
55
|
useSensor,
|
|
53
56
|
useSensors,
|
|
54
57
|
type DragEndEvent,
|
|
58
|
+
type DragStartEvent,
|
|
55
59
|
type UniqueIdentifier,
|
|
56
60
|
} from '@dnd-kit/core';
|
|
57
61
|
import { CSS } from '@dnd-kit/utilities';
|
|
@@ -73,6 +77,7 @@ import {
|
|
|
73
77
|
Pencil,
|
|
74
78
|
PlayCircle,
|
|
75
79
|
Plus,
|
|
80
|
+
Send,
|
|
76
81
|
Timer,
|
|
77
82
|
Trash2,
|
|
78
83
|
} from 'lucide-react';
|
|
@@ -87,14 +92,17 @@ import {
|
|
|
87
92
|
type TaskDetailSheetData,
|
|
88
93
|
} from '../_components/task-detail-sheet';
|
|
89
94
|
import { TaskFileAttachments } from '../_components/task-file-attachments';
|
|
95
|
+
import { TimesheetEntryCreateSheet } from '../_components/timesheet-entry-create-sheet';
|
|
90
96
|
import { fetchOperations, mutateOperations } from '../_lib/api';
|
|
91
97
|
import { useMentionItems } from '../_lib/hooks/use-mention-items';
|
|
92
98
|
import type {
|
|
99
|
+
OperationsCollaborator,
|
|
93
100
|
OperationsProjectOption,
|
|
94
101
|
OperationsTaskOption,
|
|
95
102
|
PaginatedResponse,
|
|
96
103
|
} from '../_lib/types';
|
|
97
104
|
import { formatDate, getStatusBadgeClass } from '../_lib/utils/format';
|
|
105
|
+
import { getTaskDescriptionPreview } from '../_lib/utils/task-ui';
|
|
98
106
|
|
|
99
107
|
type TaskViewMode = 'table' | 'cards' | 'board';
|
|
100
108
|
|
|
@@ -114,11 +122,20 @@ type TaskFormState = {
|
|
|
114
122
|
description: string;
|
|
115
123
|
priority: 'low' | 'medium' | 'high';
|
|
116
124
|
status: BoardColumnId;
|
|
125
|
+
assigneeCollaboratorId: string;
|
|
117
126
|
dueDate: string;
|
|
118
127
|
estimateHours: string;
|
|
119
128
|
tags: string;
|
|
120
129
|
};
|
|
121
130
|
|
|
131
|
+
type TimesheetEntryPrefill = {
|
|
132
|
+
projectId: number;
|
|
133
|
+
projectAssignmentId?: number | null;
|
|
134
|
+
projectLabel: string;
|
|
135
|
+
taskId: number;
|
|
136
|
+
taskLabel: string;
|
|
137
|
+
};
|
|
138
|
+
|
|
122
139
|
const KANBAN_COLUMNS: Array<{ id: BoardColumnId; label: string }> = [
|
|
123
140
|
{ id: 'todo', label: 'Backlog' },
|
|
124
141
|
{ id: 'doing', label: 'Em execução' },
|
|
@@ -132,6 +149,7 @@ const EMPTY_TASK_FORM: TaskFormState = {
|
|
|
132
149
|
description: '',
|
|
133
150
|
priority: 'medium',
|
|
134
151
|
status: 'todo',
|
|
152
|
+
assigneeCollaboratorId: 'none',
|
|
135
153
|
dueDate: '',
|
|
136
154
|
estimateHours: '',
|
|
137
155
|
tags: '',
|
|
@@ -160,6 +178,14 @@ function parseColumnId(
|
|
|
160
178
|
return KANBAN_COLUMNS.some((c) => c.id === id) ? (id as BoardColumnId) : null;
|
|
161
179
|
}
|
|
162
180
|
|
|
181
|
+
function normalizeDateInputValue(value?: string | null) {
|
|
182
|
+
if (!value) return '';
|
|
183
|
+
const match = String(value)
|
|
184
|
+
.trim()
|
|
185
|
+
.match(/^\d{4}-\d{2}-\d{2}/);
|
|
186
|
+
return match?.[0] ?? '';
|
|
187
|
+
}
|
|
188
|
+
|
|
163
189
|
function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
|
|
164
190
|
return {
|
|
165
191
|
todo: tasks.filter((t) => t.status === 'todo'),
|
|
@@ -169,6 +195,30 @@ function splitTasksByColumn(tasks: OperationsTaskOption[]): BoardColumns {
|
|
|
169
195
|
};
|
|
170
196
|
}
|
|
171
197
|
|
|
198
|
+
function getTaskColumnId(status?: string | null): BoardColumnId {
|
|
199
|
+
return KANBAN_COLUMNS.some((column) => column.id === status)
|
|
200
|
+
? (status as BoardColumnId)
|
|
201
|
+
: 'todo';
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function replaceTaskInColumns(
|
|
205
|
+
columns: BoardColumns,
|
|
206
|
+
task: OperationsTaskOption
|
|
207
|
+
): BoardColumns {
|
|
208
|
+
const targetColumn = getTaskColumnId(task.status);
|
|
209
|
+
const nextColumns = {
|
|
210
|
+
todo: columns.todo.filter((item) => item.id !== task.id),
|
|
211
|
+
doing: columns.doing.filter((item) => item.id !== task.id),
|
|
212
|
+
review: columns.review.filter((item) => item.id !== task.id),
|
|
213
|
+
done: columns.done.filter((item) => item.id !== task.id),
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
...nextColumns,
|
|
218
|
+
[targetColumn]: [task, ...nextColumns[targetColumn]],
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
172
222
|
function getTaskPriorityLabel(value?: string | null) {
|
|
173
223
|
const labels: Record<string, string> = {
|
|
174
224
|
low: 'Baixa',
|
|
@@ -242,26 +292,6 @@ function getUserPhotoUrl(photoId?: number | null) {
|
|
|
242
292
|
: null;
|
|
243
293
|
}
|
|
244
294
|
|
|
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
295
|
function DraggableTaskCard({
|
|
266
296
|
task,
|
|
267
297
|
children,
|
|
@@ -276,10 +306,12 @@ function DraggableTaskCard({
|
|
|
276
306
|
return (
|
|
277
307
|
<div
|
|
278
308
|
ref={setNodeRef}
|
|
279
|
-
style={{
|
|
309
|
+
style={{
|
|
310
|
+
transform: CSS.Translate.toString(transform),
|
|
311
|
+
...(isDragging ? { opacity: 0, pointerEvents: 'none' } : {}),
|
|
312
|
+
}}
|
|
280
313
|
{...listeners}
|
|
281
314
|
{...attributes}
|
|
282
|
-
className={isDragging ? 'z-20' : undefined}
|
|
283
315
|
>
|
|
284
316
|
{children(isDragging)}
|
|
285
317
|
</div>
|
|
@@ -309,7 +341,11 @@ export default function OperationsMyTasksPage() {
|
|
|
309
341
|
const [search, setSearch] = useState('');
|
|
310
342
|
const [statusFilter, setStatusFilter] = useState('all');
|
|
311
343
|
const [page, setPage] = useState(1);
|
|
312
|
-
const [pageSize, setPageSize] =
|
|
344
|
+
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
345
|
+
storageKey: 'pagination:operations-my-tasks:pageSize',
|
|
346
|
+
defaultValue: 20,
|
|
347
|
+
allowedValues: [10, 20, 50],
|
|
348
|
+
});
|
|
313
349
|
const [taskCollection, setTaskCollection] =
|
|
314
350
|
useState<TaskCollection>('active');
|
|
315
351
|
const [viewMode, setViewMode] = useState<TaskViewMode>(() => {
|
|
@@ -332,10 +368,16 @@ export default function OperationsMyTasksPage() {
|
|
|
332
368
|
useState<OperationsTaskOption | null>(null);
|
|
333
369
|
const [taskFormOpen, setTaskFormOpen] = useState(false);
|
|
334
370
|
const [editingTaskId, setEditingTaskId] = useState<number | null>(null);
|
|
335
|
-
const [taskFormLoading, setTaskFormLoading] = useState(false);
|
|
336
371
|
const [archivingTaskId, setArchivingTaskId] = useState<number | null>(null);
|
|
372
|
+
const [taskFormLoading, setTaskFormLoading] = useState(false);
|
|
337
373
|
const [taskFormData, setTaskFormData] =
|
|
338
374
|
useState<TaskFormState>(EMPTY_TASK_FORM);
|
|
375
|
+
const [activeDragTask, setActiveDragTask] =
|
|
376
|
+
useState<OperationsTaskOption | null>(null);
|
|
377
|
+
const [isTimesheetEntrySheetOpen, setIsTimesheetEntrySheetOpen] =
|
|
378
|
+
useState(false);
|
|
379
|
+
const [timesheetPrefill, setTimesheetPrefill] =
|
|
380
|
+
useState<TimesheetEntryPrefill | null>(null);
|
|
339
381
|
const [inlineCreateColumn, setInlineCreateColumn] =
|
|
340
382
|
useState<BoardColumnId | null>(null);
|
|
341
383
|
const [inlineCreateName, setInlineCreateName] = useState('');
|
|
@@ -396,16 +438,57 @@ export default function OperationsMyTasksPage() {
|
|
|
396
438
|
),
|
|
397
439
|
placeholderData: (previous) => previous,
|
|
398
440
|
});
|
|
441
|
+
const { data: collaboratorsResponse } = useQuery<
|
|
442
|
+
PaginatedResponse<OperationsCollaborator>
|
|
443
|
+
>({
|
|
444
|
+
queryKey: ['operations-my-task-collaborator-options', currentLocaleCode],
|
|
445
|
+
queryFn: () =>
|
|
446
|
+
fetchOperations<PaginatedResponse<OperationsCollaborator>>(
|
|
447
|
+
request,
|
|
448
|
+
'/operations/collaborators?pageSize=200&sortField=displayName&sortOrder=asc'
|
|
449
|
+
),
|
|
450
|
+
placeholderData: (previous) => previous,
|
|
451
|
+
});
|
|
399
452
|
|
|
400
453
|
const tasks = tasksResponse?.data ?? [];
|
|
401
454
|
const boardApiTasks = boardTasksResponse?.data ?? [];
|
|
402
455
|
const projectOptions = projectOptionsResponse?.data ?? [];
|
|
456
|
+
const assigneeOptions = useMemo(() => {
|
|
457
|
+
const seen = new Set<number>();
|
|
458
|
+
return (collaboratorsResponse?.data ?? [])
|
|
459
|
+
.filter((collaborator) => {
|
|
460
|
+
if (!collaborator.id || seen.has(collaborator.id)) {
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
seen.add(collaborator.id);
|
|
464
|
+
return true;
|
|
465
|
+
})
|
|
466
|
+
.map((collaborator) => ({
|
|
467
|
+
id: String(collaborator.id),
|
|
468
|
+
label:
|
|
469
|
+
collaborator.displayName ||
|
|
470
|
+
collaborator.personName ||
|
|
471
|
+
collaborator.code,
|
|
472
|
+
}));
|
|
473
|
+
}, [collaboratorsResponse]);
|
|
403
474
|
|
|
404
475
|
const boardColumns: BoardColumns = useMemo(() => {
|
|
405
476
|
if (boardOverride) return boardOverride.columns;
|
|
406
477
|
return splitTasksByColumn(boardApiTasks);
|
|
407
478
|
}, [boardOverride, boardApiTasks]);
|
|
408
479
|
|
|
480
|
+
const editingTask = useMemo(() => {
|
|
481
|
+
if (!editingTaskId) return null;
|
|
482
|
+
return (
|
|
483
|
+
Object.values(boardColumns)
|
|
484
|
+
.flat()
|
|
485
|
+
.find((task) => task.id === editingTaskId) ??
|
|
486
|
+
boardApiTasks.find((task) => task.id === editingTaskId) ??
|
|
487
|
+
tasks.find((task) => task.id === editingTaskId) ??
|
|
488
|
+
null
|
|
489
|
+
);
|
|
490
|
+
}, [boardApiTasks, boardColumns, editingTaskId, tasks]);
|
|
491
|
+
|
|
409
492
|
const statsCards = useMemo(
|
|
410
493
|
() => [
|
|
411
494
|
{
|
|
@@ -494,23 +577,56 @@ export default function OperationsMyTasksPage() {
|
|
|
494
577
|
},
|
|
495
578
|
});
|
|
496
579
|
|
|
497
|
-
mutateOperations(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
580
|
+
mutateOperations<OperationsTaskOption>(
|
|
581
|
+
request,
|
|
582
|
+
`/operations/tasks/${taskId}`,
|
|
583
|
+
'PATCH',
|
|
584
|
+
{
|
|
585
|
+
status: targetColumn,
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
.then((updatedTask) => {
|
|
589
|
+
if (!updatedTask) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
setBoardOverride((current) => ({
|
|
594
|
+
columns: replaceTaskInColumns(current?.columns ?? boardColumns, {
|
|
595
|
+
...sourceTask,
|
|
596
|
+
...updatedTask,
|
|
597
|
+
}),
|
|
598
|
+
}));
|
|
599
|
+
})
|
|
600
|
+
.catch(() => {
|
|
601
|
+
setBoardOverride(null);
|
|
602
|
+
void refetchBoard();
|
|
603
|
+
});
|
|
503
604
|
},
|
|
504
605
|
[boardColumns, findColumnByTask, request, refetchBoard]
|
|
505
606
|
);
|
|
506
607
|
|
|
507
608
|
const onBoardDragEnd = (event: DragEndEvent) => {
|
|
609
|
+
setActiveDragTask(null);
|
|
508
610
|
const taskId = parseTaskId(event.active.id);
|
|
509
611
|
const targetColumn = parseColumnId(event.over?.id);
|
|
510
612
|
if (!taskId || !targetColumn) return;
|
|
511
613
|
moveTaskToColumn(taskId, targetColumn);
|
|
512
614
|
};
|
|
513
615
|
|
|
616
|
+
const onBoardDragStart = (event: DragStartEvent) => {
|
|
617
|
+
const taskId = parseTaskId(event.active.id);
|
|
618
|
+
if (!taskId) {
|
|
619
|
+
setActiveDragTask(null);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
const task = KANBAN_COLUMNS.map((column) => boardColumns[column.id])
|
|
624
|
+
.find((items) => items.some((item) => item.id === taskId))
|
|
625
|
+
?.find((item) => item.id === taskId);
|
|
626
|
+
|
|
627
|
+
setActiveDragTask(task ?? null);
|
|
628
|
+
};
|
|
629
|
+
|
|
514
630
|
const refetchAll = useCallback(async () => {
|
|
515
631
|
await Promise.all([refetch(), refetchBoard()]);
|
|
516
632
|
}, [refetch, refetchBoard]);
|
|
@@ -590,10 +706,13 @@ export default function OperationsMyTasksPage() {
|
|
|
590
706
|
[inlineCreateName, request, refetchBoard]
|
|
591
707
|
);
|
|
592
708
|
|
|
593
|
-
const openCreateTaskForm = useCallback(() => {
|
|
709
|
+
const openCreateTaskForm = useCallback((status?: BoardColumnId) => {
|
|
594
710
|
setEditingTaskId(null);
|
|
595
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
596
711
|
setSelectedTask(null);
|
|
712
|
+
setTaskFormData((prev) => ({
|
|
713
|
+
...EMPTY_TASK_FORM,
|
|
714
|
+
...(status ? { status } : { status: prev.status }),
|
|
715
|
+
}));
|
|
597
716
|
setTaskFormOpen(true);
|
|
598
717
|
}, []);
|
|
599
718
|
|
|
@@ -607,6 +726,9 @@ export default function OperationsMyTasksPage() {
|
|
|
607
726
|
status: KANBAN_COLUMNS.some((column) => column.id === task.status)
|
|
608
727
|
? (task.status as BoardColumnId)
|
|
609
728
|
: 'todo',
|
|
729
|
+
assigneeCollaboratorId: task.assigneeCollaboratorId
|
|
730
|
+
? String(task.assigneeCollaboratorId)
|
|
731
|
+
: 'none',
|
|
610
732
|
dueDate: normalizeDateInputValue(task.dueDate),
|
|
611
733
|
estimateHours:
|
|
612
734
|
task.estimateHours != null ? String(task.estimateHours) : '',
|
|
@@ -628,6 +750,10 @@ export default function OperationsMyTasksPage() {
|
|
|
628
750
|
const payload = {
|
|
629
751
|
projectId: selectedProject.id,
|
|
630
752
|
projectAssignmentId: selectedProject.projectAssignmentId ?? null,
|
|
753
|
+
assigneeCollaboratorId:
|
|
754
|
+
taskFormData.assigneeCollaboratorId !== 'none'
|
|
755
|
+
? Number(taskFormData.assigneeCollaboratorId)
|
|
756
|
+
: null,
|
|
631
757
|
name: normalizedName,
|
|
632
758
|
description: taskFormData.description.trim() || null,
|
|
633
759
|
priority: taskFormData.priority,
|
|
@@ -661,6 +787,29 @@ export default function OperationsMyTasksPage() {
|
|
|
661
787
|
}
|
|
662
788
|
}, [editingTaskId, projectOptions, request, refetchAll, taskFormData]);
|
|
663
789
|
|
|
790
|
+
const openTimesheetEntrySheet = useCallback(
|
|
791
|
+
(task: TaskDetailSheetData) => {
|
|
792
|
+
if (!task.projectId) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
const projectLabel = [task.projectName, task.projectCode]
|
|
797
|
+
.filter(Boolean)
|
|
798
|
+
.join(' • ');
|
|
799
|
+
|
|
800
|
+
setTimesheetPrefill({
|
|
801
|
+
projectId: task.projectId,
|
|
802
|
+
projectAssignmentId: task.projectAssignmentId ?? null,
|
|
803
|
+
projectLabel: projectLabel || commonT('labels.notAssigned'),
|
|
804
|
+
taskId: task.id,
|
|
805
|
+
taskLabel: task.name,
|
|
806
|
+
});
|
|
807
|
+
setSelectedTask(null);
|
|
808
|
+
setIsTimesheetEntrySheetOpen(true);
|
|
809
|
+
},
|
|
810
|
+
[commonT]
|
|
811
|
+
);
|
|
812
|
+
|
|
664
813
|
return (
|
|
665
814
|
<Page>
|
|
666
815
|
<OperationsHeader
|
|
@@ -779,6 +928,8 @@ export default function OperationsMyTasksPage() {
|
|
|
779
928
|
<DndContext
|
|
780
929
|
sensors={sensors}
|
|
781
930
|
collisionDetection={closestCenter}
|
|
931
|
+
onDragStart={onBoardDragStart}
|
|
932
|
+
onDragCancel={() => setActiveDragTask(null)}
|
|
782
933
|
onDragEnd={onBoardDragEnd}
|
|
783
934
|
>
|
|
784
935
|
<div className="grid gap-4 xl:grid-cols-4">
|
|
@@ -787,7 +938,7 @@ export default function OperationsMyTasksPage() {
|
|
|
787
938
|
{(isOver) => (
|
|
788
939
|
<div
|
|
789
940
|
className={[
|
|
790
|
-
'flex min-h-
|
|
941
|
+
'flex min-h-48 max-h-160 flex-col rounded-3xl border bg-linear-to-b p-3 transition-all',
|
|
791
942
|
getColumnClassName(column.id),
|
|
792
943
|
isOver
|
|
793
944
|
? 'border-primary shadow-lg ring-2 ring-primary/15'
|
|
@@ -817,17 +968,14 @@ export default function OperationsMyTasksPage() {
|
|
|
817
968
|
<button
|
|
818
969
|
type="button"
|
|
819
970
|
className="flex size-5 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
820
|
-
onClick={() =>
|
|
821
|
-
setInlineCreateColumn(column.id);
|
|
822
|
-
setInlineCreateName('');
|
|
823
|
-
}}
|
|
971
|
+
onClick={() => openCreateTaskForm(column.id)}
|
|
824
972
|
>
|
|
825
973
|
<Plus className="size-3.5" />
|
|
826
974
|
</button>
|
|
827
975
|
</div>
|
|
828
976
|
</div>
|
|
829
977
|
|
|
830
|
-
<div className="flex flex-1 flex-col gap-2">
|
|
978
|
+
<div className="flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto pb-1 pr-0.5">
|
|
831
979
|
<AnimatePresence initial={false}>
|
|
832
980
|
{boardColumns[column.id].map((task) => {
|
|
833
981
|
const taskTags = task.tags
|
|
@@ -879,9 +1027,8 @@ export default function OperationsMyTasksPage() {
|
|
|
879
1027
|
</p>
|
|
880
1028
|
{task.description ? (
|
|
881
1029
|
<p className="line-clamp-2 text-xs leading-5 text-muted-foreground">
|
|
882
|
-
{
|
|
883
|
-
|
|
884
|
-
''
|
|
1030
|
+
{getTaskDescriptionPreview(
|
|
1031
|
+
task.description
|
|
885
1032
|
)}
|
|
886
1033
|
</p>
|
|
887
1034
|
) : null}
|
|
@@ -1005,81 +1152,32 @@ export default function OperationsMyTasksPage() {
|
|
|
1005
1152
|
</AnimatePresence>
|
|
1006
1153
|
</div>
|
|
1007
1154
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
}
|
|
1017
|
-
onKeyDown={(e) => {
|
|
1018
|
-
if (e.key === 'Enter') {
|
|
1019
|
-
e.preventDefault();
|
|
1020
|
-
void handleInlineCreateTask(column.id);
|
|
1021
|
-
} else if (e.key === 'Escape') {
|
|
1022
|
-
setInlineCreateColumn(null);
|
|
1023
|
-
setInlineCreateName('');
|
|
1024
|
-
}
|
|
1025
|
-
}}
|
|
1026
|
-
onBlur={() => {
|
|
1027
|
-
if (!inlineCreateName.trim()) {
|
|
1028
|
-
setInlineCreateColumn(null);
|
|
1029
|
-
setInlineCreateName('');
|
|
1030
|
-
}
|
|
1031
|
-
}}
|
|
1032
|
-
disabled={inlineCreateLoading}
|
|
1033
|
-
className="h-8 text-sm"
|
|
1034
|
-
/>
|
|
1035
|
-
<div className="flex gap-1">
|
|
1036
|
-
<Button
|
|
1037
|
-
type="button"
|
|
1038
|
-
size="sm"
|
|
1039
|
-
className="h-7 px-2 text-xs"
|
|
1040
|
-
disabled={
|
|
1041
|
-
!inlineCreateName.trim() || inlineCreateLoading
|
|
1042
|
-
}
|
|
1043
|
-
onMouseDown={(e) => e.preventDefault()}
|
|
1044
|
-
onClick={() =>
|
|
1045
|
-
void handleInlineCreateTask(column.id)
|
|
1046
|
-
}
|
|
1047
|
-
>
|
|
1048
|
-
{t('actions.create')}
|
|
1049
|
-
</Button>
|
|
1050
|
-
<Button
|
|
1051
|
-
type="button"
|
|
1052
|
-
variant="ghost"
|
|
1053
|
-
size="sm"
|
|
1054
|
-
className="h-7 px-2 text-xs"
|
|
1055
|
-
onMouseDown={(e) => e.preventDefault()}
|
|
1056
|
-
onClick={() => {
|
|
1057
|
-
setInlineCreateColumn(null);
|
|
1058
|
-
setInlineCreateName('');
|
|
1059
|
-
}}
|
|
1060
|
-
>
|
|
1061
|
-
{commonT('actions.cancel')}
|
|
1062
|
-
</Button>
|
|
1063
|
-
</div>
|
|
1064
|
-
</div>
|
|
1065
|
-
) : (
|
|
1066
|
-
<button
|
|
1067
|
-
type="button"
|
|
1068
|
-
className="flex w-full cursor-pointer items-center gap-1 rounded-md px-1 py-1 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
1069
|
-
onClick={() => {
|
|
1070
|
-
setInlineCreateColumn(column.id);
|
|
1071
|
-
setInlineCreateName('');
|
|
1072
|
-
}}
|
|
1073
|
-
>
|
|
1074
|
-
<Plus className="size-3" />
|
|
1075
|
-
{t('actions.create')}
|
|
1076
|
-
</button>
|
|
1077
|
-
)}
|
|
1155
|
+
<button
|
|
1156
|
+
type="button"
|
|
1157
|
+
className="mt-auto flex w-full cursor-pointer items-center justify-center gap-1 rounded-2xl border border-dashed bg-background/70 px-3 py-2 text-xs text-muted-foreground transition hover:border-primary/40 hover:bg-primary/5 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
|
|
1158
|
+
onClick={() => openCreateTaskForm(column.id)}
|
|
1159
|
+
>
|
|
1160
|
+
<Plus className="size-3" />
|
|
1161
|
+
{t('actions.create')}
|
|
1162
|
+
</button>
|
|
1078
1163
|
</div>
|
|
1079
1164
|
)}
|
|
1080
1165
|
</DroppableColumn>
|
|
1081
1166
|
))}
|
|
1082
1167
|
</div>
|
|
1168
|
+
<DragOverlay zIndex={1200}>
|
|
1169
|
+
{activeDragTask ? (
|
|
1170
|
+
<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">
|
|
1171
|
+
<p className="line-clamp-2 text-sm font-semibold leading-snug">
|
|
1172
|
+
{activeDragTask.name}
|
|
1173
|
+
</p>
|
|
1174
|
+
<p className="mt-1 truncate text-xs text-muted-foreground">
|
|
1175
|
+
{activeDragTask.assigneeName ||
|
|
1176
|
+
commonT('labels.notAssigned')}
|
|
1177
|
+
</p>
|
|
1178
|
+
</div>
|
|
1179
|
+
) : null}
|
|
1180
|
+
</DragOverlay>
|
|
1083
1181
|
</DndContext>
|
|
1084
1182
|
) : (
|
|
1085
1183
|
<EmptyState
|
|
@@ -1117,7 +1215,7 @@ export default function OperationsMyTasksPage() {
|
|
|
1117
1215
|
|
|
1118
1216
|
{task.description ? (
|
|
1119
1217
|
<p className="line-clamp-3 text-sm text-muted-foreground">
|
|
1120
|
-
{task.description}
|
|
1218
|
+
{getTaskDescriptionPreview(task.description)}
|
|
1121
1219
|
</p>
|
|
1122
1220
|
) : null}
|
|
1123
1221
|
|
|
@@ -1166,7 +1264,7 @@ export default function OperationsMyTasksPage() {
|
|
|
1166
1264
|
<div className="truncate font-medium">{task.name}</div>
|
|
1167
1265
|
{task.description ? (
|
|
1168
1266
|
<div className="truncate text-xs text-muted-foreground">
|
|
1169
|
-
{task.description}
|
|
1267
|
+
{getTaskDescriptionPreview(task.description)}
|
|
1170
1268
|
</div>
|
|
1171
1269
|
) : null}
|
|
1172
1270
|
</div>
|
|
@@ -1248,12 +1346,12 @@ export default function OperationsMyTasksPage() {
|
|
|
1248
1346
|
}}
|
|
1249
1347
|
footer={
|
|
1250
1348
|
selectedTask ? (
|
|
1251
|
-
<div className="grid grid-cols-
|
|
1349
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
1252
1350
|
{taskCollection === 'archived' ? (
|
|
1253
1351
|
<>
|
|
1254
1352
|
<Button
|
|
1255
1353
|
variant="outline"
|
|
1256
|
-
className="gap-2"
|
|
1354
|
+
className="gap-2 sm:col-span-2"
|
|
1257
1355
|
onClick={() => void handleRestoreTask(selectedTask.id)}
|
|
1258
1356
|
>
|
|
1259
1357
|
<ArchiveRestore className="size-4" />
|
|
@@ -1272,6 +1370,15 @@ export default function OperationsMyTasksPage() {
|
|
|
1272
1370
|
</>
|
|
1273
1371
|
) : (
|
|
1274
1372
|
<>
|
|
1373
|
+
<Button
|
|
1374
|
+
variant="outline"
|
|
1375
|
+
className="gap-2"
|
|
1376
|
+
disabled={!selectedTask.projectId}
|
|
1377
|
+
onClick={() => openTimesheetEntrySheet(selectedTask)}
|
|
1378
|
+
>
|
|
1379
|
+
<Send className="size-4" />
|
|
1380
|
+
{commonT('actions.logHours')}
|
|
1381
|
+
</Button>
|
|
1275
1382
|
<Button
|
|
1276
1383
|
variant="outline"
|
|
1277
1384
|
className="gap-2"
|
|
@@ -1297,6 +1404,36 @@ export default function OperationsMyTasksPage() {
|
|
|
1297
1404
|
}
|
|
1298
1405
|
/>
|
|
1299
1406
|
|
|
1407
|
+
<TimesheetEntryCreateSheet
|
|
1408
|
+
open={isTimesheetEntrySheetOpen}
|
|
1409
|
+
onOpenChange={(open) => {
|
|
1410
|
+
setIsTimesheetEntrySheetOpen(open);
|
|
1411
|
+
if (!open) {
|
|
1412
|
+
setTimesheetPrefill(null);
|
|
1413
|
+
}
|
|
1414
|
+
}}
|
|
1415
|
+
project={
|
|
1416
|
+
timesheetPrefill
|
|
1417
|
+
? {
|
|
1418
|
+
id: timesheetPrefill.projectId,
|
|
1419
|
+
label: timesheetPrefill.projectLabel,
|
|
1420
|
+
projectAssignmentId: timesheetPrefill.projectAssignmentId,
|
|
1421
|
+
}
|
|
1422
|
+
: null
|
|
1423
|
+
}
|
|
1424
|
+
task={
|
|
1425
|
+
timesheetPrefill
|
|
1426
|
+
? {
|
|
1427
|
+
id: timesheetPrefill.taskId,
|
|
1428
|
+
label: timesheetPrefill.taskLabel,
|
|
1429
|
+
}
|
|
1430
|
+
: null
|
|
1431
|
+
}
|
|
1432
|
+
onCreated={() => {
|
|
1433
|
+
void refetchAll();
|
|
1434
|
+
}}
|
|
1435
|
+
/>
|
|
1436
|
+
|
|
1300
1437
|
<Dialog
|
|
1301
1438
|
open={deletePromptTask !== null}
|
|
1302
1439
|
onOpenChange={(open) => {
|
|
@@ -1306,10 +1443,10 @@ export default function OperationsMyTasksPage() {
|
|
|
1306
1443
|
<DialogContent className="sm:max-w-sm">
|
|
1307
1444
|
<DialogHeader>
|
|
1308
1445
|
<DialogTitle>{t('dialogs.deleteTitle')}</DialogTitle>
|
|
1446
|
+
<DialogDescription>
|
|
1447
|
+
{t('dialogs.deleteDescription')}
|
|
1448
|
+
</DialogDescription>
|
|
1309
1449
|
</DialogHeader>
|
|
1310
|
-
<p className="text-sm text-muted-foreground">
|
|
1311
|
-
{t('dialogs.deleteDescription')}
|
|
1312
|
-
</p>
|
|
1313
1450
|
<DialogFooter className="mt-4">
|
|
1314
1451
|
<Button variant="outline" onClick={() => setDeletePromptTask(null)}>
|
|
1315
1452
|
{commonT('actions.cancel')}
|
|
@@ -1331,13 +1468,8 @@ export default function OperationsMyTasksPage() {
|
|
|
1331
1468
|
<Sheet
|
|
1332
1469
|
open={taskFormOpen}
|
|
1333
1470
|
onOpenChange={(open) => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
if (!open) {
|
|
1337
|
-
setEditingTaskId(null);
|
|
1338
|
-
setTaskFormData(EMPTY_TASK_FORM);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1471
|
+
setTaskFormOpen(open);
|
|
1472
|
+
if (!open) setEditingTaskId(null);
|
|
1341
1473
|
}}
|
|
1342
1474
|
>
|
|
1343
1475
|
<SheetContent className="flex w-full flex-col overflow-hidden sm:max-w-xl">
|
|
@@ -1481,6 +1613,35 @@ export default function OperationsMyTasksPage() {
|
|
|
1481
1613
|
</div>
|
|
1482
1614
|
</div>
|
|
1483
1615
|
|
|
1616
|
+
<div className="space-y-2">
|
|
1617
|
+
<Label>{commonT('responsible')}</Label>
|
|
1618
|
+
<Select
|
|
1619
|
+
value={taskFormData.assigneeCollaboratorId}
|
|
1620
|
+
onValueChange={(value) =>
|
|
1621
|
+
setTaskFormData((prev) => ({
|
|
1622
|
+
...prev,
|
|
1623
|
+
assigneeCollaboratorId: value,
|
|
1624
|
+
}))
|
|
1625
|
+
}
|
|
1626
|
+
>
|
|
1627
|
+
<SelectTrigger className="w-full">
|
|
1628
|
+
<SelectValue
|
|
1629
|
+
placeholder={commonT('labels.notAssigned')}
|
|
1630
|
+
/>
|
|
1631
|
+
</SelectTrigger>
|
|
1632
|
+
<SelectContent>
|
|
1633
|
+
<SelectItem value="none">
|
|
1634
|
+
{commonT('labels.notAssigned')}
|
|
1635
|
+
</SelectItem>
|
|
1636
|
+
{assigneeOptions.map((option) => (
|
|
1637
|
+
<SelectItem key={option.id} value={option.id}>
|
|
1638
|
+
{option.label}
|
|
1639
|
+
</SelectItem>
|
|
1640
|
+
))}
|
|
1641
|
+
</SelectContent>
|
|
1642
|
+
</Select>
|
|
1643
|
+
</div>
|
|
1644
|
+
|
|
1484
1645
|
<div className="grid grid-cols-2 gap-3">
|
|
1485
1646
|
<div className="space-y-2">
|
|
1486
1647
|
<Label htmlFor="task-due-date">
|