@open-mercato/core 0.6.4-develop.4210.1.d412061cfe → 0.6.4-develop.4236.1.9fa6806b34
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/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/staff_time_entry/index.js +37 -0
- package/dist/generated/entities/staff_time_entry/index.js.map +7 -0
- package/dist/generated/entities/staff_time_entry_segment/index.js +23 -0
- package/dist/generated/entities/staff_time_entry_segment/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project/index.js +35 -0
- package/dist/generated/entities/staff_time_project/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project_member/index.js +29 -0
- package/dist/generated/entities/staff_time_project_member/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +5 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +64 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/timesheetFixtures.js +50 -0
- package/dist/helpers/integration/timesheetFixtures.js.map +7 -0
- package/dist/modules/attachments/api/library/[id]/route.js +20 -16
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +18 -14
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +10 -4
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/preferences/route.js +27 -20
- package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +16 -11
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/commands/users.js +87 -71
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/services/sidebarPreferencesService.js +39 -30
- package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
- package/dist/modules/catalog/commands/categories.js +61 -12
- package/dist/modules/catalog/commands/categories.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +79 -54
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +29 -16
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +15 -8
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users.js +27 -26
- package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
- package/dist/modules/customer_accounts/api/password/reset-confirm.js +5 -5
- package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +11 -10
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
- package/dist/modules/customers/commands/addresses.js +35 -21
- package/dist/modules/customers/commands/addresses.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +163 -162
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +3 -4
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +19 -22
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/people.js +18 -15
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/dist/modules/customers/commands/personCompanyLinks.js +105 -94
- package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +30 -23
- package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
- package/dist/modules/customers/commands/pipelines.js +27 -20
- package/dist/modules/customers/commands/pipelines.js.map +2 -2
- package/dist/modules/customers/commands/tags.js +13 -5
- package/dist/modules/customers/commands/tags.js.map +2 -2
- package/dist/modules/dashboards/api/users/widgets/route.js +0 -1
- package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/route.js +29 -1
- package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-engine.js +4 -4
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +51 -27
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/directory/commands/organizations.js +192 -158
- package/dist/modules/directory/commands/organizations.js.map +3 -3
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +22 -16
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +77 -75
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/commands/shared.js +132 -132
- package/dist/modules/messages/commands/shared.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/route.js +37 -26
- package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
- package/dist/modules/resources/commands/resources.js +125 -117
- package/dist/modules/resources/commands/resources.js.map +2 -2
- package/dist/modules/resources/commands/tags.js +7 -3
- package/dist/modules/resources/commands/tags.js.map +2 -2
- package/dist/modules/sales/api/quotes/send/route.js +12 -11
- package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +629 -478
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +146 -146
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +68 -60
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/staff/acl.js +10 -1
- package/dist/modules/staff/acl.js.map +2 -2
- package/dist/modules/staff/analytics.js +33 -0
- package/dist/modules/staff/analytics.js.map +7 -0
- package/dist/modules/staff/api/guards.js +31 -0
- package/dist/modules/staff/api/guards.js.map +7 -0
- package/dist/modules/staff/api/interceptors.js +96 -0
- package/dist/modules/staff/api/interceptors.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +170 -0
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-projects/route.js +103 -0
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +147 -0
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +171 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +180 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +155 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +173 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +260 -0
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/route.js +188 -0
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +159 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-projects/route.js +230 -0
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/page.js +710 -0
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js +22 -0
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +125 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +418 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +79 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +602 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +25 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +123 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +7 -0
- package/dist/modules/staff/cli.js +38 -1
- package/dist/modules/staff/cli.js.map +2 -2
- package/dist/modules/staff/commands/index.js +2 -0
- package/dist/modules/staff/commands/index.js.map +2 -2
- package/dist/modules/staff/commands/leave-requests.js +30 -28
- package/dist/modules/staff/commands/leave-requests.js.map +3 -3
- package/dist/modules/staff/commands/team-members.js +21 -20
- package/dist/modules/staff/commands/team-members.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js +409 -0
- package/dist/modules/staff/commands/timesheets-entries.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-projects.js +618 -0
- package/dist/modules/staff/commands/timesheets-projects.js.map +7 -0
- package/dist/modules/staff/data/enrichers.js +104 -0
- package/dist/modules/staff/data/enrichers.js.map +7 -0
- package/dist/modules/staff/data/entities.js +226 -1
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/staff/data/validators.js +113 -1
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/events.js +13 -1
- package/dist/modules/staff/events.js.map +2 -2
- package/dist/modules/staff/lib/crud.js +7 -1
- package/dist/modules/staff/lib/crud.js.map +2 -2
- package/dist/modules/staff/lib/staffMemberResolver.js +15 -0
- package/dist/modules/staff/lib/staffMemberResolver.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js +60 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js +260 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js +41 -0
- package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/initials.js +10 -0
- package/dist/modules/staff/lib/timesheets-projects/initials.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/kpiMath.js +12 -0
- package/dist/modules/staff/lib/timesheets-projects/kpiMath.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js +55 -0
- package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js +66 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +81 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js +58 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js +152 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +37 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js +57 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js +50 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js +163 -0
- package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +209 -0
- package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js +52 -0
- package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +77 -0
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/ListView.js +173 -0
- package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js +32 -0
- package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +270 -0
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js +57 -0
- package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/colors.js +43 -0
- package/dist/modules/staff/lib/timesheets-ui/colors.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260326135612.js +24 -0
- package/dist/modules/staff/migrations/Migration20260326135612.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260413102715.js +23 -0
- package/dist/modules/staff/migrations/Migration20260413102715.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260413111602.js +13 -0
- package/dist/modules/staff/migrations/Migration20260413111602.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260511112759.js +19 -0
- package/dist/modules/staff/migrations/Migration20260511112759.js.map +7 -0
- package/dist/modules/staff/search.js +35 -0
- package/dist/modules/staff/search.js.map +2 -2
- package/dist/modules/staff/setup.js +15 -1
- package/dist/modules/staff/setup.js.map +2 -2
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js +16 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js.map +7 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +126 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js +26 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js.map +7 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js +15 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js.map +7 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +238 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js +26 -0
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +145 -0
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection-table.js +12 -0
- package/dist/modules/staff/widgets/injection-table.js.map +7 -0
- package/dist/modules/sync_excel/api/import/route.js +19 -17
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/translations/commands/translations.js +22 -19
- package/dist/modules/translations/commands/translations.js.map +2 -2
- package/generated/entities/staff_time_entry/index.ts +17 -0
- package/generated/entities/staff_time_entry_segment/index.ts +10 -0
- package/generated/entities/staff_time_project/index.ts +16 -0
- package/generated/entities/staff_time_project_member/index.ts +13 -0
- package/generated/entities.ids.generated.ts +5 -1
- package/generated/entity-fields-registry.ts +64 -0
- package/package.json +7 -7
- package/src/helpers/integration/timesheetFixtures.ts +61 -0
- package/src/modules/attachments/api/library/[id]/route.ts +24 -17
- package/src/modules/attachments/api/route.ts +20 -14
- package/src/modules/auth/api/roles/acl/route.ts +11 -5
- package/src/modules/auth/api/sidebar/preferences/route.ts +33 -24
- package/src/modules/auth/api/users/acl/route.ts +17 -12
- package/src/modules/auth/commands/users.ts +96 -80
- package/src/modules/auth/services/sidebarPreferencesService.ts +40 -32
- package/src/modules/catalog/commands/categories.ts +61 -12
- package/src/modules/catalog/commands/products.ts +93 -60
- package/src/modules/catalog/commands/variants.ts +29 -16
- package/src/modules/currencies/commands/currencies.ts +27 -14
- package/src/modules/customer_accounts/api/admin/users.ts +31 -26
- package/src/modules/customer_accounts/api/password/reset-confirm.ts +5 -6
- package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +14 -13
- package/src/modules/customers/commands/addresses.ts +35 -23
- package/src/modules/customers/commands/companies.ts +166 -165
- package/src/modules/customers/commands/deals.ts +2 -4
- package/src/modules/customers/commands/interactions.ts +20 -26
- package/src/modules/customers/commands/people.ts +18 -15
- package/src/modules/customers/commands/personCompanyLinks.ts +109 -100
- package/src/modules/customers/commands/pipeline-stages.ts +31 -27
- package/src/modules/customers/commands/pipelines.ts +29 -23
- package/src/modules/customers/commands/tags.ts +13 -5
- package/src/modules/dashboards/api/users/widgets/route.ts +0 -1
- package/src/modules/dashboards/api/widgets/data/route.ts +36 -1
- package/src/modules/data_sync/lib/sync-engine.ts +4 -5
- package/src/modules/data_sync/lib/sync-run-service.ts +57 -28
- package/src/modules/directory/commands/organizations.ts +203 -166
- package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +26 -18
- package/src/modules/messages/commands/messages.ts +82 -80
- package/src/modules/messages/commands/shared.ts +138 -133
- package/src/modules/perspectives/api/[tableId]/route.ts +38 -27
- package/src/modules/resources/commands/resources.ts +127 -117
- package/src/modules/resources/commands/tags.ts +7 -3
- package/src/modules/sales/api/quotes/send/route.ts +17 -12
- package/src/modules/sales/commands/documents.ts +673 -481
- package/src/modules/sales/commands/payments.ts +158 -152
- package/src/modules/sales/commands/returns.ts +74 -63
- package/src/modules/staff/acl.ts +11 -0
- package/src/modules/staff/analytics.ts +30 -0
- package/src/modules/staff/api/guards.ts +59 -0
- package/src/modules/staff/api/interceptors.ts +122 -0
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +191 -0
- package/src/modules/staff/api/timesheets/my-projects/route.ts +115 -0
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +159 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +187 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +191 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +168 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +191 -0
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +292 -0
- package/src/modules/staff/api/timesheets/time-entries/route.ts +193 -0
- package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +167 -0
- package/src/modules/staff/api/timesheets/time-projects/route.ts +244 -0
- package/src/modules/staff/backend/staff/timesheets/page.meta.ts +20 -0
- package/src/modules/staff/backend/staff/timesheets/page.tsx +899 -0
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +141 -0
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +579 -0
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +90 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +23 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +765 -0
- package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +138 -0
- package/src/modules/staff/cli.ts +40 -1
- package/src/modules/staff/commands/index.ts +2 -0
- package/src/modules/staff/commands/leave-requests.ts +37 -29
- package/src/modules/staff/commands/team-members.ts +25 -20
- package/src/modules/staff/commands/timesheets-entries.ts +504 -0
- package/src/modules/staff/commands/timesheets-projects.ts +699 -0
- package/src/modules/staff/data/enrichers.ts +134 -0
- package/src/modules/staff/data/entities.ts +198 -0
- package/src/modules/staff/data/validators.ts +129 -0
- package/src/modules/staff/events.ts +13 -0
- package/src/modules/staff/i18n/de.json +209 -1
- package/src/modules/staff/i18n/en.json +209 -1
- package/src/modules/staff/i18n/es.json +209 -1
- package/src/modules/staff/i18n/pl.json +209 -1
- package/src/modules/staff/lib/crud.ts +8 -0
- package/src/modules/staff/lib/staffMemberResolver.ts +22 -0
- package/src/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.ts +89 -0
- package/src/modules/staff/lib/timesheets-projects/computeProjectsKpis.ts +311 -0
- package/src/modules/staff/lib/timesheets-projects/dateBuckets.ts +37 -0
- package/src/modules/staff/lib/timesheets-projects/initials.ts +6 -0
- package/src/modules/staff/lib/timesheets-projects/kpiMath.ts +8 -0
- package/src/modules/staff/lib/timesheets-projects/listProjectMembersPreview.ts +83 -0
- package/src/modules/staff/lib/timesheets-projects-ui/HoursSparkline.tsx +75 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +110 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.tsx +73 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.tsx +185 -0
- package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +53 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.tsx +63 -0
- package/src/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.ts +63 -0
- package/src/modules/staff/lib/timesheets-ui/AddRowDropdown.tsx +188 -0
- package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +229 -0
- package/src/modules/staff/lib/timesheets-ui/ColorPicker.tsx +65 -0
- package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +99 -0
- package/src/modules/staff/lib/timesheets-ui/ListView.tsx +230 -0
- package/src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx +40 -0
- package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +327 -0
- package/src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx +60 -0
- package/src/modules/staff/lib/timesheets-ui/colors.ts +58 -0
- package/src/modules/staff/migrations/.snapshot-open-mercato.json +1148 -0
- package/src/modules/staff/migrations/Migration20260326135612.ts +26 -0
- package/src/modules/staff/migrations/Migration20260413102715.ts +25 -0
- package/src/modules/staff/migrations/Migration20260413111602.ts +13 -0
- package/src/modules/staff/migrations/Migration20260511112759.ts +21 -0
- package/src/modules/staff/search.ts +35 -0
- package/src/modules/staff/setup.ts +15 -0
- package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts +17 -0
- package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +158 -0
- package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts +25 -0
- package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts +15 -0
- package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +297 -0
- package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.ts +25 -0
- package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +161 -0
- package/src/modules/staff/widgets/injection-table.ts +10 -0
- package/src/modules/sync_excel/api/import/route.ts +23 -18
- package/src/modules/translations/commands/translations.ts +49 -41
|
@@ -140,6 +140,41 @@ const searchConfig = {
|
|
|
140
140
|
fieldPolicy: {
|
|
141
141
|
searchable: ["name", "description", "appearance_icon", "appearance_color"]
|
|
142
142
|
}
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
entityId: "staff:staff_time_project",
|
|
146
|
+
enabled: true,
|
|
147
|
+
priority: 7,
|
|
148
|
+
buildSource: async (ctx) => {
|
|
149
|
+
const { t } = await resolveTranslations();
|
|
150
|
+
const record = ctx.record;
|
|
151
|
+
const lines = [];
|
|
152
|
+
appendLine(lines, "Name", record.name);
|
|
153
|
+
appendLine(lines, "Code", record.code);
|
|
154
|
+
appendLine(lines, "Description", record.description);
|
|
155
|
+
appendLine(lines, "Type", record.project_type ?? record.projectType);
|
|
156
|
+
appendLine(lines, "Cost Center", record.cost_center ?? record.costCenter);
|
|
157
|
+
const presenter = {
|
|
158
|
+
title: String(record.name ?? record.id ?? t("staff.search.badge.timeProject", "Project")),
|
|
159
|
+
subtitle: formatSubtitle(record.code, record.project_type ?? record.projectType),
|
|
160
|
+
icon: "clock",
|
|
161
|
+
badge: t("staff.search.badge.timeProject", "Project")
|
|
162
|
+
};
|
|
163
|
+
return buildIndexSource(ctx, presenter, lines);
|
|
164
|
+
},
|
|
165
|
+
formatResult: async (ctx) => {
|
|
166
|
+
const { t } = await resolveTranslations();
|
|
167
|
+
return {
|
|
168
|
+
title: String(ctx.record.name ?? ctx.record.id ?? ""),
|
|
169
|
+
subtitle: formatSubtitle(ctx.record.code, ctx.record.project_type ?? ctx.record.projectType),
|
|
170
|
+
icon: "clock",
|
|
171
|
+
badge: t("staff.search.badge.timeProject", "Project")
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
resolveUrl: async (ctx) => `/backend/staff/timesheets/projects/${encodeURIComponent(String(ctx.record.id))}`,
|
|
175
|
+
fieldPolicy: {
|
|
176
|
+
searchable: ["name", "code", "description", "project_type", "cost_center"]
|
|
177
|
+
}
|
|
143
178
|
}
|
|
144
179
|
]
|
|
145
180
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/staff/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildTeamPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.team', 'Team')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'users',\n badge: t('staff.search.badge.team', 'Team'),\n }\n}\n\nfunction buildTeamMemberPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.display_name, record.displayName, record.name, customFields.display_name, customFields.name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.teamMember', 'Employee')\n const description = snippet(record.description ?? customFields.description)\n const tags = Array.isArray(record.tags) ? record.tags.join(', ') : undefined\n return {\n title: String(title),\n subtitle: formatSubtitle(description, tags),\n icon: 'user',\n badge: t('staff.search.badge.teamMember', 'Employee'),\n }\n}\n\nfunction buildTeamRolePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.teamRole', 'Role')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shield',\n badge: t('staff.search.badge.teamRole', 'Role'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'staff:staff_team',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Active', record.is_active ?? record.isActive)\n return buildIndexSource(ctx, buildTeamPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/teams/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description'],\n },\n },\n {\n entityId: 'staff:staff_team_member',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.display_name ?? record.displayName ?? ctx.customFields.display_name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Tags', record.tags)\n appendLine(lines, 'Active', record.is_active ?? record.isActive)\n return buildIndexSource(ctx, buildTeamMemberPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamMemberPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/team-members/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['display_name', 'description', 'tags'],\n },\n },\n {\n entityId: 'staff:staff_team_role',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildTeamRolePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamRolePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/team-roles/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildTeamPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.team', 'Team')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'users',\n badge: t('staff.search.badge.team', 'Team'),\n }\n}\n\nfunction buildTeamMemberPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.display_name, record.displayName, record.name, customFields.display_name, customFields.name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.teamMember', 'Employee')\n const description = snippet(record.description ?? customFields.description)\n const tags = Array.isArray(record.tags) ? record.tags.join(', ') : undefined\n return {\n title: String(title),\n subtitle: formatSubtitle(description, tags),\n icon: 'user',\n badge: t('staff.search.badge.teamMember', 'Employee'),\n }\n}\n\nfunction buildTeamRolePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('staff.search.badge.teamRole', 'Role')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shield',\n badge: t('staff.search.badge.teamRole', 'Role'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'staff:staff_team',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Active', record.is_active ?? record.isActive)\n return buildIndexSource(ctx, buildTeamPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/teams/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description'],\n },\n },\n {\n entityId: 'staff:staff_team_member',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.display_name ?? record.displayName ?? ctx.customFields.display_name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Tags', record.tags)\n appendLine(lines, 'Active', record.is_active ?? record.isActive)\n return buildIndexSource(ctx, buildTeamMemberPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamMemberPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/team-members/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['display_name', 'description', 'tags'],\n },\n },\n {\n entityId: 'staff:staff_team_role',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildTeamRolePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildTeamRolePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/staff/team-roles/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n {\n entityId: 'staff:staff_time_project',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name)\n appendLine(lines, 'Code', record.code)\n appendLine(lines, 'Description', record.description)\n appendLine(lines, 'Type', record.project_type ?? record.projectType)\n appendLine(lines, 'Cost Center', record.cost_center ?? record.costCenter)\n const presenter: SearchResultPresenter = {\n title: String(record.name ?? record.id ?? t('staff.search.badge.timeProject', 'Project')),\n subtitle: formatSubtitle(record.code, record.project_type ?? record.projectType),\n icon: 'clock',\n badge: t('staff.search.badge.timeProject', 'Project'),\n }\n return buildIndexSource(ctx, presenter, lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return {\n title: String(ctx.record.name ?? ctx.record.id ?? ''),\n subtitle: formatSubtitle(ctx.record.code, ctx.record.project_type ?? ctx.record.projectType),\n icon: 'clock',\n badge: t('staff.search.badge.timeProject', 'Project'),\n }\n },\n resolveUrl: async (ctx) => `/backend/staff/timesheets/projects/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'code', 'description', 'project_type', 'cost_center'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { appendWidgetsToRoles } from "@open-mercato/core/modules/dashboards/lib/role-widgets";
|
|
1
2
|
import { seedStaffAddressTypes, seedStaffTeamExamples } from "./lib/seeds.js";
|
|
3
|
+
const TIMESHEETS_DASHBOARD_WIDGET_IDS = [
|
|
4
|
+
"staff.timesheets.timeReporting",
|
|
5
|
+
"staff.timesheets.hoursByProject"
|
|
6
|
+
];
|
|
2
7
|
const setup = {
|
|
3
8
|
seedDefaults: async (ctx) => {
|
|
4
9
|
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId };
|
|
5
10
|
await seedStaffAddressTypes(ctx.em, scope);
|
|
11
|
+
await appendWidgetsToRoles(ctx.em, {
|
|
12
|
+
tenantId: ctx.tenantId,
|
|
13
|
+
organizationId: ctx.organizationId,
|
|
14
|
+
roleNames: ["superadmin", "admin", "employee"],
|
|
15
|
+
widgetIds: TIMESHEETS_DASHBOARD_WIDGET_IDS
|
|
16
|
+
});
|
|
6
17
|
},
|
|
7
18
|
seedExamples: async (ctx) => {
|
|
8
19
|
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId };
|
|
@@ -15,7 +26,10 @@ const setup = {
|
|
|
15
26
|
"staff.my_availability.view",
|
|
16
27
|
"staff.my_availability.manage",
|
|
17
28
|
"staff.my_leave_requests.view",
|
|
18
|
-
"staff.my_leave_requests.send"
|
|
29
|
+
"staff.my_leave_requests.send",
|
|
30
|
+
"staff.timesheets.view",
|
|
31
|
+
"staff.timesheets.manage_own",
|
|
32
|
+
"staff.timesheets.projects.view"
|
|
19
33
|
]
|
|
20
34
|
}
|
|
21
35
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/staff/setup.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { seedStaffAddressTypes, seedStaffTeamExamples } from './lib/seeds'\n\nexport const setup: ModuleSetupConfig = {\n seedDefaults: async (ctx) => {\n const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n await seedStaffAddressTypes(ctx.em, scope)\n },\n\n seedExamples: async (ctx) => {\n const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n await seedStaffTeamExamples(ctx.em, scope)\n },\n\n defaultRoleFeatures: {\n admin: ['staff.*', 'staff.leave_requests.manage'],\n employee: [\n 'staff.leave_requests.send',\n 'staff.my_availability.view',\n 'staff.my_availability.manage',\n 'staff.my_leave_requests.view',\n 'staff.my_leave_requests.send',\n ],\n },\n}\n\nexport default setup\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,uBAAuB,6BAA6B;
|
|
4
|
+
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\nimport { appendWidgetsToRoles } from '@open-mercato/core/modules/dashboards/lib/role-widgets'\nimport { seedStaffAddressTypes, seedStaffTeamExamples } from './lib/seeds'\n\nconst TIMESHEETS_DASHBOARD_WIDGET_IDS = [\n 'staff.timesheets.timeReporting',\n 'staff.timesheets.hoursByProject',\n]\n\nexport const setup: ModuleSetupConfig = {\n seedDefaults: async (ctx) => {\n const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n await seedStaffAddressTypes(ctx.em, scope)\n await appendWidgetsToRoles(ctx.em, {\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n roleNames: ['superadmin', 'admin', 'employee'],\n widgetIds: TIMESHEETS_DASHBOARD_WIDGET_IDS,\n })\n },\n\n seedExamples: async (ctx) => {\n const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }\n await seedStaffTeamExamples(ctx.em, scope)\n },\n\n defaultRoleFeatures: {\n admin: ['staff.*', 'staff.leave_requests.manage'],\n employee: [\n 'staff.leave_requests.send',\n 'staff.my_availability.view',\n 'staff.my_availability.manage',\n 'staff.my_leave_requests.view',\n 'staff.my_leave_requests.send',\n 'staff.timesheets.view',\n 'staff.timesheets.manage_own',\n 'staff.timesheets.projects.view',\n ],\n },\n}\n\nexport default setup\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,4BAA4B;AACrC,SAAS,uBAAuB,6BAA6B;AAE7D,MAAM,kCAAkC;AAAA,EACtC;AAAA,EACA;AACF;AAEO,MAAM,QAA2B;AAAA,EACtC,cAAc,OAAO,QAAQ;AAC3B,UAAM,QAAQ,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAC3E,UAAM,sBAAsB,IAAI,IAAI,KAAK;AACzC,UAAM,qBAAqB,IAAI,IAAI;AAAA,MACjC,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,WAAW,CAAC,cAAc,SAAS,UAAU;AAAA,MAC7C,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,OAAO,QAAQ;AAC3B,UAAM,QAAQ,EAAE,UAAU,IAAI,UAAU,gBAAgB,IAAI,eAAe;AAC3E,UAAM,sBAAsB,IAAI,IAAI,KAAK;AAAA,EAC3C;AAAA,EAEA,qBAAqB;AAAA,IACnB,OAAO,CAAC,WAAW,6BAA6B;AAAA,IAChD,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isValidDateRangePreset } from "@open-mercato/ui/backend/date-range";
|
|
2
|
+
const DEFAULT_SETTINGS = {
|
|
3
|
+
dateRange: "this_month"
|
|
4
|
+
};
|
|
5
|
+
function hydrateSettings(raw) {
|
|
6
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULT_SETTINGS };
|
|
7
|
+
const obj = raw;
|
|
8
|
+
return {
|
|
9
|
+
dateRange: isValidDateRangePreset(obj.dateRange) ? obj.dateRange : DEFAULT_SETTINGS.dateRange
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
DEFAULT_SETTINGS,
|
|
14
|
+
hydrateSettings
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts"],
|
|
4
|
+
"sourcesContent": ["import { type DateRangePreset, isValidDateRangePreset } from '@open-mercato/ui/backend/date-range'\n\nexport type HoursByProjectSettings = {\n dateRange: DateRangePreset\n}\n\nexport const DEFAULT_SETTINGS: HoursByProjectSettings = {\n dateRange: 'this_month',\n}\n\nexport function hydrateSettings(raw: unknown): HoursByProjectSettings {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_SETTINGS }\n const obj = raw as Record<string, unknown>\n return {\n dateRange: isValidDateRangePreset(obj.dateRange) ? obj.dateRange : DEFAULT_SETTINGS.dateRange,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAA+B,8BAA8B;AAMtD,MAAM,mBAA2C;AAAA,EACtD,WAAW;AACb;AAEO,SAAS,gBAAgB,KAAsC;AACpE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,EAAE,GAAG,iBAAiB;AAClE,QAAM,MAAM;AACZ,SAAO;AAAA,IACL,WAAW,uBAAuB,IAAI,SAAS,IAAI,IAAI,YAAY,iBAAiB;AAAA,EACtF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
5
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
6
|
+
import {
|
|
7
|
+
DateRangeSelect,
|
|
8
|
+
InlineDateRangeSelect
|
|
9
|
+
} from "@open-mercato/ui/backend/date-range";
|
|
10
|
+
import { DEFAULT_SETTINGS, hydrateSettings } from "./config.js";
|
|
11
|
+
function minutesToHours(minutes) {
|
|
12
|
+
const hours = minutes / 60;
|
|
13
|
+
return hours % 1 === 0 ? String(hours) : hours.toFixed(1);
|
|
14
|
+
}
|
|
15
|
+
async function fetchData(settings) {
|
|
16
|
+
const body = {
|
|
17
|
+
entityType: "staff:staff_time_entries",
|
|
18
|
+
metric: { field: "durationMinutes", aggregate: "sum" },
|
|
19
|
+
groupBy: { field: "timeProjectId", limit: 20, resolveLabels: true },
|
|
20
|
+
dateRange: { field: "date", preset: settings.dateRange }
|
|
21
|
+
};
|
|
22
|
+
const res = await apiCall("/api/dashboards/widgets/data", {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify(body)
|
|
26
|
+
});
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
const err = res.result?.error;
|
|
29
|
+
throw new Error(typeof err === "string" ? err : "Failed to fetch data");
|
|
30
|
+
}
|
|
31
|
+
return res.result;
|
|
32
|
+
}
|
|
33
|
+
const HoursByProjectWidget = ({
|
|
34
|
+
mode,
|
|
35
|
+
settings = DEFAULT_SETTINGS,
|
|
36
|
+
onSettingsChange,
|
|
37
|
+
refreshToken,
|
|
38
|
+
onRefreshStateChange
|
|
39
|
+
}) => {
|
|
40
|
+
const t = useT();
|
|
41
|
+
const hydrated = React.useMemo(() => hydrateSettings(settings), [settings]);
|
|
42
|
+
const [data, setData] = React.useState([]);
|
|
43
|
+
const [totalMinutes, setTotalMinutes] = React.useState(0);
|
|
44
|
+
const [loading, setLoading] = React.useState(true);
|
|
45
|
+
const [error, setError] = React.useState(null);
|
|
46
|
+
const refresh = React.useCallback(async () => {
|
|
47
|
+
onRefreshStateChange?.(true);
|
|
48
|
+
setLoading(true);
|
|
49
|
+
setError(null);
|
|
50
|
+
try {
|
|
51
|
+
const result = await fetchData(hydrated);
|
|
52
|
+
const sorted = [...result.data].sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
|
|
53
|
+
setData(sorted);
|
|
54
|
+
setTotalMinutes(sorted.reduce((sum, item) => sum + (item.value ?? 0), 0));
|
|
55
|
+
} catch (err) {
|
|
56
|
+
console.error("staff.timesheets.hoursByProject", err);
|
|
57
|
+
setError(t("staff.timesheets.widgets.hoursByProject.error", "Failed to load data"));
|
|
58
|
+
} finally {
|
|
59
|
+
setLoading(false);
|
|
60
|
+
onRefreshStateChange?.(false);
|
|
61
|
+
}
|
|
62
|
+
}, [hydrated, onRefreshStateChange, t]);
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
void refresh();
|
|
65
|
+
}, [refresh, refreshToken]);
|
|
66
|
+
if (mode === "settings") {
|
|
67
|
+
return /* @__PURE__ */ jsx("div", { className: "space-y-4 text-sm", children: /* @__PURE__ */ jsx(
|
|
68
|
+
DateRangeSelect,
|
|
69
|
+
{
|
|
70
|
+
id: "hours-by-project-date-range",
|
|
71
|
+
label: t("staff.timesheets.widgets.hoursByProject.settings.dateRange", "Date Range"),
|
|
72
|
+
value: hydrated.dateRange,
|
|
73
|
+
onChange: (dateRange) => onSettingsChange({ ...hydrated, dateRange })
|
|
74
|
+
}
|
|
75
|
+
) });
|
|
76
|
+
}
|
|
77
|
+
if (loading) {
|
|
78
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center py-8", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("staff.timesheets.widgets.hoursByProject.loading", "Loading...") }) });
|
|
79
|
+
}
|
|
80
|
+
if (error) {
|
|
81
|
+
return /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center py-8", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }) });
|
|
82
|
+
}
|
|
83
|
+
const maxValue = data.length > 0 ? Math.max(...data.map((d) => d.value ?? 0)) : 0;
|
|
84
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
85
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-end", children: /* @__PURE__ */ jsx(
|
|
86
|
+
InlineDateRangeSelect,
|
|
87
|
+
{
|
|
88
|
+
value: hydrated.dateRange,
|
|
89
|
+
onChange: (dateRange) => onSettingsChange({ ...hydrated, dateRange })
|
|
90
|
+
}
|
|
91
|
+
) }),
|
|
92
|
+
data.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: t("staff.timesheets.widgets.hoursByProject.empty", "No hours tracked in this period.") }) : /* @__PURE__ */ jsxs("div", { className: "space-y-2.5", children: [
|
|
93
|
+
data.map((item) => {
|
|
94
|
+
const barWidth = maxValue > 0 ? (item.value ?? 0) / maxValue * 100 : 0;
|
|
95
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
96
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
|
|
97
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: item.groupLabel || item.groupKey }),
|
|
98
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: [
|
|
99
|
+
minutesToHours(item.value ?? 0),
|
|
100
|
+
" h"
|
|
101
|
+
] })
|
|
102
|
+
] }),
|
|
103
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-full rounded-full bg-muted", children: /* @__PURE__ */ jsx(
|
|
104
|
+
"div",
|
|
105
|
+
{
|
|
106
|
+
className: "h-2 rounded-full bg-primary transition-all",
|
|
107
|
+
style: { width: `${barWidth}%` }
|
|
108
|
+
}
|
|
109
|
+
) })
|
|
110
|
+
] }, item.groupKey);
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t pt-2 text-sm font-semibold", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("span", { children: t("staff.timesheets.widgets.hoursByProject.total", "Total") }),
|
|
114
|
+
/* @__PURE__ */ jsxs("span", { className: "tabular-nums", children: [
|
|
115
|
+
minutesToHours(totalMinutes),
|
|
116
|
+
" h"
|
|
117
|
+
] })
|
|
118
|
+
] })
|
|
119
|
+
] })
|
|
120
|
+
] });
|
|
121
|
+
};
|
|
122
|
+
var widget_client_default = HoursByProjectWidget;
|
|
123
|
+
export {
|
|
124
|
+
widget_client_default as default
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=widget.client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DateRangeSelect,\n InlineDateRangeSelect,\n type DateRangePreset,\n} from '@open-mercato/ui/backend/date-range'\nimport { DEFAULT_SETTINGS, hydrateSettings, type HoursByProjectSettings } from './config'\n\ntype WidgetDataItem = { groupKey: string; groupLabel?: string; value: number | null }\ntype WidgetDataResponse = {\n value: number | null\n data: WidgetDataItem[]\n metadata: { fetchedAt: string; recordCount: number }\n}\n\nfunction minutesToHours(minutes: number): string {\n const hours = minutes / 60\n return hours % 1 === 0 ? String(hours) : hours.toFixed(1)\n}\n\nasync function fetchData(settings: HoursByProjectSettings): Promise<WidgetDataResponse> {\n const body = {\n entityType: 'staff:staff_time_entries',\n metric: { field: 'durationMinutes', aggregate: 'sum' },\n groupBy: { field: 'timeProjectId', limit: 20, resolveLabels: true },\n dateRange: { field: 'date', preset: settings.dateRange },\n }\n\n const res = await apiCall<WidgetDataResponse>('/api/dashboards/widgets/data', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = (res.result as Record<string, unknown>)?.error\n throw new Error(typeof err === 'string' ? err : 'Failed to fetch data')\n }\n\n return res.result as WidgetDataResponse\n}\n\nconst HoursByProjectWidget: React.FC<DashboardWidgetComponentProps<HoursByProjectSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateSettings(settings), [settings])\n const [data, setData] = React.useState<WidgetDataItem[]>([])\n const [totalMinutes, setTotalMinutes] = React.useState(0)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const result = await fetchData(hydrated)\n const sorted = [...result.data].sort((a, b) => (b.value ?? 0) - (a.value ?? 0))\n setData(sorted)\n setTotalMinutes(sorted.reduce((sum, item) => sum + (item.value ?? 0), 0))\n } catch (err) {\n console.error('staff.timesheets.hoursByProject', err)\n setError(t('staff.timesheets.widgets.hoursByProject.error', 'Failed to load data'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n void refresh()\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <DateRangeSelect\n id=\"hours-by-project-date-range\"\n label={t('staff.timesheets.widgets.hoursByProject.settings.dateRange', 'Date Range')}\n value={hydrated.dateRange}\n onChange={(dateRange: DateRangePreset) => onSettingsChange({ ...hydrated, dateRange })}\n />\n </div>\n )\n }\n\n if (loading) {\n return (\n <div className=\"flex h-full items-center justify-center py-8\">\n <p className=\"text-sm text-muted-foreground\">{t('staff.timesheets.widgets.hoursByProject.loading', 'Loading...')}</p>\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center py-8\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n )\n }\n\n const maxValue = data.length > 0 ? Math.max(...data.map((d) => d.value ?? 0)) : 0\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-end\">\n <InlineDateRangeSelect\n value={hydrated.dateRange}\n onChange={(dateRange) => onSettingsChange({ ...hydrated, dateRange })}\n />\n </div>\n\n {data.length === 0 ? (\n <p className=\"py-4 text-center text-sm text-muted-foreground\">\n {t('staff.timesheets.widgets.hoursByProject.empty', 'No hours tracked in this period.')}\n </p>\n ) : (\n <div className=\"space-y-2.5\">\n {data.map((item) => {\n const barWidth = maxValue > 0 ? ((item.value ?? 0) / maxValue) * 100 : 0\n return (\n <div key={item.groupKey} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"truncate font-medium\">{item.groupLabel || item.groupKey}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">{minutesToHours(item.value ?? 0)} h</span>\n </div>\n <div className=\"h-2 w-full rounded-full bg-muted\">\n <div\n className=\"h-2 rounded-full bg-primary transition-all\"\n style={{ width: `${barWidth}%` }}\n />\n </div>\n </div>\n )\n })}\n\n <div className=\"flex items-center justify-between border-t pt-2 text-sm font-semibold\">\n <span>{t('staff.timesheets.widgets.hoursByProject.total', 'Total')}</span>\n <span className=\"tabular-nums\">{minutesToHours(totalMinutes)} h</span>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default HoursByProjectWidget\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { lazyDashboardWidget } from "@open-mercato/shared/modules/dashboard/widgets";
|
|
2
|
+
import { DEFAULT_SETTINGS, hydrateSettings } from "./config.js";
|
|
3
|
+
const HoursByProjectWidget = lazyDashboardWidget(() => import("./widget.client.js"));
|
|
4
|
+
const widget = {
|
|
5
|
+
metadata: {
|
|
6
|
+
id: "staff.timesheets.hoursByProject",
|
|
7
|
+
title: "Hours by Project",
|
|
8
|
+
description: "Tracked hours grouped by project for a selected period",
|
|
9
|
+
features: ["dashboards.view", "analytics.view", "staff.timesheets.view"],
|
|
10
|
+
defaultSize: "md",
|
|
11
|
+
defaultEnabled: false,
|
|
12
|
+
defaultSettings: DEFAULT_SETTINGS,
|
|
13
|
+
tags: ["analytics", "staff", "timesheets"],
|
|
14
|
+
category: "analytics",
|
|
15
|
+
icon: "clock",
|
|
16
|
+
supportsRefresh: true
|
|
17
|
+
},
|
|
18
|
+
Widget: HoursByProjectWidget,
|
|
19
|
+
hydrateSettings,
|
|
20
|
+
dehydrateSettings: (s) => ({ dateRange: s.dateRange })
|
|
21
|
+
};
|
|
22
|
+
var widget_default = widget;
|
|
23
|
+
export {
|
|
24
|
+
widget_default as default
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts"],
|
|
4
|
+
"sourcesContent": ["import { lazyDashboardWidget, type DashboardWidgetModule } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { DEFAULT_SETTINGS, hydrateSettings, type HoursByProjectSettings } from './config'\n\nconst HoursByProjectWidget = lazyDashboardWidget(() => import('./widget.client'))\n\nconst widget: DashboardWidgetModule<HoursByProjectSettings> = {\n metadata: {\n id: 'staff.timesheets.hoursByProject',\n title: 'Hours by Project',\n description: 'Tracked hours grouped by project for a selected period',\n features: ['dashboards.view', 'analytics.view', 'staff.timesheets.view'],\n defaultSize: 'md',\n defaultEnabled: false,\n defaultSettings: DEFAULT_SETTINGS,\n tags: ['analytics', 'staff', 'timesheets'],\n category: 'analytics',\n icon: 'clock',\n supportsRefresh: true,\n },\n Widget: HoursByProjectWidget,\n hydrateSettings,\n dehydrateSettings: (s) => ({ dateRange: s.dateRange }),\n}\n\nexport default widget\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,2BAAuD;AAChE,SAAS,kBAAkB,uBAAoD;AAE/E,MAAM,uBAAuB,oBAAoB,MAAM,OAAO,iBAAiB,CAAC;AAEhF,MAAM,SAAwD;AAAA,EAC5D,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,mBAAmB,kBAAkB,uBAAuB;AAAA,IACvE,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,MAAM,CAAC,aAAa,SAAS,YAAY;AAAA,IACzC,UAAU;AAAA,IACV,MAAM;AAAA,IACN,iBAAiB;AAAA,EACnB;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU;AACtD;AAEA,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const DEFAULT_SETTINGS = {
|
|
2
|
+
lastProjectId: null
|
|
3
|
+
};
|
|
4
|
+
function hydrateSettings(raw) {
|
|
5
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULT_SETTINGS };
|
|
6
|
+
const obj = raw;
|
|
7
|
+
return {
|
|
8
|
+
lastProjectId: typeof obj.lastProjectId === "string" ? obj.lastProjectId : null
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
DEFAULT_SETTINGS,
|
|
13
|
+
hydrateSettings
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts"],
|
|
4
|
+
"sourcesContent": ["export type TimeReportingSettings = {\n lastProjectId: string | null\n}\n\nexport const DEFAULT_SETTINGS: TimeReportingSettings = {\n lastProjectId: null,\n}\n\nexport function hydrateSettings(raw: unknown): TimeReportingSettings {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_SETTINGS }\n const obj = raw as Record<string, unknown>\n return {\n lastProjectId: typeof obj.lastProjectId === 'string' ? obj.lastProjectId : null,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAIO,MAAM,mBAA0C;AAAA,EACrD,eAAe;AACjB;AAEO,SAAS,gBAAgB,KAAqC;AACnE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,EAAE,GAAG,iBAAiB;AAClE,QAAM,MAAM;AACZ,SAAO;AAAA,IACL,eAAe,OAAO,IAAI,kBAAkB,WAAW,IAAI,gBAAgB;AAAA,EAC7E;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|