@open-mercato/core 0.6.8-develop.7029.1.a1bb3363af → 0.6.8-develop.7031.1.005201cd70
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/dist/modules/api_keys/backend/api-keys/page.js +3 -1
- package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/auth/backend/roles/page.js +3 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +2 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/business_rules/backend/logs/page.js +3 -1
- package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/page.js +3 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/page.js +3 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
- package/dist/modules/catalog/ai-agents.js +1 -1
- package/dist/modules/catalog/ai-agents.js.map +1 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
- package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
- package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
- package/dist/modules/configs/lib/system-status.js +9 -0
- package/dist/modules/configs/lib/system-status.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +3 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +3 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
- package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/deals-pack.js +4 -1
- package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
- package/dist/modules/customers/ai-tools/people-pack.js +4 -1
- package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
- package/dist/modules/customers/api/deals/map/route.js +2 -1
- package/dist/modules/customers/api/deals/map/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -1
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +5 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -1
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
- package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/devices/backend/devices/page.js +3 -1
- package/dist/modules/devices/backend/devices/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
- package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -2
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
- package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
- package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +4 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
- package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +108 -48
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -1
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -0
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +3 -0
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/page.js +3 -0
- package/dist/modules/warranty_claims/backend/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
- package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
- package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +3 -0
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js +4 -0
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/page.js +3 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
- package/dist/modules/workflows/backend/events/page.js +3 -1
- package/dist/modules/workflows/backend/events/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +3 -1
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
- package/src/modules/auth/backend/roles/page.tsx +4 -2
- package/src/modules/auth/backend/users/page.tsx +3 -2
- package/src/modules/business_rules/backend/logs/page.tsx +4 -1
- package/src/modules/business_rules/backend/rules/page.tsx +4 -1
- package/src/modules/business_rules/backend/sets/page.tsx +4 -1
- package/src/modules/catalog/ai-agents.ts +1 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
- package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/ko.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
- package/src/modules/configs/i18n/de.json +2 -0
- package/src/modules/configs/i18n/en.json +2 -0
- package/src/modules/configs/i18n/es.json +2 -0
- package/src/modules/configs/i18n/ko.json +2 -0
- package/src/modules/configs/i18n/pl.json +2 -0
- package/src/modules/configs/lib/system-status.ts +9 -0
- package/src/modules/currencies/backend/currencies/page.tsx +4 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +4 -1
- package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
- package/src/modules/customers/ai-tools/deals-pack.ts +4 -1
- package/src/modules/customers/ai-tools/people-pack.ts +4 -1
- package/src/modules/customers/api/deals/map/route.ts +1 -0
- package/src/modules/customers/backend/customers/companies/page.tsx +4 -1
- package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
- package/src/modules/customers/backend/customers/people/page.tsx +4 -1
- package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
- package/src/modules/devices/backend/devices/page.tsx +4 -1
- package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
- package/src/modules/entities/api/records.ts +2 -0
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
- package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
- package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
- package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
- package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +4 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
- package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
- package/src/modules/query_index/lib/engine.ts +156 -53
- package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +5 -0
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
- package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
- package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
- package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
- package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
- package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
- package/src/modules/wms/commands/inventory-actions.ts +3 -0
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -0
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
- package/src/modules/workflows/backend/definitions/page.tsx +4 -1
- package/src/modules/workflows/backend/events/page.tsx +4 -1
- package/src/modules/workflows/backend/instances/page.tsx +4 -1
- package/src/modules/workflows/backend/tasks/page.tsx +4 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/workflows/backend/instances/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/workflows/extension-points'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\n\ntype WorkflowInstance = {\n id: string\n definitionId: string\n workflowId: string\n version: number\n status: 'RUNNING' | 'PAUSED' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'COMPENSATING' | 'COMPENSATED'\n currentStepId: string\n correlationKey: string | null\n startedAt: string\n completedAt: string | null\n cancelledAt: string | null\n errorMessage: string | null\n retryCount: number\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\ntype InstancesResponse = {\n data: WorkflowInstance[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n }\n}\n\nexport default function WorkflowInstancesListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-instances', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.status) params.set('status', filterValues.status as string)\n if (filterValues.workflowId) params.set('workflowId', filterValues.workflowId as string)\n if (filterValues.correlationKey) params.set('correlationKey', filterValues.correlationKey as string)\n if (filterValues.entityType) params.set('entityType', filterValues.entityType as string)\n if (filterValues.entityId) params.set('entityId', filterValues.entityId as string)\n\n const result = await apiCall<InstancesResponse>(\n `/api/workflows/instances?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch workflow instances')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n }\n\n return response?.data || []\n },\n })\n\n const handleCancel = async (id: string, workflowId: string) => {\n const confirmed = await confirmDialog({\n title: t('workflows.instances.confirm.cancel', { id: workflowId }),\n variant: 'destructive',\n })\n if (!confirmed) {\n return\n }\n\n const result = await apiCall(`/api/workflows/instances/${id}/cancel`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.instances.messages.cancelled'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })\n } else {\n flash(t('workflows.instances.messages.cancelFailed'), 'error')\n }\n }\n\n const handleRetry = async (id: string, workflowId: string) => {\n const ok = await confirmDialog({\n title: t('workflows.instances.confirm.retry', { id: workflowId }),\n variant: 'default',\n })\n if (!ok) {\n return\n }\n\n const result = await apiCall(`/api/workflows/instances/${id}/retry`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.instances.messages.retried'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })\n } else {\n flash(t('workflows.instances.messages.retryFailed'), 'error')\n }\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const getStatusBadgeClass = (status: WorkflowInstance['status']) => {\n switch (status) {\n case 'RUNNING':\n return 'bg-status-info-bg text-status-info-text'\n case 'PAUSED':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'COMPLETED':\n return 'bg-status-success-bg text-status-success-text'\n case 'FAILED':\n return 'bg-status-error-bg text-status-error-text'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n case 'COMPENSATING':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'COMPENSATED':\n return 'bg-status-neutral-bg text-status-neutral-text'\n default:\n return 'bg-muted text-muted-foreground'\n }\n }\n\n const filters: FilterDef[] = [\n {\n id: 'status',\n type: 'select',\n label: t('workflows.instances.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.instances.status.RUNNING'), value: 'RUNNING' },\n { label: t('workflows.instances.status.PAUSED'), value: 'PAUSED' },\n { label: t('workflows.instances.status.COMPLETED'), value: 'COMPLETED' },\n { label: t('workflows.instances.status.FAILED'), value: 'FAILED' },\n { label: t('workflows.instances.status.CANCELLED'), value: 'CANCELLED' },\n { label: t('workflows.instances.status.COMPENSATING'), value: 'COMPENSATING' },\n { label: t('workflows.instances.status.COMPENSATED'), value: 'COMPENSATED' },\n ],\n },\n {\n id: 'workflowId',\n type: 'text',\n label: t('workflows.instances.filters.workflowId'),\n placeholder: t('workflows.instances.filters.workflowIdPlaceholder'),\n },\n {\n id: 'correlationKey',\n type: 'text',\n label: t('workflows.instances.filters.correlationKey'),\n placeholder: t('workflows.instances.filters.correlationKeyPlaceholder'),\n },\n {\n id: 'entityType',\n type: 'text',\n label: t('workflows.instances.filters.entityType'),\n placeholder: t('workflows.instances.filters.entityTypePlaceholder'),\n },\n {\n id: 'entityId',\n type: 'text',\n label: t('workflows.instances.filters.entityId'),\n placeholder: t('workflows.instances.filters.entityIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<WorkflowInstance>[] = [\n {\n id: 'workflowId',\n header: t('workflows.instances.fields.workflowId'),\n accessorKey: 'workflowId',\n cell: ({ row }) => (\n <Link href={`/backend/instances/${row.original.id}`} className=\"block hover:underline\">\n <div className=\"font-mono text-sm font-medium\">{row.original.workflowId}</div>\n {row.original.correlationKey && (\n <div className=\"text-xs text-muted-foreground\">\n {t('workflows.instances.fields.correlationKey')}: {row.original.correlationKey}\n </div>\n )}\n </Link>\n ),\n },\n {\n id: 'status',\n header: t('workflows.instances.fields.status'),\n accessorKey: 'status',\n cell: ({ row }) => (\n <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(row.original.status)}`}>\n {t(`workflows.instances.status.${row.original.status}`)}\n </span>\n ),\n },\n {\n id: 'currentStep',\n header: t('workflows.instances.fields.currentStep'),\n accessorKey: 'currentStepId',\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground\">{row.original.currentStepId}</span>\n ),\n },\n {\n id: 'timing',\n header: t('workflows.instances.fields.timing'),\n cell: ({ row }) => {\n const started = new Date(row.original.startedAt)\n const completed = row.original.completedAt ? new Date(row.original.completedAt) : null\n const duration = completed ? completed.getTime() - started.getTime() : Date.now() - started.getTime()\n const durationText = duration < 60000\n ? `${Math.floor(duration / 1000)}s`\n : `${Math.floor(duration / 60000)}m`\n\n return (\n <div className=\"text-sm\">\n <div className=\"text-foreground\">{started.toLocaleString()}</div>\n <div className=\"text-xs text-muted-foreground\">\n {completed ? t('workflows.instances.duration') : t('workflows.instances.elapsed')}: {durationText}\n </div>\n </div>\n )\n },\n },\n {\n id: 'retryCount',\n header: t('workflows.instances.fields.retryCount'),\n accessorKey: 'retryCount',\n cell: ({ row }) => (\n <span className={`text-sm ${row.original.retryCount > 0 ? 'text-status-warning-text font-medium' : 'text-muted-foreground'}`}>\n {row.original.retryCount}\n </span>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n const items: Array<{ id: string; label: string; href?: string; onSelect?: () => void }> = [\n {\n id: 'view',\n label: t('workflows.instances.actions.viewDetails'),\n href: `/backend/instances/${row.original.id}`,\n },\n ]\n\n if (row.original.status === 'RUNNING' || row.original.status === 'PAUSED') {\n items.push({\n id: 'cancel',\n label: t('workflows.instances.actions.cancel'),\n onSelect: () => void handleCancel(row.original.id, row.original.workflowId),\n })\n }\n\n if (row.original.status === 'FAILED') {\n items.push({\n id: 'retry',\n label: t('workflows.instances.actions.retry'),\n onSelect: () => void handleRetry(row.original.id, row.original.workflowId),\n })\n }\n\n return <RowActions items={items} />\n },\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-8 text-center\">\n <p className=\"text-status-error-text\">{t('workflows.instances.messages.loadFailed')}</p>\n <Button onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })} className=\"mt-4\">\n {t('common.retry')}\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.instances.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n perspective={{\n tableId: extensionPoints.hosts.instancesTable.tableId,\n }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/workflows/extension-points'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\n\ntype WorkflowInstance = {\n id: string\n definitionId: string\n workflowId: string\n version: number\n status: 'RUNNING' | 'PAUSED' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'COMPENSATING' | 'COMPENSATED'\n currentStepId: string\n correlationKey: string | null\n startedAt: string\n completedAt: string | null\n cancelledAt: string | null\n errorMessage: string | null\n retryCount: number\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\ntype InstancesResponse = {\n data: WorkflowInstance[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n totalIsCapped?: boolean\n }\n}\n\nexport default function WorkflowInstancesListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-instances', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.status) params.set('status', filterValues.status as string)\n if (filterValues.workflowId) params.set('workflowId', filterValues.workflowId as string)\n if (filterValues.correlationKey) params.set('correlationKey', filterValues.correlationKey as string)\n if (filterValues.entityType) params.set('entityType', filterValues.entityType as string)\n if (filterValues.entityId) params.set('entityId', filterValues.entityId as string)\n\n const result = await apiCall<InstancesResponse>(\n `/api/workflows/instances?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch workflow instances')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n setTotalIsCapped(response.pagination?.totalIsCapped === true)\n }\n\n return response?.data || []\n },\n })\n\n const handleCancel = async (id: string, workflowId: string) => {\n const confirmed = await confirmDialog({\n title: t('workflows.instances.confirm.cancel', { id: workflowId }),\n variant: 'destructive',\n })\n if (!confirmed) {\n return\n }\n\n const result = await apiCall(`/api/workflows/instances/${id}/cancel`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.instances.messages.cancelled'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })\n } else {\n flash(t('workflows.instances.messages.cancelFailed'), 'error')\n }\n }\n\n const handleRetry = async (id: string, workflowId: string) => {\n const ok = await confirmDialog({\n title: t('workflows.instances.confirm.retry', { id: workflowId }),\n variant: 'default',\n })\n if (!ok) {\n return\n }\n\n const result = await apiCall(`/api/workflows/instances/${id}/retry`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.instances.messages.retried'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })\n } else {\n flash(t('workflows.instances.messages.retryFailed'), 'error')\n }\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const getStatusBadgeClass = (status: WorkflowInstance['status']) => {\n switch (status) {\n case 'RUNNING':\n return 'bg-status-info-bg text-status-info-text'\n case 'PAUSED':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'COMPLETED':\n return 'bg-status-success-bg text-status-success-text'\n case 'FAILED':\n return 'bg-status-error-bg text-status-error-text'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n case 'COMPENSATING':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'COMPENSATED':\n return 'bg-status-neutral-bg text-status-neutral-text'\n default:\n return 'bg-muted text-muted-foreground'\n }\n }\n\n const filters: FilterDef[] = [\n {\n id: 'status',\n type: 'select',\n label: t('workflows.instances.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.instances.status.RUNNING'), value: 'RUNNING' },\n { label: t('workflows.instances.status.PAUSED'), value: 'PAUSED' },\n { label: t('workflows.instances.status.COMPLETED'), value: 'COMPLETED' },\n { label: t('workflows.instances.status.FAILED'), value: 'FAILED' },\n { label: t('workflows.instances.status.CANCELLED'), value: 'CANCELLED' },\n { label: t('workflows.instances.status.COMPENSATING'), value: 'COMPENSATING' },\n { label: t('workflows.instances.status.COMPENSATED'), value: 'COMPENSATED' },\n ],\n },\n {\n id: 'workflowId',\n type: 'text',\n label: t('workflows.instances.filters.workflowId'),\n placeholder: t('workflows.instances.filters.workflowIdPlaceholder'),\n },\n {\n id: 'correlationKey',\n type: 'text',\n label: t('workflows.instances.filters.correlationKey'),\n placeholder: t('workflows.instances.filters.correlationKeyPlaceholder'),\n },\n {\n id: 'entityType',\n type: 'text',\n label: t('workflows.instances.filters.entityType'),\n placeholder: t('workflows.instances.filters.entityTypePlaceholder'),\n },\n {\n id: 'entityId',\n type: 'text',\n label: t('workflows.instances.filters.entityId'),\n placeholder: t('workflows.instances.filters.entityIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<WorkflowInstance>[] = [\n {\n id: 'workflowId',\n header: t('workflows.instances.fields.workflowId'),\n accessorKey: 'workflowId',\n cell: ({ row }) => (\n <Link href={`/backend/instances/${row.original.id}`} className=\"block hover:underline\">\n <div className=\"font-mono text-sm font-medium\">{row.original.workflowId}</div>\n {row.original.correlationKey && (\n <div className=\"text-xs text-muted-foreground\">\n {t('workflows.instances.fields.correlationKey')}: {row.original.correlationKey}\n </div>\n )}\n </Link>\n ),\n },\n {\n id: 'status',\n header: t('workflows.instances.fields.status'),\n accessorKey: 'status',\n cell: ({ row }) => (\n <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(row.original.status)}`}>\n {t(`workflows.instances.status.${row.original.status}`)}\n </span>\n ),\n },\n {\n id: 'currentStep',\n header: t('workflows.instances.fields.currentStep'),\n accessorKey: 'currentStepId',\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground\">{row.original.currentStepId}</span>\n ),\n },\n {\n id: 'timing',\n header: t('workflows.instances.fields.timing'),\n cell: ({ row }) => {\n const started = new Date(row.original.startedAt)\n const completed = row.original.completedAt ? new Date(row.original.completedAt) : null\n const duration = completed ? completed.getTime() - started.getTime() : Date.now() - started.getTime()\n const durationText = duration < 60000\n ? `${Math.floor(duration / 1000)}s`\n : `${Math.floor(duration / 60000)}m`\n\n return (\n <div className=\"text-sm\">\n <div className=\"text-foreground\">{started.toLocaleString()}</div>\n <div className=\"text-xs text-muted-foreground\">\n {completed ? t('workflows.instances.duration') : t('workflows.instances.elapsed')}: {durationText}\n </div>\n </div>\n )\n },\n },\n {\n id: 'retryCount',\n header: t('workflows.instances.fields.retryCount'),\n accessorKey: 'retryCount',\n cell: ({ row }) => (\n <span className={`text-sm ${row.original.retryCount > 0 ? 'text-status-warning-text font-medium' : 'text-muted-foreground'}`}>\n {row.original.retryCount}\n </span>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n const items: Array<{ id: string; label: string; href?: string; onSelect?: () => void }> = [\n {\n id: 'view',\n label: t('workflows.instances.actions.viewDetails'),\n href: `/backend/instances/${row.original.id}`,\n },\n ]\n\n if (row.original.status === 'RUNNING' || row.original.status === 'PAUSED') {\n items.push({\n id: 'cancel',\n label: t('workflows.instances.actions.cancel'),\n onSelect: () => void handleCancel(row.original.id, row.original.workflowId),\n })\n }\n\n if (row.original.status === 'FAILED') {\n items.push({\n id: 'retry',\n label: t('workflows.instances.actions.retry'),\n onSelect: () => void handleRetry(row.original.id, row.original.workflowId),\n })\n }\n\n return <RowActions items={items} />\n },\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-8 text-center\">\n <p className=\"text-status-error-text\">{t('workflows.instances.messages.loadFailed')}</p>\n <Button onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-instances'] })} className=\"mt-4\">\n {t('common.retry')}\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.instances.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n perspective={{\n tableId: extensionPoints.hosts.instancesTable.tableId,\n }}\n pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -17,6 +17,7 @@ function UserTasksListPage() {
|
|
|
17
17
|
const [pageSize] = React.useState(50);
|
|
18
18
|
const [total, setTotal] = React.useState(0);
|
|
19
19
|
const [totalPages, setTotalPages] = React.useState(1);
|
|
20
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false);
|
|
20
21
|
const t = useT();
|
|
21
22
|
const router = useRouter();
|
|
22
23
|
const queryClient = useQueryClient();
|
|
@@ -46,6 +47,7 @@ function UserTasksListPage() {
|
|
|
46
47
|
setTotal(response.pagination.total || 0);
|
|
47
48
|
const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize);
|
|
48
49
|
setTotalPages(calculatedPages || 1);
|
|
50
|
+
setTotalIsCapped(response.pagination?.totalIsCapped === true);
|
|
49
51
|
}
|
|
50
52
|
return response?.data || [];
|
|
51
53
|
}
|
|
@@ -247,7 +249,7 @@ function UserTasksListPage() {
|
|
|
247
249
|
perspective: {
|
|
248
250
|
tableId: extensionPoints.hosts.tasksTable.tableId
|
|
249
251
|
},
|
|
250
|
-
pagination: { page, pageSize, total, totalPages, onPageChange: setPage }
|
|
252
|
+
pagination: { page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }
|
|
251
253
|
}
|
|
252
254
|
) }),
|
|
253
255
|
ConfirmDialogElement
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/workflows/backend/tasks/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/workflows/extension-points'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\n\ntype UserTaskStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED'\n\ntype UserTask = {\n id: string\n workflowInstanceId: string\n stepInstanceId: string\n taskName: string\n description: string | null\n status: UserTaskStatus\n formSchema: any | null\n formData: any | null\n assignedTo: string | null\n assignedToRoles: string[] | null\n claimedBy: string | null\n claimedAt: string | null\n dueDate: string | null\n escalatedAt: string | null\n escalatedTo: string | null\n completedBy: string | null\n completedAt: string | null\n comments: string | null\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\ntype TasksResponse = {\n data: UserTask[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n }\n}\n\nexport default function UserTasksListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({\n myTasks: 'true', // Default to \"My Tasks\" view\n })\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-tasks', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.status) params.set('status', filterValues.status as string)\n if (filterValues.overdue === 'true') params.set('overdue', 'true')\n if (filterValues.workflowInstanceId) params.set('workflowInstanceId', filterValues.workflowInstanceId as string)\n\n const result = await apiCall<TasksResponse>(\n `/api/workflows/tasks?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch user tasks')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n }\n\n return response?.data || []\n },\n })\n\n const handleClaim = async (id: string, taskName: string) => {\n const confirmed = await confirmDialog({\n title: t('workflows.tasks.confirm.claim', { name: taskName }),\n variant: 'default',\n })\n if (!confirmed) {\n return\n }\n\n const result = await apiCall(`/api/workflows/tasks/${id}/claim`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.tasks.messages.claimed'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-tasks'] })\n } else {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n }\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({ myTasks: 'true' })\n setPage(1)\n }, [])\n\n const getStatusBadgeClass = (status: UserTaskStatus) => {\n switch (status) {\n case 'PENDING':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'IN_PROGRESS':\n return 'bg-status-info-bg text-status-info-text'\n case 'COMPLETED':\n return 'bg-status-success-bg text-status-success-text'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n default:\n return 'bg-muted text-muted-foreground'\n }\n }\n\n const isOverdue = (task: UserTask) => {\n if (!task.dueDate || task.status === 'COMPLETED' || task.status === 'CANCELLED') {\n return false\n }\n return new Date(task.dueDate) < new Date()\n }\n\n const filters: FilterDef[] = [\n {\n id: 'status',\n type: 'select',\n label: t('workflows.tasks.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.tasks.statuses.PENDING'), value: 'PENDING' },\n { label: t('workflows.tasks.statuses.IN_PROGRESS'), value: 'IN_PROGRESS' },\n { label: t('workflows.tasks.statuses.COMPLETED'), value: 'COMPLETED' },\n { label: t('workflows.tasks.statuses.CANCELLED'), value: 'CANCELLED' },\n ],\n },\n {\n id: 'myTasks',\n type: 'select',\n label: t('workflows.tasks.filters.view'),\n options: [\n { label: t('workflows.tasks.filters.myTasks'), value: 'true' },\n { label: t('workflows.tasks.filters.allTasks'), value: '' },\n ],\n },\n {\n id: 'overdue',\n type: 'select',\n label: t('workflows.tasks.filters.overdue'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.tasks.filters.overdueOnly'), value: 'true' },\n ],\n },\n {\n id: 'workflowInstanceId',\n type: 'text',\n label: t('workflows.tasks.filters.workflowInstanceId'),\n placeholder: t('workflows.tasks.filters.workflowInstanceIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<UserTask>[] = [\n {\n id: 'taskName',\n header: t('workflows.tasks.fields.taskName'),\n accessorKey: 'taskName',\n cell: ({ row }) => (\n <div>\n <div className=\"font-medium text-sm\">{row.original.taskName}</div>\n {row.original.description && (\n <div className=\"text-xs text-muted-foreground line-clamp-1\">\n {row.original.description}\n </div>\n )}\n {isOverdue(row.original) && (\n <div className=\"text-xs text-status-error-text font-medium mt-1\">\n {t('workflows.tasks.overdue')}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'status',\n header: t('workflows.tasks.fields.status'),\n accessorKey: 'status',\n cell: ({ row }) => (\n <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(row.original.status)}`}>\n {t(`workflows.tasks.statuses.${row.original.status}`)}\n </span>\n ),\n },\n {\n id: 'assignment',\n header: t('workflows.tasks.fields.assignment'),\n cell: ({ row }) => {\n if (row.original.claimedBy) {\n return (\n <div className=\"text-sm\">\n <div className=\"text-foreground\">{t('workflows.tasks.claimedBy')}: {row.original.claimedBy}</div>\n </div>\n )\n }\n if (row.original.assignedTo) {\n return <div className=\"text-sm text-foreground\">{row.original.assignedTo}</div>\n }\n if (row.original.assignedToRoles && row.original.assignedToRoles.length > 0) {\n return (\n <div className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.roles')}: {row.original.assignedToRoles.join(', ')}\n </div>\n )\n }\n return <span className=\"text-sm text-muted-foreground\">-</span>\n },\n },\n {\n id: 'dueDate',\n header: t('workflows.tasks.fields.dueDate'),\n accessorKey: 'dueDate',\n cell: ({ row }) => {\n if (!row.original.dueDate) {\n return <span className=\"text-sm text-muted-foreground\">-</span>\n }\n const dueDate = new Date(row.original.dueDate)\n const overdue = isOverdue(row.original)\n return (\n <div className={`text-sm ${overdue ? 'text-status-error-text font-medium' : 'text-foreground'}`}>\n {dueDate.toLocaleString()}\n </div>\n )\n },\n },\n {\n id: 'createdAt',\n header: t('workflows.tasks.fields.createdAt'),\n accessorKey: 'createdAt',\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground\">\n {new Date(row.original.createdAt).toLocaleString()}\n </span>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n const items: Array<{ id: string; label: string; href?: string; onSelect?: () => void }> = [\n {\n id: 'view',\n label: t('workflows.tasks.actions.viewDetails'),\n href: `/backend/tasks/${row.original.id}`,\n },\n ]\n\n // Allow claiming if task is PENDING and assigned to roles (not specific user)\n if (\n row.original.status === 'PENDING' &&\n !row.original.assignedTo &&\n row.original.assignedToRoles &&\n row.original.assignedToRoles.length > 0\n ) {\n items.push({\n id: 'claim',\n label: t('workflows.tasks.actions.claim'),\n onSelect: () => void handleClaim(row.original.id, row.original.taskName),\n })\n }\n\n // Allow completing if task is in progress or pending\n if (row.original.status === 'PENDING' || row.original.status === 'IN_PROGRESS') {\n items.push({\n id: 'complete',\n label: t('workflows.tasks.actions.complete'),\n href: `/backend/tasks/${row.original.id}`,\n })\n }\n\n return <RowActions items={items} />\n },\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-8 text-center\">\n <p className=\"text-status-error-text\">{t('workflows.tasks.messages.loadFailed')}</p>\n <Button onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-tasks'] })} className=\"mt-4\">\n {t('common.retry')}\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.tasks.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n perspective={{\n tableId: extensionPoints.hosts.tasksTable.tableId,\n }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/workflows/extension-points'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\n\ntype UserTaskStatus = 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'CANCELLED'\n\ntype UserTask = {\n id: string\n workflowInstanceId: string\n stepInstanceId: string\n taskName: string\n description: string | null\n status: UserTaskStatus\n formSchema: any | null\n formData: any | null\n assignedTo: string | null\n assignedToRoles: string[] | null\n claimedBy: string | null\n claimedAt: string | null\n dueDate: string | null\n escalatedAt: string | null\n escalatedTo: string | null\n completedBy: string | null\n completedAt: string | null\n comments: string | null\n tenantId: string\n organizationId: string\n createdAt: string\n updatedAt: string\n}\n\ntype TasksResponse = {\n data: UserTask[]\n pagination: {\n total: number\n limit: number\n offset: number\n hasMore: boolean\n totalIsCapped?: boolean\n }\n}\n\nexport default function UserTasksListPage() {\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(50)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const t = useT()\n const router = useRouter()\n const queryClient = useQueryClient()\n const { confirm: confirmDialog, ConfirmDialogElement } = useConfirmDialog()\n const [filterValues, setFilterValues] = React.useState<FilterValues>({\n myTasks: 'true', // Default to \"My Tasks\" view\n })\n\n const { data, isLoading, error } = useQuery({\n queryKey: ['workflow-tasks', 'list', filterValues, page],\n queryFn: async () => {\n const params = new URLSearchParams()\n const offset = (page - 1) * pageSize\n params.set('limit', pageSize.toString())\n params.set('offset', offset.toString())\n\n if (filterValues.status) params.set('status', filterValues.status as string)\n if (filterValues.overdue === 'true') params.set('overdue', 'true')\n if (filterValues.workflowInstanceId) params.set('workflowInstanceId', filterValues.workflowInstanceId as string)\n\n const result = await apiCall<TasksResponse>(\n `/api/workflows/tasks?${params.toString()}`\n )\n\n if (!result.ok) {\n throw new Error('Failed to fetch user tasks')\n }\n\n const response = result.result\n if (response?.pagination) {\n setTotal(response.pagination.total || 0)\n const calculatedPages = Math.ceil((response.pagination.total || 0) / pageSize)\n setTotalPages(calculatedPages || 1)\n setTotalIsCapped(response.pagination?.totalIsCapped === true)\n }\n\n return response?.data || []\n },\n })\n\n const handleClaim = async (id: string, taskName: string) => {\n const confirmed = await confirmDialog({\n title: t('workflows.tasks.confirm.claim', { name: taskName }),\n variant: 'default',\n })\n if (!confirmed) {\n return\n }\n\n const result = await apiCall(`/api/workflows/tasks/${id}/claim`, {\n method: 'POST',\n })\n\n if (result.ok) {\n flash(t('workflows.tasks.messages.claimed'), 'success')\n queryClient.invalidateQueries({ queryKey: ['workflow-tasks'] })\n } else {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n }\n }\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n Object.entries(values).forEach(([key, value]) => {\n if (value !== undefined && value !== '') next[key] = value\n })\n setFilterValues(next)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({ myTasks: 'true' })\n setPage(1)\n }, [])\n\n const getStatusBadgeClass = (status: UserTaskStatus) => {\n switch (status) {\n case 'PENDING':\n return 'bg-status-warning-bg text-status-warning-text'\n case 'IN_PROGRESS':\n return 'bg-status-info-bg text-status-info-text'\n case 'COMPLETED':\n return 'bg-status-success-bg text-status-success-text'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n default:\n return 'bg-muted text-muted-foreground'\n }\n }\n\n const isOverdue = (task: UserTask) => {\n if (!task.dueDate || task.status === 'COMPLETED' || task.status === 'CANCELLED') {\n return false\n }\n return new Date(task.dueDate) < new Date()\n }\n\n const filters: FilterDef[] = [\n {\n id: 'status',\n type: 'select',\n label: t('workflows.tasks.filters.status'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.tasks.statuses.PENDING'), value: 'PENDING' },\n { label: t('workflows.tasks.statuses.IN_PROGRESS'), value: 'IN_PROGRESS' },\n { label: t('workflows.tasks.statuses.COMPLETED'), value: 'COMPLETED' },\n { label: t('workflows.tasks.statuses.CANCELLED'), value: 'CANCELLED' },\n ],\n },\n {\n id: 'myTasks',\n type: 'select',\n label: t('workflows.tasks.filters.view'),\n options: [\n { label: t('workflows.tasks.filters.myTasks'), value: 'true' },\n { label: t('workflows.tasks.filters.allTasks'), value: '' },\n ],\n },\n {\n id: 'overdue',\n type: 'select',\n label: t('workflows.tasks.filters.overdue'),\n options: [\n { label: t('common.all'), value: '' },\n { label: t('workflows.tasks.filters.overdueOnly'), value: 'true' },\n ],\n },\n {\n id: 'workflowInstanceId',\n type: 'text',\n label: t('workflows.tasks.filters.workflowInstanceId'),\n placeholder: t('workflows.tasks.filters.workflowInstanceIdPlaceholder'),\n },\n ]\n\n const columns: ColumnDef<UserTask>[] = [\n {\n id: 'taskName',\n header: t('workflows.tasks.fields.taskName'),\n accessorKey: 'taskName',\n cell: ({ row }) => (\n <div>\n <div className=\"font-medium text-sm\">{row.original.taskName}</div>\n {row.original.description && (\n <div className=\"text-xs text-muted-foreground line-clamp-1\">\n {row.original.description}\n </div>\n )}\n {isOverdue(row.original) && (\n <div className=\"text-xs text-status-error-text font-medium mt-1\">\n {t('workflows.tasks.overdue')}\n </div>\n )}\n </div>\n ),\n },\n {\n id: 'status',\n header: t('workflows.tasks.fields.status'),\n accessorKey: 'status',\n cell: ({ row }) => (\n <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(row.original.status)}`}>\n {t(`workflows.tasks.statuses.${row.original.status}`)}\n </span>\n ),\n },\n {\n id: 'assignment',\n header: t('workflows.tasks.fields.assignment'),\n cell: ({ row }) => {\n if (row.original.claimedBy) {\n return (\n <div className=\"text-sm\">\n <div className=\"text-foreground\">{t('workflows.tasks.claimedBy')}: {row.original.claimedBy}</div>\n </div>\n )\n }\n if (row.original.assignedTo) {\n return <div className=\"text-sm text-foreground\">{row.original.assignedTo}</div>\n }\n if (row.original.assignedToRoles && row.original.assignedToRoles.length > 0) {\n return (\n <div className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.roles')}: {row.original.assignedToRoles.join(', ')}\n </div>\n )\n }\n return <span className=\"text-sm text-muted-foreground\">-</span>\n },\n },\n {\n id: 'dueDate',\n header: t('workflows.tasks.fields.dueDate'),\n accessorKey: 'dueDate',\n cell: ({ row }) => {\n if (!row.original.dueDate) {\n return <span className=\"text-sm text-muted-foreground\">-</span>\n }\n const dueDate = new Date(row.original.dueDate)\n const overdue = isOverdue(row.original)\n return (\n <div className={`text-sm ${overdue ? 'text-status-error-text font-medium' : 'text-foreground'}`}>\n {dueDate.toLocaleString()}\n </div>\n )\n },\n },\n {\n id: 'createdAt',\n header: t('workflows.tasks.fields.createdAt'),\n accessorKey: 'createdAt',\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground\">\n {new Date(row.original.createdAt).toLocaleString()}\n </span>\n ),\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n const items: Array<{ id: string; label: string; href?: string; onSelect?: () => void }> = [\n {\n id: 'view',\n label: t('workflows.tasks.actions.viewDetails'),\n href: `/backend/tasks/${row.original.id}`,\n },\n ]\n\n // Allow claiming if task is PENDING and assigned to roles (not specific user)\n if (\n row.original.status === 'PENDING' &&\n !row.original.assignedTo &&\n row.original.assignedToRoles &&\n row.original.assignedToRoles.length > 0\n ) {\n items.push({\n id: 'claim',\n label: t('workflows.tasks.actions.claim'),\n onSelect: () => void handleClaim(row.original.id, row.original.taskName),\n })\n }\n\n // Allow completing if task is in progress or pending\n if (row.original.status === 'PENDING' || row.original.status === 'IN_PROGRESS') {\n items.push({\n id: 'complete',\n label: t('workflows.tasks.actions.complete'),\n href: `/backend/tasks/${row.original.id}`,\n })\n }\n\n return <RowActions items={items} />\n },\n },\n ]\n\n if (error) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-8 text-center\">\n <p className=\"text-status-error-text\">{t('workflows.tasks.messages.loadFailed')}</p>\n <Button onClick={() => queryClient.invalidateQueries({ queryKey: ['workflow-tasks'] })} className=\"mt-4\">\n {t('common.retry')}\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('workflows.tasks.list.title')}\n columns={columns}\n data={data || []}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n perspective={{\n tableId: extensionPoints.hosts.tasksTable.tableId,\n }}\n pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7031.1.005201cd70",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
256
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
257
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7031.1.005201cd70",
|
|
256
|
+
"@open-mercato/shared": "0.6.8-develop.7031.1.005201cd70",
|
|
257
|
+
"@open-mercato/ui": "0.6.8-develop.7031.1.005201cd70",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
263
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
264
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7031.1.005201cd70",
|
|
263
|
+
"@open-mercato/shared": "0.6.8-develop.7031.1.005201cd70",
|
|
264
|
+
"@open-mercato/ui": "0.6.8-develop.7031.1.005201cd70",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -36,6 +36,7 @@ type ResponsePayload = {
|
|
|
36
36
|
total: number
|
|
37
37
|
page: number
|
|
38
38
|
totalPages: number
|
|
39
|
+
totalIsCapped?: boolean
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
function formatDate(value: string | null, t: (key: string, params?: Record<string, string | number>) => string) {
|
|
@@ -54,6 +55,7 @@ export default function ApiKeysListPage() {
|
|
|
54
55
|
const [page, setPage] = React.useState(1)
|
|
55
56
|
const [total, setTotal] = React.useState(0)
|
|
56
57
|
const [totalPages, setTotalPages] = React.useState(1)
|
|
58
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false)
|
|
57
59
|
const [search, setSearch] = React.useState('')
|
|
58
60
|
const [isLoading, setIsLoading] = React.useState(true)
|
|
59
61
|
const [reloadToken, setReloadToken] = React.useState(0)
|
|
@@ -87,6 +89,7 @@ export default function ApiKeysListPage() {
|
|
|
87
89
|
setRows(Array.isArray(payload.items) ? payload.items : [])
|
|
88
90
|
setTotal(payload.total || 0)
|
|
89
91
|
setTotalPages(payload.totalPages || 1)
|
|
92
|
+
setTotalIsCapped(payload?.totalIsCapped === true)
|
|
90
93
|
}
|
|
91
94
|
} catch (error) {
|
|
92
95
|
if (!cancelled) {
|
|
@@ -198,7 +201,7 @@ export default function ApiKeysListPage() {
|
|
|
198
201
|
createLabel={t('api_keys.list.actions.create')}
|
|
199
202
|
/>
|
|
200
203
|
)}
|
|
201
|
-
pagination={{ page, pageSize: 20, total, totalPages, onPageChange: setPage }}
|
|
204
|
+
pagination={{ page, pageSize: 20, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
202
205
|
isLoading={isLoading}
|
|
203
206
|
/>
|
|
204
207
|
</PageBody>
|
|
@@ -42,6 +42,7 @@ type AttachmentLibraryResponse = {
|
|
|
42
42
|
pageSize: number
|
|
43
43
|
total: number
|
|
44
44
|
totalPages: number
|
|
45
|
+
totalIsCapped?: boolean
|
|
45
46
|
availableTags: string[]
|
|
46
47
|
partitions: Array<{ code: string; title: string; description?: string | null; isPublic?: boolean }>
|
|
47
48
|
error?: string
|
|
@@ -1054,6 +1055,7 @@ export function AttachmentLibrary() {
|
|
|
1054
1055
|
|
|
1055
1056
|
const total = data?.total ?? 0
|
|
1056
1057
|
const totalPages = data?.totalPages ?? 0
|
|
1058
|
+
const totalIsCapped = data?.totalIsCapped === true
|
|
1057
1059
|
return (
|
|
1058
1060
|
<>
|
|
1059
1061
|
<DataTable<AttachmentRow>
|
|
@@ -1154,6 +1156,7 @@ export function AttachmentLibrary() {
|
|
|
1154
1156
|
pageSize: PAGE_SIZE,
|
|
1155
1157
|
total,
|
|
1156
1158
|
totalPages,
|
|
1159
|
+
totalIsCapped,
|
|
1157
1160
|
onPageChange: (next) => setPage(next),
|
|
1158
1161
|
}}
|
|
1159
1162
|
/>
|
|
@@ -21,6 +21,7 @@ type ActionLogResponse = {
|
|
|
21
21
|
pageSize: number
|
|
22
22
|
total: number
|
|
23
23
|
totalPages: number
|
|
24
|
+
totalIsCapped?: boolean
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
type AccessLogResponse = {
|
|
@@ -30,6 +31,7 @@ type AccessLogResponse = {
|
|
|
30
31
|
pageSize: number
|
|
31
32
|
total: number
|
|
32
33
|
totalPages: number
|
|
34
|
+
totalIsCapped?: boolean
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
type TabOption = 'actions' | 'access'
|
|
@@ -48,11 +50,13 @@ export default function AuditLogsPage() {
|
|
|
48
50
|
const [actionsPageSize, setActionsPageSize] = React.useState(DEFAULT_PAGE_SIZE)
|
|
49
51
|
const [actionsTotal, setActionsTotal] = React.useState(0)
|
|
50
52
|
const [actionsTotalPages, setActionsTotalPages] = React.useState(1)
|
|
53
|
+
const [actionsTotalIsCapped, setActionsTotalIsCapped] = React.useState(false)
|
|
51
54
|
const actionsPageSizeRef = React.useRef(DEFAULT_PAGE_SIZE)
|
|
52
55
|
const [accessPage, setAccessPage] = React.useState(1)
|
|
53
56
|
const [accessPageSize, setAccessPageSize] = React.useState(DEFAULT_PAGE_SIZE)
|
|
54
57
|
const [accessTotal, setAccessTotal] = React.useState(0)
|
|
55
58
|
const [accessTotalPages, setAccessTotalPages] = React.useState(1)
|
|
59
|
+
const [accessTotalIsCapped, setAccessTotalIsCapped] = React.useState(false)
|
|
56
60
|
const accessPageSizeRef = React.useRef(DEFAULT_PAGE_SIZE)
|
|
57
61
|
|
|
58
62
|
const fetchActions = React.useCallback(async (page: number, pageSize: number) => {
|
|
@@ -95,6 +99,7 @@ export default function AuditLogsPage() {
|
|
|
95
99
|
})
|
|
96
100
|
setActionsTotal(actionsRes.total ?? (actionsRes.items?.length ?? 0))
|
|
97
101
|
setActionsTotalPages(actionsRes.totalPages ?? 1)
|
|
102
|
+
setActionsTotalIsCapped(actionsRes.totalIsCapped === true)
|
|
98
103
|
setAccessLogs(accessRes.items ?? [])
|
|
99
104
|
const resolvedPage = accessRes.page ?? accessPageNum
|
|
100
105
|
const resolvedPageSize = accessRes.pageSize ?? accessPageSizeNum
|
|
@@ -111,6 +116,7 @@ export default function AuditLogsPage() {
|
|
|
111
116
|
})
|
|
112
117
|
setAccessTotal(resolvedTotal)
|
|
113
118
|
setAccessTotalPages(resolvedTotalPages)
|
|
119
|
+
setAccessTotalIsCapped(accessRes.totalIsCapped === true)
|
|
114
120
|
}, [fetchActions, fetchAccess])
|
|
115
121
|
|
|
116
122
|
const loadWithState = React.useCallback(async (
|
|
@@ -210,6 +216,7 @@ export default function AuditLogsPage() {
|
|
|
210
216
|
pageSize: actionsPageSize,
|
|
211
217
|
total: actionsTotal,
|
|
212
218
|
totalPages: actionsTotalPages,
|
|
219
|
+
totalIsCapped: actionsTotalIsCapped,
|
|
213
220
|
onPageChange: handleActionsPageChange,
|
|
214
221
|
}}
|
|
215
222
|
/>
|
|
@@ -225,6 +232,7 @@ export default function AuditLogsPage() {
|
|
|
225
232
|
pageSize: accessPageSize,
|
|
226
233
|
total: accessTotal,
|
|
227
234
|
totalPages: accessTotalPages,
|
|
235
|
+
totalIsCapped: accessTotalIsCapped,
|
|
228
236
|
onPageChange: handleAccessPageChange,
|
|
229
237
|
}}
|
|
230
238
|
/>
|
|
@@ -33,6 +33,7 @@ export default function RolesListPage() {
|
|
|
33
33
|
const [page, setPage] = React.useState(1)
|
|
34
34
|
const [total, setTotal] = React.useState(0)
|
|
35
35
|
const [totalPages, setTotalPages] = React.useState(1)
|
|
36
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false)
|
|
36
37
|
const [search, setSearch] = React.useState('')
|
|
37
38
|
const [rows, setRows] = React.useState<Row[]>([])
|
|
38
39
|
const [isLoading, setIsLoading] = React.useState(true)
|
|
@@ -55,7 +56,7 @@ export default function RolesListPage() {
|
|
|
55
56
|
items?: Row[]
|
|
56
57
|
total?: number
|
|
57
58
|
totalPages?: number
|
|
58
|
-
isSuperAdmin?: boolean
|
|
59
|
+
isSuperAdmin?: boolean; totalIsCapped?: boolean
|
|
59
60
|
}>(
|
|
60
61
|
`/api/auth/roles?${params.toString()}`,
|
|
61
62
|
undefined,
|
|
@@ -65,6 +66,7 @@ export default function RolesListPage() {
|
|
|
65
66
|
setRows(j.items || [])
|
|
66
67
|
setTotal(j.total || 0)
|
|
67
68
|
setTotalPages(j.totalPages || 1)
|
|
69
|
+
setTotalIsCapped(j?.totalIsCapped === true)
|
|
68
70
|
setIsSuperAdmin(!!j.isSuperAdmin)
|
|
69
71
|
}
|
|
70
72
|
} finally {
|
|
@@ -156,7 +158,7 @@ export default function RolesListPage() {
|
|
|
156
158
|
createLabel={t('auth.roles.list.actions.create', 'Create')}
|
|
157
159
|
/>
|
|
158
160
|
)}
|
|
159
|
-
pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
|
|
161
|
+
pagination={{ page, pageSize: 50, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
160
162
|
isLoading={isLoading}
|
|
161
163
|
/>
|
|
162
164
|
</PageBody>
|
|
@@ -351,7 +351,7 @@ export default function UsersListPage() {
|
|
|
351
351
|
const { data: usersData, isLoading } = useQuery({
|
|
352
352
|
queryKey: ['users', params, scopeVersion],
|
|
353
353
|
queryFn: async () => {
|
|
354
|
-
const call = await apiCall<{ items: Row[]; total: number; totalPages: number; isSuperAdmin?: boolean }>(
|
|
354
|
+
const call = await apiCall<{ items: Row[]; total: number; totalPages: number; totalIsCapped?: boolean; isSuperAdmin?: boolean }>(
|
|
355
355
|
`/api/auth/users?${params}`,
|
|
356
356
|
)
|
|
357
357
|
if (!call.ok) {
|
|
@@ -364,6 +364,7 @@ export default function UsersListPage() {
|
|
|
364
364
|
const rows = usersData?.items || []
|
|
365
365
|
const total = usersData?.total || 0
|
|
366
366
|
const totalPages = usersData?.totalPages || 1
|
|
367
|
+
const totalIsCapped = usersData?.totalIsCapped === true
|
|
367
368
|
const isSuperAdmin = !!usersData?.isSuperAdmin
|
|
368
369
|
const rowsWithOrgNames: Row[] = React.useMemo(() => rows.map(row => ({
|
|
369
370
|
...row,
|
|
@@ -456,7 +457,7 @@ export default function UsersListPage() {
|
|
|
456
457
|
{ id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },
|
|
457
458
|
]} />
|
|
458
459
|
)}
|
|
459
|
-
pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}
|
|
460
|
+
pagination={{ page, pageSize: 50, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
460
461
|
isLoading={isLoading}
|
|
461
462
|
/>
|
|
462
463
|
</PageBody>
|
|
@@ -38,6 +38,7 @@ type LogsResponse = {
|
|
|
38
38
|
items: RuleExecutionLog[]
|
|
39
39
|
total: number
|
|
40
40
|
totalPages: number
|
|
41
|
+
totalIsCapped?: boolean
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
export default function ExecutionLogsPage() {
|
|
@@ -45,6 +46,7 @@ export default function ExecutionLogsPage() {
|
|
|
45
46
|
const [pageSize] = React.useState(50)
|
|
46
47
|
const [total, setTotal] = React.useState(0)
|
|
47
48
|
const [totalPages, setTotalPages] = React.useState(1)
|
|
49
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false)
|
|
48
50
|
const t = useT()
|
|
49
51
|
const [filterValues, setFilterValues] = React.useState<FilterValues>({})
|
|
50
52
|
|
|
@@ -76,6 +78,7 @@ export default function ExecutionLogsPage() {
|
|
|
76
78
|
if (response) {
|
|
77
79
|
setTotal(response.total || 0)
|
|
78
80
|
setTotalPages(response.totalPages || 1)
|
|
81
|
+
setTotalIsCapped(response?.totalIsCapped === true)
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
return response?.items || []
|
|
@@ -246,7 +249,7 @@ export default function ExecutionLogsPage() {
|
|
|
246
249
|
onFiltersClear={handleFiltersClear}
|
|
247
250
|
isLoading={isLoading}
|
|
248
251
|
error={error ? t('business_rules.logs.messages.loadFailed') : undefined}
|
|
249
|
-
pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}
|
|
252
|
+
pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
250
253
|
/>
|
|
251
254
|
</PageBody>
|
|
252
255
|
</Page>
|
|
@@ -42,6 +42,7 @@ type RulesResponse = {
|
|
|
42
42
|
items: Rule[]
|
|
43
43
|
total: number
|
|
44
44
|
totalPages: number
|
|
45
|
+
totalIsCapped?: boolean
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export default function RulesListPage() {
|
|
@@ -49,6 +50,7 @@ export default function RulesListPage() {
|
|
|
49
50
|
const [pageSize] = React.useState(20)
|
|
50
51
|
const [total, setTotal] = React.useState(0)
|
|
51
52
|
const [totalPages, setTotalPages] = React.useState(1)
|
|
53
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false)
|
|
52
54
|
const t = useT()
|
|
53
55
|
const router = useRouter()
|
|
54
56
|
const queryClient = useQueryClient()
|
|
@@ -82,6 +84,7 @@ export default function RulesListPage() {
|
|
|
82
84
|
if (response) {
|
|
83
85
|
setTotal(response.total || 0)
|
|
84
86
|
setTotalPages(response.totalPages || 1)
|
|
87
|
+
setTotalIsCapped(response?.totalIsCapped === true)
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
return response?.items || []
|
|
@@ -352,7 +355,7 @@ export default function RulesListPage() {
|
|
|
352
355
|
createLabel={t('business_rules.actions.create')}
|
|
353
356
|
/>
|
|
354
357
|
)}
|
|
355
|
-
pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}
|
|
358
|
+
pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
356
359
|
/>
|
|
357
360
|
</PageBody>
|
|
358
361
|
{ConfirmDialogElement}
|
|
@@ -35,6 +35,7 @@ type RuleSetsResponse = {
|
|
|
35
35
|
items: RuleSet[]
|
|
36
36
|
total: number
|
|
37
37
|
totalPages: number
|
|
38
|
+
totalIsCapped?: boolean
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export default function RuleSetsListPage() {
|
|
@@ -42,6 +43,7 @@ export default function RuleSetsListPage() {
|
|
|
42
43
|
const [pageSize] = React.useState(20)
|
|
43
44
|
const [total, setTotal] = React.useState(0)
|
|
44
45
|
const [totalPages, setTotalPages] = React.useState(1)
|
|
46
|
+
const [totalIsCapped, setTotalIsCapped] = React.useState(false)
|
|
45
47
|
const t = useT()
|
|
46
48
|
const router = useRouter()
|
|
47
49
|
const queryClient = useQueryClient()
|
|
@@ -72,6 +74,7 @@ export default function RuleSetsListPage() {
|
|
|
72
74
|
if (response) {
|
|
73
75
|
setTotal(response.total || 0)
|
|
74
76
|
setTotalPages(response.totalPages || 1)
|
|
77
|
+
setTotalIsCapped(response?.totalIsCapped === true)
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
return response?.items || []
|
|
@@ -258,7 +261,7 @@ export default function RuleSetsListPage() {
|
|
|
258
261
|
createLabel={t('business_rules.sets.actions.create')}
|
|
259
262
|
/>
|
|
260
263
|
)}
|
|
261
|
-
pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}
|
|
264
|
+
pagination={{ page, pageSize, total, totalPages, totalIsCapped, onPageChange: setPage }}
|
|
262
265
|
/>
|
|
263
266
|
</PageBody>
|
|
264
267
|
{ConfirmDialogElement}
|
|
@@ -407,7 +407,7 @@ const MERCHANDISING_PROMPT_SECTIONS: PromptSection[] = [
|
|
|
407
407
|
'- Selection-first: if `pageContext.recordId` contains a non-empty comma-separated UUID list (or `pageContext.extra.selectedCount > 0`), the operator has selected rows in the grid and EXPECTS you to act on those first. Call catalog.list_selected_products with those IDs, present what you found, and THEN ask whether to expand to the full catalog or to a broader search. Do NOT silently fall back to catalog.search_products when a selection is present.',
|
|
408
408
|
'- "list products" with no selection → call catalog.search_products with NO parameters (returns all active products, paginated; default limit=50, max=100).',
|
|
409
409
|
'- User mentions a product name → call catalog.search_products with q=that name.',
|
|
410
|
-
'- If catalog.search_products
|
|
410
|
+
'- If catalog.search_products fills the page (as many items as `limit`), more may follow: say so and offer to fetch the next page; do NOT raise `limit` above 100. When `totalIsCapped` is true, `total` is a floor — phrase it as "at least N", never as an exact count.',
|
|
411
411
|
'Present results first, then offer refinement options. The user does NOT want to answer questions before seeing data.',
|
|
412
412
|
].join('\n'),
|
|
413
413
|
},
|
|
@@ -97,7 +97,7 @@ function resolveSearchService(ctx: CatalogToolContext): SearchServiceLike | null
|
|
|
97
97
|
const searchProductsInput = z
|
|
98
98
|
.object({
|
|
99
99
|
q: z.string().trim().optional().describe('Optional fulltext query (title / subtitle / sku / handle). Omit or leave empty (or do NOT pass it at all) to list all products. NEVER use "*", "**", or "%" — they are not wildcards and will be discarded.'),
|
|
100
|
-
limit: z.number().int().min(1).max(100).optional().describe('Page size. Default 50, hard maximum 100. Results are paginated:
|
|
100
|
+
limit: z.number().int().min(1).max(100).optional().describe('Page size. Default 50, hard maximum 100. Results are paginated: keep calling with the next `offset` until a page returns fewer than `limit` items, instead of asking for more than 100 rows. Do not treat `offset >= total` as the end — `total` is a floor when `totalIsCapped` is true.'),
|
|
101
101
|
offset: z.number().int().min(0).optional().describe('Rows to skip for pagination (default 0). Combine with `limit` to fetch subsequent pages — for example offset=100, limit=100 fetches rows 101..200.'),
|
|
102
102
|
categoryId: z.string().optional().describe('Restrict to products assigned to this catalog category UUID. Only use a category ID returned by a previous tool call — do NOT guess. Empty string is treated the same as omitting the field.'),
|
|
103
103
|
priceMin: z.number().optional().describe('Lower-bound (inclusive) on the gross unit price. OMIT this field when you do not want a lower bound — do NOT pass 0 as "no minimum", because 0 is a real bound that combined with priceMax=0 will return only free products.'),
|
|
@@ -266,7 +266,7 @@ const searchProductsTool: CatalogAiToolDefinition = {
|
|
|
266
266
|
displayName: 'Search products',
|
|
267
267
|
description:
|
|
268
268
|
'Hybrid search + filter across tenant products. When `q` is non-empty, routes through the search service (tenant + organization scoped) then hydrates tenant-scoped product summaries; when `q` is empty or omitted, runs the catalog query engine with the supplied filters and returns ALL products. ' +
|
|
269
|
-
'Pagination: response shape is `{ items, total, limit, offset, source }`. Hard cap is 100 rows per call (`limit` max=100, default=50);
|
|
269
|
+
'Pagination: response shape is `{ items, total, totalIsCapped, limit, offset, source }`. Hard cap is 100 rows per call (`limit` max=100, default=50); keep calling with the next `offset` until a page returns fewer than `limit` items, rather than asking for >100. When `totalIsCapped` is true, `total` is a floor — render it as "at least N" and never treat `offset >= total` as exhaustion. ' +
|
|
270
270
|
'Empty / sentinel inputs: pass an empty `q` (or omit it) to list all products. NEVER pass `0` for `priceMin`/`priceMax` to mean "no bound" — `0` is a real numeric bound (priceMin=0 + priceMax=0 returns only free products). To remove a bound, OMIT the field. Empty string `categoryId` and empty `tags` arrays are ignored. ' +
|
|
271
271
|
'`source` in the output indicates which path executed (`search_service` vs `query_engine`).',
|
|
272
272
|
inputSchema: searchProductsInput,
|
|
@@ -73,6 +73,8 @@ export interface MerchandisingPageContext {
|
|
|
73
73
|
extra: {
|
|
74
74
|
filter: MerchandisingPageContextFilter
|
|
75
75
|
totalMatching: number
|
|
76
|
+
/** `totalMatching` is a floor, not an exact count (server-capped list count). */
|
|
77
|
+
totalMatchingIsCapped?: boolean
|
|
76
78
|
selectedCount: number
|
|
77
79
|
}
|
|
78
80
|
}
|
|
@@ -181,7 +183,7 @@ function useContextItems(pageContext: MerchandisingPageContext): AiChatContextIt
|
|
|
181
183
|
const t = useT()
|
|
182
184
|
return React.useMemo(() => {
|
|
183
185
|
const items: AiChatContextItem[] = []
|
|
184
|
-
const { selectedCount, totalMatching, filter } = pageContext.extra
|
|
186
|
+
const { selectedCount, totalMatching, totalMatchingIsCapped, filter } = pageContext.extra
|
|
185
187
|
if (selectedCount > 0) {
|
|
186
188
|
items.push({
|
|
187
189
|
label: t(
|
|
@@ -191,10 +193,15 @@ function useContextItems(pageContext: MerchandisingPageContext): AiChatContextIt
|
|
|
191
193
|
})
|
|
192
194
|
} else if (totalMatching > 0) {
|
|
193
195
|
items.push({
|
|
194
|
-
label:
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
label: totalMatchingIsCapped
|
|
197
|
+
? t(
|
|
198
|
+
'catalog.merchandising_assistant.context.matchingProductsCapped',
|
|
199
|
+
'{count}+ products in view',
|
|
200
|
+
).replace('{count}', String(totalMatching))
|
|
201
|
+
: t(
|
|
202
|
+
'catalog.merchandising_assistant.context.matchingProducts',
|
|
203
|
+
'{count} products in view',
|
|
204
|
+
).replace('{count}', String(totalMatching)),
|
|
198
205
|
})
|
|
199
206
|
}
|
|
200
207
|
if (filter.categoryId) {
|