@open-mercato/core 0.6.8-develop.6911.1.f853dd04a9 → 0.6.8-develop.6912.1.36161dc9ac
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.map +1 -1
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +1 -1
- package/dist/modules/audit_logs/components/AccessLogsTable.js.map +1 -1
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +1 -1
- package/dist/modules/auth/backend/roles/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/business_rules/backend/logs/page.js.map +1 -1
- package/dist/modules/business_rules/backend/rules/page.js.map +1 -1
- package/dist/modules/business_rules/backend/sets/page.js.map +1 -1
- package/dist/modules/catalog/components/PriceKindSettings.js.map +1 -1
- package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +1 -1
- package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
- package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +1 -1
- package/dist/modules/communication_channels/backend/profile/communication-channels/page.js.map +1 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +1 -1
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +1 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +1 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +1 -1
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +1 -1
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/components/CustomerTodosTable.js.map +1 -1
- package/dist/modules/data_sync/backend/data-sync/page.js.map +1 -1
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/page.js.map +1 -1
- package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/entities/components/SystemEntitiesTable.js.map +2 -2
- package/dist/modules/entities/components/UserEntitiesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
- package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +1 -1
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +1 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +1 -1
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +1 -1
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js.map +1 -1
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +1 -1
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +1 -1
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +1 -1
- package/dist/modules/sales/components/TaxRatesSettings.js.map +1 -1
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +1 -1
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +1 -1
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +1 -1
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +1 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +1 -1
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +1 -1
- package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +1 -1
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +1 -1
- package/dist/modules/workflows/backend/definitions/page.js.map +1 -1
- package/dist/modules/workflows/backend/events/page.js.map +1 -1
- package/dist/modules/workflows/backend/instances/page.js.map +1 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +1 -1
- package/jest.config.cjs +1 -1
- package/package.json +7 -7
- package/src/modules/api_keys/backend/api-keys/page.tsx +1 -1
- package/src/modules/attachments/components/AttachmentLibrary.tsx +2 -1
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +1 -1
- package/src/modules/audit_logs/components/AccessLogsTable.tsx +1 -1
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +1 -1
- package/src/modules/auth/backend/roles/page.tsx +2 -1
- package/src/modules/auth/backend/users/page.tsx +2 -1
- package/src/modules/business_rules/backend/logs/page.tsx +1 -1
- package/src/modules/business_rules/backend/rules/page.tsx +1 -1
- package/src/modules/business_rules/backend/sets/page.tsx +1 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +1 -1
- package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +1 -1
- package/src/modules/catalog/components/products/ProductsDataTable.tsx +2 -1
- package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +1 -1
- package/src/modules/communication_channels/backend/profile/communication-channels/page.tsx +1 -1
- package/src/modules/currencies/backend/currencies/page.tsx +1 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +1 -1
- package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +1 -1
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +1 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +2 -1
- package/src/modules/customers/backend/customers/deals/page.tsx +1 -1
- package/src/modules/customers/backend/customers/people/page.tsx +2 -1
- package/src/modules/customers/components/CustomerTodosTable.tsx +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +1 -1
- package/src/modules/dictionaries/components/DictionaryTable.tsx +2 -1
- package/src/modules/directory/backend/directory/organizations/page.tsx +1 -1
- package/src/modules/directory/backend/directory/tenants/page.tsx +2 -1
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +2 -1
- package/src/modules/entities/components/SystemEntitiesTable.tsx +2 -1
- package/src/modules/entities/components/UserEntitiesTable.tsx +2 -1
- 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 +1 -1
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +1 -1
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +1 -1
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +1 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +2 -1
- package/src/modules/query_index/components/QueryIndexesTable.tsx +2 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +2 -1
- package/src/modules/resources/backend/resources/resources/page.tsx +1 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +2 -1
- package/src/modules/sales/backend/sales/channels/page.tsx +2 -1
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +1 -1
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +1 -1
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +1 -1
- package/src/modules/sales/components/TaxRatesSettings.tsx +1 -1
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +2 -1
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +1 -1
- package/src/modules/sales/components/documents/PaymentsSection.tsx +1 -1
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +2 -1
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +1 -1
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +2 -1
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +2 -1
- package/src/modules/staff/backend/staff/team-members/page.tsx +3 -2
- package/src/modules/staff/backend/staff/team-roles/page.tsx +1 -1
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +2 -1
- package/src/modules/staff/backend/staff/teams/page.tsx +2 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +2 -1
- package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +2 -1
- package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +4 -3
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +1 -1
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +1 -1
- package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -1
- package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +1 -1
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +1 -1
- package/src/modules/workflows/backend/definitions/page.tsx +1 -1
- package/src/modules/workflows/backend/events/page.tsx +1 -1
- package/src/modules/workflows/backend/instances/page.tsx +1 -1
- package/src/modules/workflows/backend/tasks/page.tsx +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../../src/modules/entities/backend/entities/user/%5BentityId%5D/records/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { resolveExtensionPointPattern } from '@open-mercato/shared/modules/widgets/extension-points'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport { useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { filterCustomFieldDefs, useCustomFieldDefs, type CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { PreparedExport } from '@open-mercato/shared/lib/crud/exporters'\nimport type { FilterDef } from '@open-mercato/ui/backend/FilterBar'\nimport { ContextHelp } from '@open-mercato/ui/backend/ContextHelp'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport Link from 'next/link'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { useRecordsEntityGuard } from '@open-mercato/core/modules/entities/components/useRecordsEntityGuard'\nimport {\n RelationCell,\n RelationDisplaysProvider,\n useRecordListRelationDisplays,\n} from '@open-mercato/core/modules/entities/components/RecordListRelationCell'\n\ntype RecordsResponse = {\n items: any[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nfunction toCsvUrl(base: string, params: URLSearchParams) {\n // Build a relative URL to avoid SSR/CSR origin mismatch hydration issues\n const p = new URLSearchParams(params)\n p.set('format', 'csv')\n const qs = p.toString()\n return qs ? `${base}?${qs}` : base\n}\n\nfunction normalizeCell(v: any): string {\n if (Array.isArray(v)) return v.filter((x) => x != null && x !== '').join(', ')\n if (v === true) return 'Yes'\n if (v === false) return 'No'\n if (v == null) return ''\n if (v instanceof Date) return v.toISOString()\n return String(v)\n}\n\nexport default function RecordsPage({ params }: { params: { entityId?: string } }) {\n const t = useT()\n const entityId = decodeURIComponent(params?.entityId || '')\n const guard = useRecordsEntityGuard(entityId)\n if (guard !== 'allowed') {\n return (\n <Page>\n <PageBody>\n {guard === 'blocked' ? (\n <ErrorMessage label={t('entities.userEntities.records.errors.systemEntity', 'This entity is system-managed. Records are available for custom entities only.')} />\n ) : (\n <LoadingMessage label={t('entities.userEntities.records.loading', 'Loading records...')} />\n )}\n </PageBody>\n </Page>\n )\n }\n return <RecordsPageInner params={params} />\n}\n\nfunction RecordsPageInner({ params }: { params: { entityId?: string } }) {\n const t = useT()\n const entityId = decodeURIComponent(params?.entityId || '')\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'id', desc: false }])\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSize] = React.useState(50)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<Record<string, any>>({})\n const [columns, setColumns] = React.useState<ColumnDef<any>[]>([])\n const [rawData, setRawData] = React.useState<any[]>([])\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(false)\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const deleteMutationContextId = `entities.user.records.${entityId}:single-delete`\n const { runMutation: runDeleteMutation, retryLastMutation: retryDeleteMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: deleteMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const { data: cfDefs = [] } = useCustomFieldDefs(entityId, {\n enabled: Boolean(entityId),\n keyExtras: [scopeVersion],\n })\n const relationDefinitions = React.useMemo(\n () => filterCustomFieldDefs(cfDefs, 'list').filter(\n (definition): definition is CustomFieldDefDto => definition.kind === 'relation',\n ),\n [cfDefs],\n )\n const relationDisplaysByField = useRecordListRelationDisplays(relationDefinitions, rawData)\n\n // Fields searched server-side: every visible column plus the base `id`.\n const searchableFields = React.useMemo(() => {\n const fields = (columns || [])\n .map((col) => (col as any).accessorKey)\n .filter((key): key is string => typeof key === 'string' && key.length > 0)\n return Array.from(new Set(['id', ...fields]))\n }, [columns])\n\n // Fetch records whenever paging/sorting/filters/search change. Search is applied\n // server-side (before pagination) so totals and exports stay consistent (#3229).\n React.useEffect(() => {\n let cancelled = false\n const run = async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams()\n params.set('entityId', entityId)\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n const trimmedSearch = search.trim()\n if (trimmedSearch) {\n params.set('search', trimmedSearch)\n if (searchableFields.length) params.set('searchFields', searchableFields.join(','))\n }\n const s = sorting?.[0]\n if (s?.id) {\n params.set('sortField', String(s.id))\n params.set('sortDir', s.desc ? 'desc' : 'asc')\n }\n // Flatten filter values into query params\n for (const [k, v] of Object.entries(filterValues)) {\n if (v == null) continue\n if (Array.isArray(v)) {\n if (v.length) params.set(k, v.join(','))\n } else if (typeof v === 'object') {\n // dateRange-like shapes are not supported generically here; skip\n } else {\n params.set(k, String(v))\n }\n }\n const j = await readApiResultOrThrow<RecordsResponse>(\n `/api/entities/records?${params.toString()}`,\n undefined,\n {\n errorMessage: 'Failed to load records',\n fallback: {\n items: [],\n total: 0,\n page,\n pageSize,\n totalPages: 1,\n },\n },\n )\n if (!cancelled) {\n setRawData(j.items || [])\n setTotal(j.total)\n setTotalPages(j.totalPages)\n }\n } catch (e) {\n if (!cancelled) {\n setRawData([])\n setTotal(0)\n setTotalPages(1)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n if (entityId) run()\n return () => { cancelled = true }\n }, [entityId, page, pageSize, sorting, filterValues, scopeVersion, search, searchableFields])\n\n // Build columns from custom field definitions only (no data round-trip)\n React.useEffect(() => {\n const visibleDefs = filterCustomFieldDefs(cfDefs, 'list') as any\n const maxVisible = 10\n const cols: ColumnDef<any>[] = visibleDefs.map((d: any, idx: number) => ({\n accessorKey: d.key,\n header: d.label || d.key,\n meta: { priority: idx < 4 ? 1 : idx < 6 ? 2 : idx < 8 ? 3 : idx < maxVisible ? 4 : 5 },\n cell: ({ getValue }: { getValue: () => unknown }) => {\n const v = getValue() as any\n if (d.kind === 'relation') {\n return <RelationCell fieldKey={d.key} value={v} fallbackText={normalizeCell(v)} />\n }\n return <span className=\"inline-block max-w-60 truncate align-top\" title={normalizeCell(v)}>{normalizeCell(v)}</span>\n },\n }))\n // Ensure hidden 'id' column exists for sorting/state\n const hasIdCol = cols.some((c) => (c as any).accessorKey === 'id' || (c as any).id === 'id')\n if (!hasIdCol) cols.unshift({ accessorKey: 'id', header: 'ID', meta: { hidden: true, priority: 6 } } as any)\n setColumns(cols)\n }, [cfDefs])\n\n // Search is server-side (see fetch effect); render the fetched page as-is so\n // pagination totals and exports stay consistent with the active search (#3229).\n const data = rawData\n\n const viewExportColumns = React.useMemo(() => {\n return (columns || [])\n .map((col) => {\n const accessorKey = (col as any).accessorKey\n if (!accessorKey || typeof accessorKey !== 'string') return null\n if ((col as any).meta?.hidden) return null\n const header = typeof col.header === 'string'\n ? col.header\n : accessorKey.startsWith('cf_')\n ? accessorKey.slice(3)\n : accessorKey\n return { field: accessorKey, header }\n })\n .filter((col): col is { field: string; header: string } => !!col)\n }, [columns])\n\n const buildFullExportUrl = React.useCallback((format: DataTableExportFormat) => {\n const qp = new URLSearchParams({\n entityId,\n format,\n exportScope: 'full',\n all: 'true',\n })\n const sort = sorting?.[0]\n if (sort?.id) {\n qp.set('sortField', String(sort.id))\n qp.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n const trimmedSearch = search.trim()\n if (trimmedSearch) {\n qp.set('search', trimmedSearch)\n if (searchableFields.length) qp.set('searchFields', searchableFields.join(','))\n }\n return `/api/entities/records?${qp.toString()}`\n }, [entityId, sorting, search, searchableFields])\n\n const exportConfig = React.useMemo(() => {\n const safeEntityId = entityId.replace(/[^a-z0-9_-]/gi, '_') || 'records'\n return {\n view: {\n description: 'Exports the current list respecting filters and column visibility.',\n prepare: async (): Promise<{ prepared: PreparedExport; filename: string }> => {\n const rowsForExport = data.map((row) => {\n const out: Record<string, unknown> = {}\n for (const col of viewExportColumns) {\n out[col.field] = (row as Record<string, unknown>)[col.field]\n }\n return out\n })\n const prepared: PreparedExport = {\n columns: viewExportColumns.map((col) => ({ field: col.field, header: col.header })),\n rows: rowsForExport,\n }\n return { prepared, filename: `${safeEntityId}_view` }\n },\n },\n full: {\n description: 'Exports raw records with every field and custom field included.',\n getUrl: (format: DataTableExportFormat) => buildFullExportUrl(format),\n filename: () => `${safeEntityId}_full`,\n },\n }\n }, [buildFullExportUrl, data, entityId, viewExportColumns])\n\n const hasAnyFormFields = React.useMemo(() => filterCustomFieldDefs(cfDefs, 'form').length > 0, [cfDefs])\n const actions = (\n <>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}`}>\n Edit Entity Definition\n </Link>\n </Button>\n {hasAnyFormFields && (\n <Button asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records/create`}>\n Create\n </Link>\n </Button>\n )}\n </>\n )\n\n // Ensure filters are visible even if no custom fields are marked filterable\n const baseFilters: FilterDef[] = React.useMemo(() => ([\n { id: 'id', label: 'ID', type: 'text' },\n ]), [])\n\n return (\n <Page>\n <PageBody>\n <ContextHelp bulb title=\"API: Manage Records via cURL\" className=\"mb-4\">\n <p className=\"mb-2\">\n Interact with this custom entity via the backend API using cURL. Use API keys for machine-to-machine access\u2014mint one from the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/user-guide/api-keys\">\n Managing API keys guide\n </a>{' '}\n or the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/cli/api-keys\">\n API keys CLI documentation\n </a>{' '}\n before running these calls.\n </p>\n <div className=\"space-y-2\">\n <div>\n <div className=\"font-medium mb-1\">1) Configure environment variables</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`export BASE_URL=\"http://localhost:3000/api\"\nexport API_KEY=\"<paste API key secret here>\" # scoped with entities.features\nexport ENTITY_ID=\"${entityId}\"\nexport RECORD_ID=\"<record uuid>\"`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">\n Need a new key? Follow the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/user-guide/api-keys\">\n Managing API keys\n </a>{' '}\n walkthrough or mint one via{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/cli/api-keys\">\n mercato api_keys add\n </a>\n .\n </p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">2) List records</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID\" | jq`}</code></pre>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">3) Read a single record (by id)</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID&id=$RECORD_ID\" | jq`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">Note: Response is a list; filter by <code>id</code> to get a single item.</p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">4) Create a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X POST \\\n -H \"X-Api-Key: $API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d \"{\n \\\\\"entityId\\\\\": \\\\\"$ENTITY_ID\\\\\",\n \\\\\"values\\\\\": {\n \\\\\"field_one\\\\\": \\\\\"Example\\\\\",\n \\\\\"field_two\\\\\": 123\n }\n }\" \\\n \"$BASE_URL/entities/records\" | jq`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">For custom entities, send field keys without the <code>cf_</code> prefix. The API normalizes this server-side.</p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">5) Update a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X PUT \\\n -H \"X-Api-Key: $API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d \"{\n \\\\\"entityId\\\\\": \\\\\"$ENTITY_ID\\\\\",\n \\\\\"recordId\\\\\": \\\\\"$RECORD_ID\\\\\",\n \\\\\"values\\\\\": {\n \\\\\"field_one\\\\\": \\\\\"Updated\\\\\"\n }\n }\" \\\n \"$BASE_URL/entities/records\" | jq`}</code></pre>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">6) Delete a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X DELETE \\\n -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID&recordId=$RECORD_ID\" | jq`}</code></pre>\n </div>\n\n <div className=\"text-muted-foreground\">\n Security notes:\n <ul className=\"list-disc pl-5 mt-1 space-y-1\">\n <li>All endpoints require a valid API key. Keys inherit tenant, organization, and feature scope.</li>\n <li>Rotate keys regularly and delete unused ones in the admin UI.</li>\n <li>Store the secret in a secure vault; anyone with the header can act within the key's permissions.</li>\n </ul>\n </div>\n </div>\n </ContextHelp>\n <RelationDisplaysProvider displaysByField={relationDisplaysByField}>\n <DataTable\n stickyActionsColumn\n title={`Records: ${entityId}`}\n entityId={entityId}\n actions={actions}\n columns={columns}\n data={data}\n perspective={{\n tableId: resolveExtensionPointPattern(extensionPoints.hosts.userRecordsTable.pattern, { entityId }),\n }}\n exporter={exportConfig}\n filters={baseFilters}\n filterValues={filterValues}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: 'Edit', href: `/backend/entities/user/${encodeURIComponent(entityId)}/records/${encodeURIComponent(String((row as any).id))}` },\n { id: 'delete', label: 'Delete', destructive: true, onSelect: async () => {\n const recordId = String((row as any).id)\n try {\n const confirmed = await confirm({\n title: 'Delete this record?',\n variant: 'destructive',\n })\n if (!confirmed) return\n await runDeleteMutation({\n operation: async () => {\n const deleteCall = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader((row as any).updatedAt),\n () => apiCall(\n `/api/entities/records?entityId=${encodeURIComponent(entityId)}&recordId=${encodeURIComponent(recordId)}`,\n { method: 'DELETE' },\n ),\n )\n if (!deleteCall.ok) {\n await raiseCrudError(deleteCall.response, 'Failed to delete record')\n }\n },\n context: {\n formId: deleteMutationContextId,\n resourceKind: 'entities.record',\n resourceId: recordId,\n retryLastMutation: retryDeleteMutation,\n },\n })\n const j = await readApiResultOrThrow<RecordsResponse>(\n `/api/entities/records?entityId=${encodeURIComponent(entityId)}&page=${page}&pageSize=${pageSize}`,\n undefined,\n {\n errorMessage: 'Failed to reload records',\n fallback: { items: [], total: 0, page, pageSize, totalPages: 1 },\n },\n )\n setRawData(j.items || [])\n setTotal(j.total || 0)\n setTotalPages(j.totalPages || 1)\n flash('Record has been removed', 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to delete record'\n flash(message, 'error')\n }\n } },\n ]}\n />\n )}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setPage(1) }}\n onFiltersApply={(vals) => { setFilterValues(vals); setPage(1) }}\n onFiltersClear={() => { setFilterValues({}); setPage(1) }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n isLoading={loading}\n />\n </RelationDisplaysProvider>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { resolveExtensionPointPattern } from '@open-mercato/shared/modules/widgets/extension-points'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport { useSearchParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { filterCustomFieldDefs, useCustomFieldDefs, type CustomFieldDefDto } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { PreparedExport } from '@open-mercato/shared/lib/crud/exporters'\nimport type { FilterDef } from '@open-mercato/ui/backend/FilterBar'\nimport { ContextHelp } from '@open-mercato/ui/backend/ContextHelp'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport Link from 'next/link'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ErrorMessage, LoadingMessage } from '@open-mercato/ui/backend/detail'\nimport { useRecordsEntityGuard } from '@open-mercato/core/modules/entities/components/useRecordsEntityGuard'\nimport {\n RelationCell,\n RelationDisplaysProvider,\n useRecordListRelationDisplays,\n} from '@open-mercato/core/modules/entities/components/RecordListRelationCell'\n\ntype RecordsResponse = {\n items: any[]\n total: number\n page: number\n pageSize: number\n totalPages: number\n}\n\nfunction toCsvUrl(base: string, params: URLSearchParams) {\n // Build a relative URL to avoid SSR/CSR origin mismatch hydration issues\n const p = new URLSearchParams(params)\n p.set('format', 'csv')\n const qs = p.toString()\n return qs ? `${base}?${qs}` : base\n}\n\nfunction normalizeCell(v: any): string {\n if (Array.isArray(v)) return v.filter((x) => x != null && x !== '').join(', ')\n if (v === true) return 'Yes'\n if (v === false) return 'No'\n if (v == null) return ''\n if (v instanceof Date) return v.toISOString()\n return String(v)\n}\n\nexport default function RecordsPage({ params }: { params: { entityId?: string } }) {\n const t = useT()\n const entityId = decodeURIComponent(params?.entityId || '')\n const guard = useRecordsEntityGuard(entityId)\n if (guard !== 'allowed') {\n return (\n <Page>\n <PageBody>\n {guard === 'blocked' ? (\n <ErrorMessage label={t('entities.userEntities.records.errors.systemEntity', 'This entity is system-managed. Records are available for custom entities only.')} />\n ) : (\n <LoadingMessage label={t('entities.userEntities.records.loading', 'Loading records...')} />\n )}\n </PageBody>\n </Page>\n )\n }\n return <RecordsPageInner params={params} />\n}\n\nfunction RecordsPageInner({ params }: { params: { entityId?: string } }) {\n const t = useT()\n const entityId = decodeURIComponent(params?.entityId || '')\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'id', desc: false }])\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSize] = React.useState(50)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<Record<string, any>>({})\n const [columns, setColumns] = React.useState<ColumnDef<any>[]>([])\n const [rawData, setRawData] = React.useState<any[]>([])\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [loading, setLoading] = React.useState(false)\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const deleteMutationContextId = `entities.user.records.${entityId}:single-delete`\n const { runMutation: runDeleteMutation, retryLastMutation: retryDeleteMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: deleteMutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n const { data: cfDefs = [] } = useCustomFieldDefs(entityId, {\n enabled: Boolean(entityId),\n keyExtras: [scopeVersion],\n })\n const relationDefinitions = React.useMemo(\n () => filterCustomFieldDefs(cfDefs, 'list').filter(\n (definition): definition is CustomFieldDefDto => definition.kind === 'relation',\n ),\n [cfDefs],\n )\n const relationDisplaysByField = useRecordListRelationDisplays(relationDefinitions, rawData)\n\n // Fields searched server-side: every visible column plus the base `id`.\n const searchableFields = React.useMemo(() => {\n const fields = (columns || [])\n .map((col) => (col as any).accessorKey)\n .filter((key): key is string => typeof key === 'string' && key.length > 0)\n return Array.from(new Set(['id', ...fields]))\n }, [columns])\n\n // Fetch records whenever paging/sorting/filters/search change. Search is applied\n // server-side (before pagination) so totals and exports stay consistent (#3229).\n React.useEffect(() => {\n let cancelled = false\n const run = async () => {\n setLoading(true)\n try {\n const params = new URLSearchParams()\n params.set('entityId', entityId)\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n const trimmedSearch = search.trim()\n if (trimmedSearch) {\n params.set('search', trimmedSearch)\n if (searchableFields.length) params.set('searchFields', searchableFields.join(','))\n }\n const s = sorting?.[0]\n if (s?.id) {\n params.set('sortField', String(s.id))\n params.set('sortDir', s.desc ? 'desc' : 'asc')\n }\n // Flatten filter values into query params\n for (const [k, v] of Object.entries(filterValues)) {\n if (v == null) continue\n if (Array.isArray(v)) {\n if (v.length) params.set(k, v.join(','))\n } else if (typeof v === 'object') {\n // dateRange-like shapes are not supported generically here; skip\n } else {\n params.set(k, String(v))\n }\n }\n const j = await readApiResultOrThrow<RecordsResponse>(\n `/api/entities/records?${params.toString()}`,\n undefined,\n {\n errorMessage: 'Failed to load records',\n fallback: {\n items: [],\n total: 0,\n page,\n pageSize,\n totalPages: 1,\n },\n },\n )\n if (!cancelled) {\n setRawData(j.items || [])\n setTotal(j.total)\n setTotalPages(j.totalPages)\n }\n } catch (e) {\n if (!cancelled) {\n setRawData([])\n setTotal(0)\n setTotalPages(1)\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n if (entityId) run()\n return () => { cancelled = true }\n }, [entityId, page, pageSize, sorting, filterValues, scopeVersion, search, searchableFields])\n\n // Build columns from custom field definitions only (no data round-trip)\n React.useEffect(() => {\n const visibleDefs = filterCustomFieldDefs(cfDefs, 'list') as any\n const maxVisible = 10\n const cols: ColumnDef<any>[] = visibleDefs.map((d: any, idx: number) => ({\n accessorKey: d.key,\n header: d.label || d.key,\n meta: { priority: idx < 4 ? 1 : idx < 6 ? 2 : idx < 8 ? 3 : idx < maxVisible ? 4 : 5 },\n cell: ({ getValue }: { getValue: () => unknown }) => {\n const v = getValue() as any\n if (d.kind === 'relation') {\n return <RelationCell fieldKey={d.key} value={v} fallbackText={normalizeCell(v)} />\n }\n return <span className=\"inline-block max-w-60 truncate align-top\" title={normalizeCell(v)}>{normalizeCell(v)}</span>\n },\n }))\n // Ensure hidden 'id' column exists for sorting/state\n const hasIdCol = cols.some((c) => (c as any).accessorKey === 'id' || (c as any).id === 'id')\n if (!hasIdCol) cols.unshift({ accessorKey: 'id', header: 'ID', meta: { hidden: true, priority: 6 } } as any)\n setColumns(cols)\n }, [cfDefs])\n\n // Search is server-side (see fetch effect); render the fetched page as-is so\n // pagination totals and exports stay consistent with the active search (#3229).\n const data = rawData\n\n const viewExportColumns = React.useMemo(() => {\n return (columns || [])\n .map((col) => {\n const accessorKey = (col as any).accessorKey\n if (!accessorKey || typeof accessorKey !== 'string') return null\n if ((col as any).meta?.hidden) return null\n const header = typeof col.header === 'string'\n ? col.header\n : accessorKey.startsWith('cf_')\n ? accessorKey.slice(3)\n : accessorKey\n return { field: accessorKey, header }\n })\n .filter((col): col is { field: string; header: string } => !!col)\n }, [columns])\n\n const buildFullExportUrl = React.useCallback((format: DataTableExportFormat) => {\n const qp = new URLSearchParams({\n entityId,\n format,\n exportScope: 'full',\n all: 'true',\n })\n const sort = sorting?.[0]\n if (sort?.id) {\n qp.set('sortField', String(sort.id))\n qp.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n const trimmedSearch = search.trim()\n if (trimmedSearch) {\n qp.set('search', trimmedSearch)\n if (searchableFields.length) qp.set('searchFields', searchableFields.join(','))\n }\n return `/api/entities/records?${qp.toString()}`\n }, [entityId, sorting, search, searchableFields])\n\n const exportConfig = React.useMemo(() => {\n const safeEntityId = entityId.replace(/[^a-z0-9_-]/gi, '_') || 'records'\n return {\n view: {\n description: 'Exports the current list respecting filters and column visibility.',\n prepare: async (): Promise<{ prepared: PreparedExport; filename: string }> => {\n const rowsForExport = data.map((row) => {\n const out: Record<string, unknown> = {}\n for (const col of viewExportColumns) {\n out[col.field] = (row as Record<string, unknown>)[col.field]\n }\n return out\n })\n const prepared: PreparedExport = {\n columns: viewExportColumns.map((col) => ({ field: col.field, header: col.header })),\n rows: rowsForExport,\n }\n return { prepared, filename: `${safeEntityId}_view` }\n },\n },\n full: {\n description: 'Exports raw records with every field and custom field included.',\n getUrl: (format: DataTableExportFormat) => buildFullExportUrl(format),\n filename: () => `${safeEntityId}_full`,\n },\n }\n }, [buildFullExportUrl, data, entityId, viewExportColumns])\n\n const hasAnyFormFields = React.useMemo(() => filterCustomFieldDefs(cfDefs, 'form').length > 0, [cfDefs])\n const actions = (\n <>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}`}>\n Edit Entity Definition\n </Link>\n </Button>\n {hasAnyFormFields && (\n <Button asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records/create`}>\n Create\n </Link>\n </Button>\n )}\n </>\n )\n\n // Ensure filters are visible even if no custom fields are marked filterable\n const baseFilters: FilterDef[] = React.useMemo(() => ([\n { id: 'id', label: 'ID', type: 'text' },\n ]), [])\n\n return (\n <Page>\n <PageBody>\n <ContextHelp bulb title=\"API: Manage Records via cURL\" className=\"mb-4\">\n <p className=\"mb-2\">\n Interact with this custom entity via the backend API using cURL. Use API keys for machine-to-machine access\u2014mint one from the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/user-guide/api-keys\">\n Managing API keys guide\n </a>{' '}\n or the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/cli/api-keys\">\n API keys CLI documentation\n </a>{' '}\n before running these calls.\n </p>\n <div className=\"space-y-2\">\n <div>\n <div className=\"font-medium mb-1\">1) Configure environment variables</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`export BASE_URL=\"http://localhost:3000/api\"\nexport API_KEY=\"<paste API key secret here>\" # scoped with entities.features\nexport ENTITY_ID=\"${entityId}\"\nexport RECORD_ID=\"<record uuid>\"`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">\n Need a new key? Follow the{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/user-guide/api-keys\">\n Managing API keys\n </a>{' '}\n walkthrough or mint one via{' '}\n <a className=\"underline\" target=\"_blank\" rel=\"noreferrer\" href=\"https://docs.openmercato.com/cli/api-keys\">\n mercato api_keys add\n </a>\n .\n </p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">2) List records</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID\" | jq`}</code></pre>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">3) Read a single record (by id)</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID&id=$RECORD_ID\" | jq`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">Note: Response is a list; filter by <code>id</code> to get a single item.</p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">4) Create a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X POST \\\n -H \"X-Api-Key: $API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d \"{\n \\\\\"entityId\\\\\": \\\\\"$ENTITY_ID\\\\\",\n \\\\\"values\\\\\": {\n \\\\\"field_one\\\\\": \\\\\"Example\\\\\",\n \\\\\"field_two\\\\\": 123\n }\n }\" \\\n \"$BASE_URL/entities/records\" | jq`}</code></pre>\n <p className=\"text-muted-foreground mt-1\">For custom entities, send field keys without the <code>cf_</code> prefix. The API normalizes this server-side.</p>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">5) Update a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X PUT \\\n -H \"X-Api-Key: $API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d \"{\n \\\\\"entityId\\\\\": \\\\\"$ENTITY_ID\\\\\",\n \\\\\"recordId\\\\\": \\\\\"$RECORD_ID\\\\\",\n \\\\\"values\\\\\": {\n \\\\\"field_one\\\\\": \\\\\"Updated\\\\\"\n }\n }\" \\\n \"$BASE_URL/entities/records\" | jq`}</code></pre>\n </div>\n\n <div>\n <div className=\"font-medium mb-1\">6) Delete a record</div>\n <pre className=\"bg-muted p-3 rounded text-xs overflow-auto\"><code>{`curl -s -X DELETE \\\n -H \"X-Api-Key: $API_KEY\" \\\n \"$BASE_URL/entities/records?entityId=$ENTITY_ID&recordId=$RECORD_ID\" | jq`}</code></pre>\n </div>\n\n <div className=\"text-muted-foreground\">\n Security notes:\n <ul className=\"list-disc pl-5 mt-1 space-y-1\">\n <li>All endpoints require a valid API key. Keys inherit tenant, organization, and feature scope.</li>\n <li>Rotate keys regularly and delete unused ones in the admin UI.</li>\n <li>Store the secret in a secure vault; anyone with the header can act within the key's permissions.</li>\n </ul>\n </div>\n </div>\n </ContextHelp>\n <RelationDisplaysProvider displaysByField={relationDisplaysByField}>\n <DataTable\n stickyActionsColumn\n title={`Records: ${entityId}`}\n entityId={entityId}\n actions={actions}\n columns={columns}\n data={data}\n perspective={{\n tableId: resolveExtensionPointPattern(extensionPoints.hosts.userRecordsTable.pattern, { entityId }),\n }}\n exporter={exportConfig}\n filters={baseFilters}\n filterValues={filterValues}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: 'Edit', href: `/backend/entities/user/${encodeURIComponent(entityId)}/records/${encodeURIComponent(String((row as any).id))}` },\n { id: 'delete', label: 'Delete', destructive: true, onSelect: async () => {\n const recordId = String((row as any).id)\n try {\n const confirmed = await confirm({\n title: 'Delete this record?',\n variant: 'destructive',\n })\n if (!confirmed) return\n await runDeleteMutation({\n operation: async () => {\n const deleteCall = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader((row as any).updatedAt),\n () => apiCall(\n `/api/entities/records?entityId=${encodeURIComponent(entityId)}&recordId=${encodeURIComponent(recordId)}`,\n { method: 'DELETE' },\n ),\n )\n if (!deleteCall.ok) {\n await raiseCrudError(deleteCall.response, 'Failed to delete record')\n }\n },\n context: {\n formId: deleteMutationContextId,\n resourceKind: 'entities.record',\n resourceId: recordId,\n retryLastMutation: retryDeleteMutation,\n },\n })\n const j = await readApiResultOrThrow<RecordsResponse>(\n `/api/entities/records?entityId=${encodeURIComponent(entityId)}&page=${page}&pageSize=${pageSize}`,\n undefined,\n {\n errorMessage: 'Failed to reload records',\n fallback: { items: [], total: 0, page, pageSize, totalPages: 1 },\n },\n )\n setRawData(j.items || [])\n setTotal(j.total || 0)\n setTotalPages(j.totalPages || 1)\n flash('Record has been removed', 'success')\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to delete record'\n flash(message, 'error')\n }\n } },\n ]}\n />\n )}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setPage(1) }}\n onFiltersApply={(vals) => { setFilterValues(vals); setPage(1) }}\n onFiltersClear={() => { setFilterValues({}); setPage(1) }}\n pagination={{ page, pageSize, total, totalPages, onPageChange: setPage }}\n isLoading={loading}\n />\n </RelationDisplaysProvider>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAkEY,SAqNR,UArNQ,KAqNR,YArNQ;AAjEZ,YAAY,WAAW;AACvB,SAAS,oCAAoC;AAC7C,SAAS,uBAAuB;AAIhC,SAAS,uBAAuB,0BAAkD;AAClF,SAAS,MAAM,gBAAgB;AAC/B,SAAS,iBAA6C;AAGtD,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,SAAS,sBAAsB,mCAAmC;AAC3E,SAAS,iCAAiC;AAC1C,SAAS,aAAa;AACtB,SAAS,sBAAsB;AAC/B,SAAS,mCAAmC;AAC5C,SAAS,wBAAwB;AACjC,SAAS,0BAA0B;AACnC,SAAS,YAAY;AACrB,SAAS,cAAc,sBAAsB;AAC7C,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUP,SAAS,SAAS,MAAc,QAAyB;AAEvD,QAAM,IAAI,IAAI,gBAAgB,MAAM;AACpC,IAAE,IAAI,UAAU,KAAK;AACrB,QAAM,KAAK,EAAE,SAAS;AACtB,SAAO,KAAK,GAAG,IAAI,IAAI,EAAE,KAAK;AAChC;AAEA,SAAS,cAAc,GAAgB;AACrC,MAAI,MAAM,QAAQ,CAAC,EAAG,QAAO,EAAE,OAAO,CAAC,MAAM,KAAK,QAAQ,MAAM,EAAE,EAAE,KAAK,IAAI;AAC7E,MAAI,MAAM,KAAM,QAAO;AACvB,MAAI,MAAM,MAAO,QAAO;AACxB,MAAI,KAAK,KAAM,QAAO;AACtB,MAAI,aAAa,KAAM,QAAO,EAAE,YAAY;AAC5C,SAAO,OAAO,CAAC;AACjB;AAEe,SAAR,YAA6B,EAAE,OAAO,GAAsC;AACjF,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,mBAAmB,QAAQ,YAAY,EAAE;AAC1D,QAAM,QAAQ,sBAAsB,QAAQ;AAC5C,MAAI,UAAU,WAAW;AACvB,WACE,oBAAC,QACC,8BAAC,YACE,oBAAU,YACT,oBAAC,gBAAa,OAAO,EAAE,qDAAqD,gFAAgF,GAAG,IAE/J,oBAAC,kBAAe,OAAO,EAAE,yCAAyC,oBAAoB,GAAG,GAE7F,GACF;AAAA,EAEJ;AACA,SAAO,oBAAC,oBAAiB,QAAgB;AAC3C;AAEA,SAAS,iBAAiB,EAAE,OAAO,GAAsC;AACvE,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,mBAAmB,QAAQ,YAAY,EAAE;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAuB,CAAC,EAAE,IAAI,MAAM,MAAM,MAAM,CAAC,CAAC;AACtF,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,CAAC;AACxC,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,EAAE;AACjD,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE;AAC7C,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAA8B,CAAC,CAAC;AAC9E,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAA2B,CAAC,CAAC;AACjE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAgB,CAAC,CAAC;AACtD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAS,CAAC;AAC1C,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,CAAC;AACpD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAClD,QAAM,eAAe,4BAA4B;AACjD,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,0BAA0B,yBAAyB,QAAQ;AACjE,QAAM,EAAE,aAAa,mBAAmB,mBAAmB,oBAAoB,IAAI,mBAKhF;AAAA,IACD,WAAW;AAAA,IACX,gBAAgB,EAAE,8BAA8B,4BAA4B;AAAA,EAC9E,CAAC;AACD,QAAM,EAAE,MAAM,SAAS,CAAC,EAAE,IAAI,mBAAmB,UAAU;AAAA,IACzD,SAAS,QAAQ,QAAQ;AAAA,IACzB,WAAW,CAAC,YAAY;AAAA,EAC1B,CAAC;AACD,QAAM,sBAAsB,MAAM;AAAA,IAChC,MAAM,sBAAsB,QAAQ,MAAM,EAAE;AAAA,MAC1C,CAAC,eAAgD,WAAW,SAAS;AAAA,IACvE;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AACA,QAAM,0BAA0B,8BAA8B,qBAAqB,OAAO;AAG1F,QAAM,mBAAmB,MAAM,QAAQ,MAAM;AAC3C,UAAM,UAAU,WAAW,CAAC,GACzB,IAAI,CAAC,QAAS,IAAY,WAAW,EACrC,OAAO,CAAC,QAAuB,OAAO,QAAQ,YAAY,IAAI,SAAS,CAAC;AAC3E,WAAO,MAAM,KAAK,oBAAI,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;AAAA,EAC9C,GAAG,CAAC,OAAO,CAAC;AAIZ,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,UAAM,MAAM,YAAY;AACtB,iBAAW,IAAI;AACf,UAAI;AACF,cAAMA,UAAS,IAAI,gBAAgB;AACnC,QAAAA,QAAO,IAAI,YAAY,QAAQ;AAC/B,QAAAA,QAAO,IAAI,QAAQ,OAAO,IAAI,CAAC;AAC/B,QAAAA,QAAO,IAAI,YAAY,OAAO,QAAQ,CAAC;AACvC,cAAM,gBAAgB,OAAO,KAAK;AAClC,YAAI,eAAe;AACjB,UAAAA,QAAO,IAAI,UAAU,aAAa;AAClC,cAAI,iBAAiB,OAAQ,CAAAA,QAAO,IAAI,gBAAgB,iBAAiB,KAAK,GAAG,CAAC;AAAA,QACpF;AACA,cAAM,IAAI,UAAU,CAAC;AACrB,YAAI,GAAG,IAAI;AACT,UAAAA,QAAO,IAAI,aAAa,OAAO,EAAE,EAAE,CAAC;AACpC,UAAAA,QAAO,IAAI,WAAW,EAAE,OAAO,SAAS,KAAK;AAAA,QAC/C;AAEA,mBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,YAAY,GAAG;AACjD,cAAI,KAAK,KAAM;AACf,cAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,gBAAI,EAAE,OAAQ,CAAAA,QAAO,IAAI,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,UACzC,WAAW,OAAO,MAAM,UAAU;AAAA,UAElC,OAAO;AACL,YAAAA,QAAO,IAAI,GAAG,OAAO,CAAC,CAAC;AAAA,UACzB;AAAA,QACF;AACA,cAAM,IAAI,MAAM;AAAA,UACd,yBAAyBA,QAAO,SAAS,CAAC;AAAA,UAC1C;AAAA,UACA;AAAA,YACE,cAAc;AAAA,YACd,UAAU;AAAA,cACR,OAAO,CAAC;AAAA,cACR,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA,YAAY;AAAA,YACd;AAAA,UACF;AAAA,QACF;AACA,YAAI,CAAC,WAAW;AACd,qBAAW,EAAE,SAAS,CAAC,CAAC;AACxB,mBAAS,EAAE,KAAK;AAChB,wBAAc,EAAE,UAAU;AAAA,QAC5B;AAAA,MACF,SAAS,GAAG;AACV,YAAI,CAAC,WAAW;AACd,qBAAW,CAAC,CAAC;AACb,mBAAS,CAAC;AACV,wBAAc,CAAC;AAAA,QACjB;AAAA,MACF,UAAE;AACA,YAAI,CAAC,UAAW,YAAW,KAAK;AAAA,MAClC;AAAA,IACF;AACA,QAAI,SAAU,KAAI;AAClB,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,UAAU,MAAM,UAAU,SAAS,cAAc,cAAc,QAAQ,gBAAgB,CAAC;AAG5F,QAAM,UAAU,MAAM;AACpB,UAAM,cAAc,sBAAsB,QAAQ,MAAM;AACxD,UAAM,aAAa;AACnB,UAAM,OAAyB,YAAY,IAAI,CAAC,GAAQ,SAAiB;AAAA,MACvE,aAAa,EAAE;AAAA,MACf,QAAQ,EAAE,SAAS,EAAE;AAAA,MACrB,MAAM,EAAE,UAAU,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,MAAM,aAAa,IAAI,EAAE;AAAA,MACrF,MAAM,CAAC,EAAE,SAAS,MAAmC;AACnD,cAAM,IAAI,SAAS;AACnB,YAAI,EAAE,SAAS,YAAY;AACzB,iBAAO,oBAAC,gBAAa,UAAU,EAAE,KAAK,OAAO,GAAG,cAAc,cAAc,CAAC,GAAG;AAAA,QAClF;AACA,eAAO,oBAAC,UAAK,WAAU,4CAA2C,OAAO,cAAc,CAAC,GAAI,wBAAc,CAAC,GAAE;AAAA,MAC/G;AAAA,IACF,EAAE;AAEF,UAAM,WAAW,KAAK,KAAK,CAAC,MAAO,EAAU,gBAAgB,QAAS,EAAU,OAAO,IAAI;AAC3F,QAAI,CAAC,SAAU,MAAK,QAAQ,EAAE,aAAa,MAAM,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,UAAU,EAAE,EAAE,CAAQ;AAC3G,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,MAAM,CAAC;AAIX,QAAM,OAAO;AAEb,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAC5C,YAAQ,WAAW,CAAC,GACjB,IAAI,CAAC,QAAQ;AACZ,YAAM,cAAe,IAAY;AACjC,UAAI,CAAC,eAAe,OAAO,gBAAgB,SAAU,QAAO;AAC5D,UAAK,IAAY,MAAM,OAAQ,QAAO;AACtC,YAAM,SAAS,OAAO,IAAI,WAAW,WACjC,IAAI,SACJ,YAAY,WAAW,KAAK,IAC1B,YAAY,MAAM,CAAC,IACnB;AACN,aAAO,EAAE,OAAO,aAAa,OAAO;AAAA,IACtC,CAAC,EACA,OAAO,CAAC,QAAkD,CAAC,CAAC,GAAG;AAAA,EACpE,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,qBAAqB,MAAM,YAAY,CAAC,WAAkC;AAC9E,UAAM,KAAK,IAAI,gBAAgB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,KAAK;AAAA,IACP,CAAC;AACD,UAAM,OAAO,UAAU,CAAC;AACxB,QAAI,MAAM,IAAI;AACZ,SAAG,IAAI,aAAa,OAAO,KAAK,EAAE,CAAC;AACnC,SAAG,IAAI,WAAW,KAAK,OAAO,SAAS,KAAK;AAAA,IAC9C;AACA,UAAM,gBAAgB,OAAO,KAAK;AAClC,QAAI,eAAe;AACjB,SAAG,IAAI,UAAU,aAAa;AAC9B,UAAI,iBAAiB,OAAQ,IAAG,IAAI,gBAAgB,iBAAiB,KAAK,GAAG,CAAC;AAAA,IAChF;AACA,WAAO,yBAAyB,GAAG,SAAS,CAAC;AAAA,EAC/C,GAAG,CAAC,UAAU,SAAS,QAAQ,gBAAgB,CAAC;AAEhD,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,UAAM,eAAe,SAAS,QAAQ,iBAAiB,GAAG,KAAK;AAC/D,WAAO;AAAA,MACL,MAAM;AAAA,QACJ,aAAa;AAAA,QACb,SAAS,YAAqE;AAC5E,gBAAM,gBAAgB,KAAK,IAAI,CAAC,QAAQ;AACtC,kBAAM,MAA+B,CAAC;AACtC,uBAAW,OAAO,mBAAmB;AACnC,kBAAI,IAAI,KAAK,IAAK,IAAgC,IAAI,KAAK;AAAA,YAC7D;AACA,mBAAO;AAAA,UACT,CAAC;AACD,gBAAM,WAA2B;AAAA,YAC/B,SAAS,kBAAkB,IAAI,CAAC,SAAS,EAAE,OAAO,IAAI,OAAO,QAAQ,IAAI,OAAO,EAAE;AAAA,YAClF,MAAM;AAAA,UACR;AACA,iBAAO,EAAE,UAAU,UAAU,GAAG,YAAY,QAAQ;AAAA,QACtD;AAAA,MACF;AAAA,MACA,MAAM;AAAA,QACJ,aAAa;AAAA,QACb,QAAQ,CAAC,WAAkC,mBAAmB,MAAM;AAAA,QACpE,UAAU,MAAM,GAAG,YAAY;AAAA,MACjC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,oBAAoB,MAAM,UAAU,iBAAiB,CAAC;AAE1D,QAAM,mBAAmB,MAAM,QAAQ,MAAM,sBAAsB,QAAQ,MAAM,EAAE,SAAS,GAAG,CAAC,MAAM,CAAC;AACvG,QAAM,UACJ,iCACE;AAAA,wBAAC,UAAO,SAAO,MAAC,SAAQ,WAAU,MAAK,MACrC,8BAAC,QAAK,MAAM,0BAA0B,mBAAmB,QAAQ,CAAC,IAAI,oCAEtE,GACF;AAAA,IACC,oBACC,oBAAC,UAAO,SAAO,MACb,8BAAC,QAAK,MAAM,0BAA0B,mBAAmB,QAAQ,CAAC,mBAAmB,oBAErF,GACF;AAAA,KAEJ;AAIF,QAAM,cAA2B,MAAM,QAAQ,MAAO;AAAA,IACpD,EAAE,IAAI,MAAM,OAAO,MAAM,MAAM,OAAO;AAAA,EACxC,GAAI,CAAC,CAAC;AAEN,SACE,qBAAC,QACC;AAAA,yBAAC,YACC;AAAA,2BAAC,eAAY,MAAI,MAAC,OAAM,gCAA+B,WAAU,QAC/D;AAAA,6BAAC,OAAE,WAAU,QAAO;AAAA;AAAA,UAC4G;AAAA,UAC9H,oBAAC,OAAE,WAAU,aAAY,QAAO,UAAS,KAAI,cAAa,MAAK,oDAAmD,qCAElH;AAAA,UAAK;AAAA,UAAI;AAAA,UACF;AAAA,UACP,oBAAC,OAAE,WAAU,aAAY,QAAO,UAAS,KAAI,cAAa,MAAK,6CAA4C,wCAE3G;AAAA,UAAK;AAAA,UAAI;AAAA,WAEX;AAAA,QACA,qBAAC,SAAI,WAAU,aACb;AAAA,+BAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,gDAAkC;AAAA,YACpE,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM;AAAA;AAAA,oBAE7D,QAAQ;AAAA,mCACM,GAAO;AAAA,YAC3B,qBAAC,OAAE,WAAU,8BAA6B;AAAA;AAAA,cACb;AAAA,cAC3B,oBAAC,OAAE,WAAU,aAAY,QAAO,UAAS,KAAI,cAAa,MAAK,oDAAmD,+BAElH;AAAA,cAAK;AAAA,cAAI;AAAA,cACmB;AAAA,cAC5B,oBAAC,OAAE,WAAU,aAAY,QAAO,UAAS,KAAI,cAAa,MAAK,6CAA4C,kCAE3G;AAAA,cAAI;AAAA,eAEN;AAAA,aACF;AAAA,UAEA,qBAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,6BAAe;AAAA,YACjD,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM,sGACxB,GAAO;AAAA,aACpD;AAAA,UAEA,qBAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,6CAA+B;AAAA,YACjE,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM,oHACV,GAAO;AAAA,YAChE,qBAAC,OAAE,WAAU,8BAA6B;AAAA;AAAA,cAAoC,oBAAC,UAAK,gBAAE;AAAA,cAAO;AAAA,eAAsB;AAAA,aACrH;AAAA,UAEA,qBAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,gCAAkB;AAAA,YACpD,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2CAU5C,GAAO;AAAA,YAC9B,qBAAC,OAAE,WAAU,8BAA6B;AAAA;AAAA,cAAiD,oBAAC,UAAK,iBAAG;AAAA,cAAO;AAAA,eAA6C;AAAA,aAC1J;AAAA,UAEA,qBAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,gCAAkB;AAAA,YACpD,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2CAU5C,GAAO;AAAA,aAChC;AAAA,UAEA,qBAAC,SACC;AAAA,gCAAC,SAAI,WAAU,oBAAmB,gCAAkB;AAAA,YACpD,oBAAC,SAAI,WAAU,8CAA6C,8BAAC,UAAM,sIAEJ,GAAO;AAAA,aACxE;AAAA,UAEA,qBAAC,SAAI,WAAU,yBAAwB;AAAA;AAAA,YAErC,qBAAC,QAAG,WAAU,iCACZ;AAAA,kCAAC,QAAG,0GAA4F;AAAA,cAChG,oBAAC,QAAG,2EAA6D;AAAA,cACjE,oBAAC,QAAG,8GAAqG;AAAA,eAC3G;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,MACA,oBAAC,4BAAyB,iBAAiB,yBACzC;AAAA,QAAC;AAAA;AAAA,UACC,qBAAmB;AAAA,UACnB,OAAO,YAAY,QAAQ;AAAA,UAC3B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,YACX,SAAS,6BAA6B,gBAAgB,MAAM,iBAAiB,SAAS,EAAE,SAAS,CAAC;AAAA,UACpG;AAAA,UACA,UAAU;AAAA,UACV,SAAS;AAAA,UACT;AAAA,UACA,YAAY,CAAC,QACX;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,EAAE,IAAI,QAAQ,OAAO,QAAQ,MAAM,0BAA0B,mBAAmB,QAAQ,CAAC,YAAY,mBAAmB,OAAQ,IAAY,EAAE,CAAC,CAAC,GAAG;AAAA,gBACnJ,EAAE,IAAI,UAAU,OAAO,UAAU,aAAa,MAAM,UAAU,YAAY;AACxE,wBAAM,WAAW,OAAQ,IAAY,EAAE;AACvC,sBAAI;AACF,0BAAM,YAAY,MAAM,QAAQ;AAAA,sBAC9B,OAAO;AAAA,sBACP,SAAS;AAAA,oBACX,CAAC;AACD,wBAAI,CAAC,UAAW;AAChB,0BAAM,kBAAkB;AAAA,sBACtB,WAAW,YAAY;AACrB,8BAAM,aAAa,MAAM;AAAA,0BACvB,0BAA2B,IAAY,SAAS;AAAA,0BAChD,MAAM;AAAA,4BACJ,kCAAkC,mBAAmB,QAAQ,CAAC,aAAa,mBAAmB,QAAQ,CAAC;AAAA,4BACvG,EAAE,QAAQ,SAAS;AAAA,0BACrB;AAAA,wBACF;AACA,4BAAI,CAAC,WAAW,IAAI;AAClB,gCAAM,eAAe,WAAW,UAAU,yBAAyB;AAAA,wBACrE;AAAA,sBACF;AAAA,sBACA,SAAS;AAAA,wBACP,QAAQ;AAAA,wBACR,cAAc;AAAA,wBACd,YAAY;AAAA,wBACZ,mBAAmB;AAAA,sBACrB;AAAA,oBACF,CAAC;AACD,0BAAM,IAAI,MAAM;AAAA,sBACd,kCAAkC,mBAAmB,QAAQ,CAAC,SAAS,IAAI,aAAa,QAAQ;AAAA,sBAChG;AAAA,sBACA;AAAA,wBACE,cAAc;AAAA,wBACd,UAAU,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,MAAM,UAAU,YAAY,EAAE;AAAA,sBACjE;AAAA,oBACF;AACA,+BAAW,EAAE,SAAS,CAAC,CAAC;AACxB,6BAAS,EAAE,SAAS,CAAC;AACrB,kCAAc,EAAE,cAAc,CAAC;AAC/B,0BAAM,2BAA2B,SAAS;AAAA,kBAC5C,SAAS,OAAO;AACd,0BAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,0BAAM,SAAS,OAAO;AAAA,kBACxB;AAAA,gBACF,EAAE;AAAA,cACJ;AAAA;AAAA,UACF;AAAA,UAEF,UAAQ;AAAA,UACR;AAAA,UACA,iBAAiB;AAAA,UACjB,aAAa;AAAA,UACb,gBAAgB,CAAC,MAAM;AAAE,sBAAU,CAAC;AAAG,oBAAQ,CAAC;AAAA,UAAE;AAAA,UAClD,gBAAgB,CAAC,SAAS;AAAE,4BAAgB,IAAI;AAAG,oBAAQ,CAAC;AAAA,UAAE;AAAA,UAC9D,gBAAgB,MAAM;AAAE,4BAAgB,CAAC,CAAC;AAAG,oBAAQ,CAAC;AAAA,UAAE;AAAA,UACxD,YAAY,EAAE,MAAM,UAAU,OAAO,YAAY,cAAc,QAAQ;AAAA,UACvE,WAAW;AAAA;AAAA,MACb,GACF;AAAA,OACF;AAAA,IACC;AAAA,KACH;AAEJ;",
|
|
6
6
|
"names": ["params"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/components/SystemEntitiesTable.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport { useQuery } from '@tanstack/react-query'\nimport type { ColumnDef
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport { useQuery } from '@tanstack/react-query'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { buildEntitiesCsv } from '../lib/entitiesCsvExport'\n\ntype EntityRow = {\n entityId: string\n label: string\n source: 'code' | 'custom'\n count: number\n}\n\ntype EntitiesResponse = { items: EntityRow[] }\n\nconst columns: ColumnDef<EntityRow>[] = [\n { accessorKey: 'entityId', header: 'Entity', meta: { priority: 1 }, cell: ({ getValue }) => <span className=\"font-mono\">{String(getValue())}</span> },\n { accessorKey: 'label', header: 'Label', meta: { priority: 2 } },\n { accessorKey: 'source', header: 'Source', meta: { priority: 3 } },\n { accessorKey: 'count', header: 'Fields', meta: { priority: 4 } },\n]\n\nexport default function SystemEntitiesTable() {\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'entityId', desc: false }])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const scopeVersion = useOrganizationScopeVersion()\n\n const { data, isLoading } = useQuery<EntitiesResponse>({\n queryKey: ['custom-entities', scopeVersion],\n queryFn: async () => {\n return readApiResultOrThrow<EntitiesResponse>('/api/entities/entities', undefined, {\n errorMessage: 'Failed to load entities',\n })\n },\n })\n\n const rowsAll = data?.items || []\n // Filter to only show system entities (source: 'code')\n const systemRows = rowsAll.filter(row => row.source === 'code')\n const rows = React.useMemo(() => {\n if (!search) return systemRows\n const q = search.toLowerCase()\n return systemRows.filter(r => r.entityId.toLowerCase().includes(q) || r.label.toLowerCase().includes(q))\n }, [systemRows, search])\n\n return (\n <DataTable\n title=\"System Entities\"\n actions={(\n <>\n <Button variant=\"outline\" onClick={() => {\n const csv = buildEntitiesCsv(rows)\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = 'entities-system.csv'\n a.click()\n URL.revokeObjectURL(url)\n }}>Export</Button>\n </>\n )}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setPage(1) }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n perspective={{ tableId: extensionPoints.hosts.systemEntitiesTable.tableId }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: 'Edit', href: `/backend/entities/system/${encodeURIComponent(row.entityId)}` },\n ]}\n />\n )}\n pagination={{ page, pageSize: 50, total: rows.length, totalPages: 1, onPageChange: setPage }}\n isLoading={isLoading}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/components/UserEntitiesTable.tsx"],
|
|
4
|
-
"sourcesContent": ["\n\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport Link from 'next/link'\nimport { useQuery } from '@tanstack/react-query'\nimport type { ColumnDef
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\n\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/entities/extension-points'\nimport Link from 'next/link'\nimport { useQuery } from '@tanstack/react-query'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { DataTable, RowActions, Button } from '@open-mercato/ui'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { buildEntitiesCsv } from '../lib/entitiesCsvExport'\n\ntype EntityRow = {\n entityId: string\n label: string\n source: 'code' | 'custom'\n count: number\n showInSidebar?: boolean\n}\n\ntype EntitiesResponse = { items: EntityRow[] }\n\nfunction buildColumns(t: (key: string, fallback: string) => string): ColumnDef<EntityRow>[] {\n return [\n { accessorKey: 'entityId', header: t('entities.user.table.column.entity', 'Entity'), meta: { priority: 1 }, cell: ({ getValue }) => <span className=\"font-mono\">{String(getValue())}</span> },\n { accessorKey: 'label', header: t('entities.user.table.column.label', 'Label'), meta: { priority: 2 } },\n { accessorKey: 'source', header: t('entities.user.table.column.source', 'Source'), meta: { priority: 3 } },\n { accessorKey: 'count', header: t('entities.user.table.column.fields', 'Fields'), meta: { priority: 4 } },\n { \n accessorKey: 'showInSidebar', \n header: t('entities.user.table.column.inSidebar', 'In Sidebar'), \n meta: { priority: 5 },\n cell: ({ getValue }) => (\n <span className={`px-2 py-1 rounded text-xs ${\n getValue() ? 'bg-status-success-bg text-status-success-text' : 'bg-muted text-muted-foreground'\n }`}>\n {getValue() ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </span>\n )\n },\n ]\n}\n\nexport default function UserEntitiesTable() {\n const t = useT()\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'entityId', desc: false }])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const scopeVersion = useOrganizationScopeVersion()\n \n const columns = React.useMemo(() => buildColumns(t), [t])\n\n const { data, isLoading } = useQuery<EntitiesResponse>({\n queryKey: ['custom-entities', scopeVersion],\n queryFn: async () => {\n return readApiResultOrThrow<EntitiesResponse>('/api/entities/entities', undefined, {\n errorMessage: 'Failed to load entities',\n })\n },\n })\n\n const rowsAll = data?.items || []\n // Filter to only show user entities (source: 'custom')\n const userRows = rowsAll.filter(row => row.source === 'custom')\n const rows = React.useMemo(() => {\n if (!search) return userRows\n const q = search.toLowerCase()\n return userRows.filter(r => r.entityId.toLowerCase().includes(q) || r.label.toLowerCase().includes(q))\n }, [userRows, search])\n\n return (\n <DataTable\n title={t('entities.user.table.title', 'User Entities')}\n actions={(\n <>\n <Button variant=\"outline\" onClick={() => {\n const csv = buildEntitiesCsv(rows, { includeSidebar: true })\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = 'entities-user.csv'\n a.click()\n URL.revokeObjectURL(url)\n }}>{t('common.export', 'Export')}</Button>\n <Button asChild>\n <Link href=\"/backend/entities/user/create\">{t('common.create', 'Create')}</Link>\n </Button>\n </>\n )}\n columns={columns}\n data={rows}\n searchValue={search}\n onSearchChange={(v) => { setSearch(v); setPage(1) }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n perspective={{ tableId: extensionPoints.hosts.userEntitiesTable.tableId }}\n emptyState={(\n <ListEmptyState\n entityName={t('entities.user.table.title', 'User Entities')}\n createHref=\"/backend/entities/user/create\"\n createLabel={t('common.create', 'Create')}\n />\n )}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}` },\n { id: 'show-records', label: t('entities.user.table.actions.showRecords', 'Show records'), href: `/backend/entities/user/${encodeURIComponent(row.entityId)}/records` },\n ]}\n />\n )}\n pagination={{ page, pageSize: 50, total: rows.length, totalPages: 1, onPageChange: setPage }}\n isLoading={isLoading}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/feature_toggles/components/FeatureTogglesTable.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport { DataTable } from \"@open-mercato/ui/backend/DataTable\";\nimport { RowActions } from \"@open-mercato/ui/backend/RowActions\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ColumnDef
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport { DataTable } from \"@open-mercato/ui/backend/DataTable\";\nimport { RowActions } from \"@open-mercato/ui/backend/RowActions\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport * as React from 'react'\nimport type { FilterDef, FilterValues } from \"@open-mercato/ui/backend/FilterBar\"\nimport { useMutation } from '@tanstack/react-query'\nimport { deleteCrud, updateCrud } from \"@open-mercato/ui/backend/utils/crud\";\nimport { Button } from \"@open-mercato/ui/primitives/button\";\nimport { Badge } from \"@open-mercato/ui/primitives/badge\";\nimport Link from \"next/link\";\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog';\nimport { ListEmptyState } from \"@open-mercato/ui/backend/filters/ListEmptyState\";\nimport { FeatureToggleType } from \"../data/entities\";\n\ntype Row = {\n id: string\n identifier: string\n name: string\n description: string\n category?: string\n type: FeatureToggleType\n updatedAt?: string | null\n}\n\ntype BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'muted'\n\nexport function FeatureTogglesTable() {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const queryClient = useQueryClient()\n\n const featureToggleTypeLabelMap = React.useMemo(() => new Map<FeatureToggleType, { label: string; variant: BadgeVariant }>([\n ['boolean', { label: t('feature_toggles.types.boolean', 'Boolean'), variant: 'default' }],\n ['string', { label: t('feature_toggles.types.string', 'String'), variant: 'secondary' }],\n ['number', { label: t('feature_toggles.types.number', 'Number'), variant: 'outline' }],\n ['json', { label: t('feature_toggles.types.json', 'JSON'), variant: 'destructive' }],\n ]), [t])\n\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [pagination, setPagination] = React.useState({ page: 1, pageSize: 25 })\n\n const categoryFilterValue = typeof filterValues.category === 'string' ? filterValues.category.trim() : ''\n const nameFilterValue = typeof filterValues.name === 'string' ? filterValues.name.trim() : ''\n const identifierFilterValue = typeof filterValues.identifier === 'string' ? filterValues.identifier.trim() : ''\n const typeFilterValue = typeof filterValues.type === 'string' ? filterValues.type.trim() : ''\n const sortField = sorting.length > 0 ? sorting[0].id : 'category'\n const sortDir = sorting.length > 0 && sorting[0].desc ? 'desc' : 'asc'\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n if (categoryFilterValue) params.set('category', categoryFilterValue)\n if (nameFilterValue) params.set('name', nameFilterValue)\n if (identifierFilterValue) params.set('identifier', identifierFilterValue)\n if (typeFilterValue) params.set('type', typeFilterValue)\n\n params.set('sortField', sortField)\n params.set('sortDir', sortDir)\n\n params.set('page', pagination.page.toString())\n params.set('pageSize', pagination.pageSize.toString())\n\n return params.toString()\n }, [categoryFilterValue, identifierFilterValue, nameFilterValue, sortField, sortDir, typeFilterValue, pagination])\n\n const handleSortingChange = React.useCallback((newSorting: SortingState) => {\n setSorting(newSorting)\n }, [])\n\n const handlePageChange = React.useCallback((page: number) => {\n setPagination(prev => ({ ...prev, page }))\n }, [])\n\n const { data: featureTogglesData, isLoading } = useQuery({\n queryKey: ['feature_toggles', queryParams],\n queryFn: async () => {\n const call = await apiCall<{ items: Row[]; total: number; totalPages: number; page: number; pageSize: number; isSuperAdmin?: boolean }>(\n `/api/feature_toggles/global${queryParams ? `?${queryParams}` : ''}`,\n )\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.list.error.load', 'Failed to load feature toggles'))\n }\n return call.result ?? { items: [], total: 0, totalPages: 1, page: 1, pageSize: 25 }\n },\n })\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'identifier',\n label: t('feature_toggles.list.filters.identifier', 'Identifier'),\n type: 'text',\n },\n {\n id: 'name',\n label: t('feature_toggles.list.filters.name', 'Name'),\n type: 'text',\n },\n {\n id: 'category',\n label: t('feature_toggles.list.filters.category', 'Category'),\n type: 'text',\n },\n {\n id: 'type',\n label: t('feature_toggles.list.filters.type', 'Type'),\n type: 'select',\n options: [\n { label: t('feature_toggles.types.boolean', 'Boolean'), value: 'boolean' },\n { label: t('feature_toggles.types.string', 'String'), value: 'string' },\n { label: t('feature_toggles.types.number', 'Number'), value: 'number' },\n { label: t('feature_toggles.types.json', 'JSON'), value: 'json' },\n ],\n },\n ], [t])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n }, [])\n\n const deleteFeatureToggleMutation = useMutation({\n mutationFn: async (row: Row) => {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => deleteCrud('feature_toggles/global', row.id),\n )\n },\n onSuccess: async () => {\n await queryClient.invalidateQueries({ queryKey: ['feature_toggles'] })\n },\n })\n\n const handleDelete = React.useCallback(async (row: Row) => {\n const confirmed = await confirm({\n title: t('feature_toggles.list.confirmDelete', 'Delete feature toggle \"{identifier}\"?', { identifier: row.identifier }),\n variant: 'destructive',\n })\n if (!confirmed) return\n await deleteFeatureToggleMutation.mutateAsync(row)\n }, [confirm, deleteFeatureToggleMutation, t])\n\n const columns = React.useMemo<ColumnDef<Row>[]>(() => {\n const base: ColumnDef<Row>[] = [\n {\n accessorKey: 'category',\n header: t('feature_toggles.list.headers.category', 'Category'),\n enableSorting: true,\n cell: ({ row }) => {\n return row.original.category || '-'\n },\n },\n {\n accessorKey: 'identifier',\n header: t('feature_toggles.list.headers.identifier', 'Identifier'),\n enableSorting: true\n },\n {\n accessorKey: 'name',\n header: t('feature_toggles.list.headers.name', 'Name'),\n enableSorting: true\n },\n {\n accessorKey: 'type',\n header: t('feature_toggles.list.headers.type', 'Type'),\n enableSorting: true,\n cell: ({ row }) => {\n const typeInfo = featureToggleTypeLabelMap.get(row.original.type)\n if (!typeInfo) return '-'\n\n return (\n <Badge variant={typeInfo.variant}>\n {typeInfo.label}\n </Badge>\n )\n },\n },\n ]\n return base\n }, [t, featureToggleTypeLabelMap])\n\n return (\n <>\n <DataTable\n title={t('feature_toggles.global.help.title', 'Feature Toggles')}\n disableRowClick\n actions={\n <Button asChild>\n <Link href=\"/backend/feature-toggles/global/create\">\n {t('common.create', 'Create')}\n </Link>\n </Button>\n }\n columns={columns}\n data={featureTogglesData?.items ?? []}\n isLoading={isLoading}\n emptyState={(\n <ListEmptyState\n entityName={t('feature_toggles.global.help.title', 'Feature Toggles')}\n createHref=\"/backend/feature-toggles/global/create\"\n createLabel={t('common.create', 'Create')}\n />\n )}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n sorting={sorting}\n onSortingChange={handleSortingChange}\n sortable={true}\n pagination={{\n page: featureTogglesData?.page ?? 1,\n pageSize: featureTogglesData?.pageSize ?? 25,\n total: featureTogglesData?.total ?? 0,\n totalPages: featureTogglesData?.totalPages ?? 0,\n onPageChange: handlePageChange,\n }}\n rowActions={(row) => (\n <RowActions items={[\n { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.id}/edit` },\n { id: 'view', label: t('common.view', 'Overrides'), href: `/backend/feature-toggles/global/${row.id}` },\n { id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },\n ]} />\n )}\n />\n {ConfirmDialogElement}\n </>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/feature_toggles/components/OverridesTable.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport { DataTable } from \"@open-mercato/ui/backend/DataTable\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { apiCall } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { raiseCrudError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { ColumnDef
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport { DataTable } from \"@open-mercato/ui/backend/DataTable\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { apiCall } from \"@open-mercato/ui/backend/utils/apiCall\";\nimport { raiseCrudError } from \"@open-mercato/ui/backend/utils/serverErrors\";\nimport { useT } from \"@open-mercato/shared/lib/i18n/context\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport type { LegacyColumnDef as ColumnDef } from \"@tanstack/react-table/legacy\";\nimport type { SortingState } from \"@tanstack/react-table\";\nimport * as React from 'react'\nimport type { FilterDef, FilterValues } from \"@open-mercato/ui/backend/FilterBar\"\nimport { RowActions } from \"@open-mercato/ui/backend/RowActions\";\nimport { OverrideListResponse } from \"../data/validators\";\n\n\nexport default function OverridesTable() {\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sorting, setSorting] = React.useState<SortingState>([])\n const [pagination, setPagination] = React.useState({ page: 1, pageSize: 25 })\n\n const t = useT()\n const queryClient = useQueryClient()\n\n const sortField = sorting.length > 0 ? sorting[0].id : undefined\n const sortDir = sorting.length > 0 && sorting[0].desc ? 'desc' : 'asc'\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n Object.entries(filterValues).forEach(([key, value]) => {\n params.set(key, value as string)\n })\n if (sortField) params.set('sortField', sortField)\n if (sorting.length > 0) params.set('sortDir', sortDir)\n\n params.set('page', pagination.page.toString())\n params.set('pageSize', pagination.pageSize.toString())\n\n return params.toString()\n }, [filterValues, sortField, sortDir, pagination])\n\n const { data: featureTogglesData, isLoading, error } = useQuery({\n queryKey: ['feature_toggle_overrides', queryParams],\n queryFn: async () => {\n const call = await apiCall<{\n items: OverrideListResponse[];\n total: number;\n totalPages: number;\n page: number;\n pageSize: number;\n isSuperAdmin?: boolean\n }>(`/api/feature_toggles/overrides?${queryParams}`)\n if (!call.ok) {\n await raiseCrudError(call.response, t('feature_toggles.list.error.load', 'Failed to load feature toggles'))\n }\n return call.result ?? {\n items: [],\n total: 0,\n totalPages: 1,\n page: 1,\n pageSize: 25\n }\n },\n })\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n }, [])\n\n const handleSortingChange = React.useCallback((newSorting: SortingState) => {\n setSorting(newSorting)\n }, [])\n\n const handlePageChange = React.useCallback((page: number) => {\n setPagination(prev => ({ ...prev, page }))\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n void queryClient.refetchQueries({ queryKey: ['feature_toggle_overrides'] })\n }, [queryClient])\n\n const columns = React.useMemo<ColumnDef<OverrideListResponse>[]>(() => {\n return [\n {\n accessorKey: 'tenantName',\n header: t('feature_toggles.overrides.headers.tenant', 'Tenant'),\n enableSorting: true\n },\n {\n accessorKey: 'identifier',\n header: t('feature_toggles.overrides.headers.identifier', 'Identifier'),\n enableSorting: true\n },\n {\n accessorKey: 'name',\n header: t('feature_toggles.overrides.headers.name', 'Name'),\n enableSorting: true\n },\n {\n accessorKey: 'category',\n header: t('feature_toggles.overrides.headers.category', 'Category'),\n enableSorting: true\n },\n {\n accessorKey: 'isOverride',\n header: t('feature_toggles.overrides.headers.overrideState', 'Override'),\n enableSorting: false,\n cell: ({ row }) => {\n return row.original.isOverride ? t('feature_toggles.overrides.headers.isOverride.true', 'Yes') : t('feature_toggles.overrides.headers.isOverride.false', 'No')\n },\n },\n ]\n }, [])\n\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'identifier',\n label: t('feature_toggles.list.filters.identifier', 'Identifier'),\n type: 'text',\n },\n {\n id: 'name',\n label: t('feature_toggles.list.filters.name', 'Name'),\n type: 'text',\n },\n {\n id: 'category',\n label: t('feature_toggles.list.filters.category', 'Category'),\n type: 'text',\n }\n ], [t])\n\n return (\n <DataTable\n title={t('feature_toggles.overrides.help.title', 'Feature Toggle Overrides')}\n columns={columns}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n data={featureTogglesData?.items ?? []}\n isLoading={isLoading}\n sorting={sorting}\n onSortingChange={handleSortingChange}\n sortable={true}\n pagination={{\n page: featureTogglesData?.page ?? 1,\n pageSize: featureTogglesData?.pageSize ?? 25,\n total: featureTogglesData?.total ?? 0,\n totalPages: featureTogglesData?.totalPages ?? 0,\n onPageChange: handlePageChange,\n }}\n refreshButton={{\n label: t('feature_toggles.list.table.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n rowActions={(row) => (\n <RowActions items={[\n { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/feature-toggles/global/${row.toggleId}` },\n ]} />\n )}\n error={error ? error.message : undefined}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/inbox_ops/backend/inbox-ops/log/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ArrowLeft, RefreshCw } from 'lucide-react'\n\ntype EmailRow = {\n id: string\n subject: string\n forwardedByAddress: string\n forwardedByName?: string\n status: string\n processingError?: string\n receivedAt: string\n}\n\ntype EmailListResponse = {\n items?: EmailRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n received: 'bg-status-info-bg text-status-info-text',\n processing: 'bg-status-neutral-bg text-status-neutral-text',\n processed: 'bg-status-success-bg text-status-success-text',\n needs_review: 'bg-status-warning-bg text-status-warning-text',\n failed: 'bg-status-error-bg text-status-error-text',\n}\n\nexport default function ProcessingLogPage() {\n const t = useT()\n const [items, setItems] = React.useState<EmailRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [statusFilter, setStatusFilter] = React.useState<string | undefined>()\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [retryingEmailId, setRetryingEmailId] = React.useState<string | null>(null)\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-log',\n })\n\n const loadEmails = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n\n try {\n const result = await apiCall<EmailListResponse>(`/api/inbox_ops/emails?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.log.load_failed', 'Failed to load processing log'))\n }\n } catch {\n setError(t('inbox_ops.log.load_failed', 'Failed to load processing log'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, t])\n\n React.useEffect(() => { loadEmails() }, [loadEmails])\n\n const handleRetryEmail = React.useCallback(async (emailId: string) => {\n setRetryingEmailId(emailId)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/emails/${emailId}/reprocess`,\n { method: 'POST' },\n ),\n context: {},\n })\n\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.reprocessing_started', 'Reprocessing started'), 'success')\n await loadEmails()\n } else {\n flash(result?.result?.error || t('inbox_ops.extraction_failed', 'Extraction failed'), 'error')\n }\n\n setRetryingEmailId(null)\n }, [loadEmails, t, runMutation])\n\n const columns: ColumnDef<EmailRow>[] = React.useMemo(() => [\n {\n accessorKey: 'subject',\n header: t('inbox_ops.log.subject', 'Subject'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium truncate max-w-[300px] block\">{row.original.subject}</span>\n ),\n },\n {\n accessorKey: 'forwardedByAddress',\n header: t('inbox_ops.log.from', 'From'),\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground truncate max-w-[200px] block\">\n {row.original.forwardedByName || row.original.forwardedByAddress}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.log.status', 'Status'),\n cell: ({ row }) => {\n const statusLabels: Record<string, string> = {\n received: t('inbox_ops.log.tab_received', 'Received'),\n processing: t('inbox_ops.log.tab_processing', 'Processing'),\n processed: t('inbox_ops.log.tab_processed', 'Processed'),\n needs_review: t('inbox_ops.log.tab_needs_review', 'Needs Review'),\n failed: t('inbox_ops.log.tab_failed', 'Failed'),\n }\n const color = STATUS_COLORS[row.original.status] || 'bg-gray-100 text-gray-800'\n const label = statusLabels[row.original.status] || row.original.status\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{label}</span>\n },\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const d = new Date(row.original.receivedAt)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n {\n accessorKey: 'processingError',\n header: t('inbox_ops.extraction_failed', 'Error'),\n cell: ({ row }) => (\n <span className=\"text-xs text-status-error-text truncate max-w-[280px] block\">\n {row.original.processingError || '-'}\n </span>\n ),\n },\n {\n id: 'actions',\n header: t('ui.actions.actions', 'Actions'),\n cell: ({ row }) => {\n const canRetry = row.original.status === 'failed' || row.original.status === 'needs_review'\n if (!canRetry) {\n return <span className=\"text-xs text-muted-foreground\">-</span>\n }\n\n const isRetrying = retryingEmailId === row.original.id\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8\"\n disabled={isRetrying}\n onClick={() => handleRetryEmail(row.original.id)}\n >\n <RefreshCw className={`h-3.5 w-3.5 mr-1 ${isRetrying ? 'animate-spin' : ''}`} />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n )\n },\n },\n ], [handleRetryEmail, retryingEmailId, t])\n\n const tabs = [\n { label: t('inbox_ops.log.tab_all', 'All'), value: undefined },\n { label: t('inbox_ops.log.tab_received', 'Received'), value: 'received' },\n { label: t('inbox_ops.log.tab_processing', 'Processing'), value: 'processing' },\n { label: t('inbox_ops.log.tab_processed', 'Processed'), value: 'processed' },\n { label: t('inbox_ops.log.tab_needs_review', 'Needs Review'), value: 'needs_review' },\n { label: t('inbox_ops.log.tab_failed', 'Failed'), value: 'failed' },\n ]\n\n return (\n <Page>\n <div className=\"flex items-center gap-3 px-3 py-3 md:px-6 md:py-4\">\n <Link href=\"/backend/inbox-ops\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\"><ArrowLeft className=\"h-4 w-4\" /></Button>\n </Link>\n <h1 className=\"text-lg font-semibold\">{t('inbox_ops.processing_log', 'Processing Log')}</h1>\n </div>\n\n <PageBody>\n <div className=\"flex items-center gap-2 px-3 py-2 md:px-0 overflow-x-auto\">\n {tabs.map((tab) => (\n <Button\n type=\"button\"\n key={tab.value ?? 'all'}\n variant={statusFilter === tab.value ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => { setStatusFilter(tab.value); setPage(1) }}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n\n {error ? (\n <ErrorMessage label={error} />\n ) : (\n <div className=\"overflow-auto\">\n <div className=\"min-w-[640px]\">\n <DataTable\n columns={columns}\n data={items}\n isLoading={isLoading}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n />\n </div>\n </div>\n )}\n </PageBody>\n </Page>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\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 { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { ArrowLeft, RefreshCw } from 'lucide-react'\n\ntype EmailRow = {\n id: string\n subject: string\n forwardedByAddress: string\n forwardedByName?: string\n status: string\n processingError?: string\n receivedAt: string\n}\n\ntype EmailListResponse = {\n items?: EmailRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n received: 'bg-status-info-bg text-status-info-text',\n processing: 'bg-status-neutral-bg text-status-neutral-text',\n processed: 'bg-status-success-bg text-status-success-text',\n needs_review: 'bg-status-warning-bg text-status-warning-text',\n failed: 'bg-status-error-bg text-status-error-text',\n}\n\nexport default function ProcessingLogPage() {\n const t = useT()\n const [items, setItems] = React.useState<EmailRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [statusFilter, setStatusFilter] = React.useState<string | undefined>()\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [retryingEmailId, setRetryingEmailId] = React.useState<string | null>(null)\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-log',\n })\n\n const loadEmails = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n\n try {\n const result = await apiCall<EmailListResponse>(`/api/inbox_ops/emails?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.log.load_failed', 'Failed to load processing log'))\n }\n } catch {\n setError(t('inbox_ops.log.load_failed', 'Failed to load processing log'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, t])\n\n React.useEffect(() => { loadEmails() }, [loadEmails])\n\n const handleRetryEmail = React.useCallback(async (emailId: string) => {\n setRetryingEmailId(emailId)\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean; error?: string }>(\n `/api/inbox_ops/emails/${emailId}/reprocess`,\n { method: 'POST' },\n ),\n context: {},\n })\n\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.flash.reprocessing_started', 'Reprocessing started'), 'success')\n await loadEmails()\n } else {\n flash(result?.result?.error || t('inbox_ops.extraction_failed', 'Extraction failed'), 'error')\n }\n\n setRetryingEmailId(null)\n }, [loadEmails, t, runMutation])\n\n const columns: ColumnDef<EmailRow>[] = React.useMemo(() => [\n {\n accessorKey: 'subject',\n header: t('inbox_ops.log.subject', 'Subject'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium truncate max-w-[300px] block\">{row.original.subject}</span>\n ),\n },\n {\n accessorKey: 'forwardedByAddress',\n header: t('inbox_ops.log.from', 'From'),\n cell: ({ row }) => (\n <span className=\"text-sm text-muted-foreground truncate max-w-[200px] block\">\n {row.original.forwardedByName || row.original.forwardedByAddress}\n </span>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.log.status', 'Status'),\n cell: ({ row }) => {\n const statusLabels: Record<string, string> = {\n received: t('inbox_ops.log.tab_received', 'Received'),\n processing: t('inbox_ops.log.tab_processing', 'Processing'),\n processed: t('inbox_ops.log.tab_processed', 'Processed'),\n needs_review: t('inbox_ops.log.tab_needs_review', 'Needs Review'),\n failed: t('inbox_ops.log.tab_failed', 'Failed'),\n }\n const color = STATUS_COLORS[row.original.status] || 'bg-gray-100 text-gray-800'\n const label = statusLabels[row.original.status] || row.original.status\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{label}</span>\n },\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const d = new Date(row.original.receivedAt)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n {\n accessorKey: 'processingError',\n header: t('inbox_ops.extraction_failed', 'Error'),\n cell: ({ row }) => (\n <span className=\"text-xs text-status-error-text truncate max-w-[280px] block\">\n {row.original.processingError || '-'}\n </span>\n ),\n },\n {\n id: 'actions',\n header: t('ui.actions.actions', 'Actions'),\n cell: ({ row }) => {\n const canRetry = row.original.status === 'failed' || row.original.status === 'needs_review'\n if (!canRetry) {\n return <span className=\"text-xs text-muted-foreground\">-</span>\n }\n\n const isRetrying = retryingEmailId === row.original.id\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n className=\"h-8\"\n disabled={isRetrying}\n onClick={() => handleRetryEmail(row.original.id)}\n >\n <RefreshCw className={`h-3.5 w-3.5 mr-1 ${isRetrying ? 'animate-spin' : ''}`} />\n {t('inbox_ops.action.retry', 'Retry')}\n </Button>\n )\n },\n },\n ], [handleRetryEmail, retryingEmailId, t])\n\n const tabs = [\n { label: t('inbox_ops.log.tab_all', 'All'), value: undefined },\n { label: t('inbox_ops.log.tab_received', 'Received'), value: 'received' },\n { label: t('inbox_ops.log.tab_processing', 'Processing'), value: 'processing' },\n { label: t('inbox_ops.log.tab_processed', 'Processed'), value: 'processed' },\n { label: t('inbox_ops.log.tab_needs_review', 'Needs Review'), value: 'needs_review' },\n { label: t('inbox_ops.log.tab_failed', 'Failed'), value: 'failed' },\n ]\n\n return (\n <Page>\n <div className=\"flex items-center gap-3 px-3 py-3 md:px-6 md:py-4\">\n <Link href=\"/backend/inbox-ops\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\"><ArrowLeft className=\"h-4 w-4\" /></Button>\n </Link>\n <h1 className=\"text-lg font-semibold\">{t('inbox_ops.processing_log', 'Processing Log')}</h1>\n </div>\n\n <PageBody>\n <div className=\"flex items-center gap-2 px-3 py-2 md:px-0 overflow-x-auto\">\n {tabs.map((tab) => (\n <Button\n type=\"button\"\n key={tab.value ?? 'all'}\n variant={statusFilter === tab.value ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => { setStatusFilter(tab.value); setPage(1) }}\n >\n {tab.label}\n </Button>\n ))}\n </div>\n\n {error ? (\n <ErrorMessage label={error} />\n ) : (\n <div className=\"overflow-auto\">\n <div className=\"min-w-[640px]\">\n <DataTable\n columns={columns}\n data={items}\n isLoading={isLoading}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n />\n </div>\n </div>\n )}\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/inbox_ops/backend/inbox-ops/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\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 { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { Settings, Inbox, Copy } from 'lucide-react'\nimport { CategoryBadge, useCategoryLabels } from '../../components/proposals/CategoryBadge'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\n category?: string | null\n inboxEmailId: string\n createdAt: string\n participants?: { name: string; email: string }[]\n actionCount?: number\n pendingActionCount?: number\n discrepancyCount?: number\n emailSubject?: string | null\n emailFrom?: string | null\n receivedAt?: string | null\n}\n\ntype ProposalListResponse = {\n items?: ProposalRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\ntype StatusCounts = {\n pending: number\n partial: number\n accepted: number\n rejected: number\n byCategory?: Record<string, number>\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n partial: 'bg-blue-100 text-blue-800',\n accepted: 'bg-green-100 text-green-800',\n rejected: 'bg-red-100 text-red-800',\n processing: 'bg-purple-100 text-purple-800',\n}\n\nfunction ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'bg-green-100 text-green-800' : num >= 0.6 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{pct}%</span>\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const t = useT()\n const statusLabels: Record<string, string> = {\n pending: t('inbox_ops.status.pending', 'Pending'),\n partial: t('inbox_ops.status.partial', 'Partial'),\n accepted: t('inbox_ops.status.accepted', 'Accepted'),\n rejected: t('inbox_ops.status.rejected', 'Rejected'),\n processing: t('inbox_ops.status.processing', 'Processing'),\n }\n const color = STATUS_COLORS[status] || 'bg-gray-100 text-gray-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{statusLabels[status] || status}</span>\n}\n\nexport default function InboxOpsProposalsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-proposals',\n })\n\n const [items, setItems] = React.useState<ProposalRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [initialLoadComplete, setInitialLoadComplete] = React.useState(false)\n const [counts, setCounts] = React.useState<StatusCounts>({ pending: 0, partial: 0, accepted: 0, rejected: 0 })\n const [settings, setSettings] = React.useState<{ inboxAddress?: string } | null>(null)\n const [copied, setCopied] = React.useState(false)\n\n const statusFilter = typeof filterValues.status === 'string' ? filterValues.status : undefined\n const categoryFilter = typeof filterValues.category === 'string' ? filterValues.category : undefined\n\n const loadProposals = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n if (categoryFilter) params.set('category', categoryFilter)\n if (search.trim()) params.set('search', search.trim())\n\n try {\n const result = await apiCall<ProposalListResponse>(`/api/inbox_ops/proposals?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n } catch {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, categoryFilter, search, scopeVersion, t])\n\n const loadCounts = React.useCallback(async () => {\n const result = await apiCall<StatusCounts>('/api/inbox_ops/proposals/counts')\n if (result?.ok && result.result) setCounts(result.result)\n }, [scopeVersion])\n\n const loadSettings = React.useCallback(async () => {\n const result = await apiCall<{ settings: { inboxAddress?: string } | null }>('/api/inbox_ops/settings')\n if (result?.ok && result.result?.settings) setSettings(result.result.settings)\n }, [scopeVersion])\n\n React.useEffect(() => {\n Promise.all([loadProposals(), loadCounts(), loadSettings()]).then(() => {\n setInitialLoadComplete(true)\n })\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) loadProposals()\n }, [page, statusFilter, categoryFilter, search, scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) {\n loadCounts()\n loadSettings()\n }\n }, [scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleCopyAddress = React.useCallback(() => {\n if (settings?.inboxAddress) {\n navigator.clipboard.writeText(settings.inboxAddress)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }, [settings])\n\n const handleRefresh = React.useCallback(() => {\n loadProposals()\n loadCounts()\n }, [loadProposals, loadCounts])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRejectProposal = React.useCallback(async (proposalId: string) => {\n const confirmed = await confirm({\n title: t('inbox_ops.action.reject_all', 'Reject Proposal'),\n text: t('inbox_ops.action.reject_all_confirm', 'Reject all pending actions in this proposal?'),\n })\n if (!confirmed) return\n\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/reject`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.action.proposal_rejected', 'Proposal rejected'), 'success')\n loadProposals()\n loadCounts()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject'), 'error')\n }\n }, [confirm, t, loadProposals, loadCounts, runMutation])\n\n const categoryLabels = useCategoryLabels()\n const byCategory = counts.byCategory || {}\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('inbox_ops.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: `${t('inbox_ops.status.pending', 'Pending')} (${counts.pending})` },\n { value: 'partial', label: `${t('inbox_ops.status.partial', 'Partial')} (${counts.partial})` },\n { value: 'accepted', label: `${t('inbox_ops.status.accepted', 'Accepted')} (${counts.accepted})` },\n { value: 'rejected', label: `${t('inbox_ops.status.rejected', 'Rejected')} (${counts.rejected})` },\n ],\n },\n {\n id: 'category',\n label: t('inbox_ops.category', 'Category'),\n type: 'select',\n options: [\n { value: 'rfq', label: `${categoryLabels.rfq} (${byCategory.rfq || 0})` },\n { value: 'order', label: `${categoryLabels.order} (${byCategory.order || 0})` },\n { value: 'order_update', label: `${categoryLabels.order_update} (${byCategory.order_update || 0})` },\n { value: 'complaint', label: `${categoryLabels.complaint} (${byCategory.complaint || 0})` },\n { value: 'shipping_update', label: `${categoryLabels.shipping_update} (${byCategory.shipping_update || 0})` },\n { value: 'inquiry', label: `${categoryLabels.inquiry} (${byCategory.inquiry || 0})` },\n { value: 'payment', label: `${categoryLabels.payment} (${byCategory.payment || 0})` },\n { value: 'other', label: `${categoryLabels.other} (${byCategory.other || 0})` },\n ],\n },\n ], [t, counts, categoryLabels, byCategory])\n\n const columns: ColumnDef<ProposalRow>[] = React.useMemo(() => [\n {\n accessorKey: 'summary',\n header: t('inbox_ops.summary', 'Summary'),\n cell: ({ row }) => (\n <div className=\"min-w-0\">\n <Link\n href={`/backend/inbox-ops/proposals/${row.original.id}`}\n className=\"text-sm font-medium text-primary hover:underline truncate max-w-[300px] block\"\n >\n {row.original.emailSubject || row.original.summary?.slice(0, 80) || t('inbox_ops.untitled_proposal', 'Untitled proposal')}\n </Link>\n {row.original.emailFrom && (\n <span className=\"text-xs text-muted-foreground truncate block\">{row.original.emailFrom}</span>\n )}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.list.status', 'Status'),\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n {\n accessorKey: 'category',\n header: t('inbox_ops.category', 'Category'),\n cell: ({ row }) => <CategoryBadge category={row.original.category} />,\n },\n {\n id: 'actions_count',\n header: t('inbox_ops.list.progress', 'Progress'),\n cell: ({ row }) => {\n const pending = row.original.pendingActionCount ?? 0\n const total = row.original.actionCount ?? 0\n if (total === 0) return <span className=\"text-sm text-muted-foreground\">\u2014</span>\n return (\n <span className=\"text-sm text-muted-foreground\">\n {t('inbox_ops.list.action_summary', '{pending}/{total} actions')\n .replace('{pending}', String(pending))\n .replace('{total}', String(total))}\n </span>\n )\n },\n },\n {\n accessorKey: 'confidence',\n header: t('inbox_ops.confidence', 'Confidence'),\n cell: ({ row }) => <ConfidenceBadge value={row.original.confidence} />,\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const dateStr = row.original.receivedAt || row.original.createdAt\n const d = new Date(dateStr)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n ], [t])\n\n const totalCount = counts.pending + counts.partial + counts.accepted + counts.rejected\n\n const emptyStateContent = initialLoadComplete && totalCount === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <Inbox className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">{t('inbox_ops.empty.title', 'Forward emails to start')}</h2>\n {settings?.inboxAddress && (\n <div className=\"mt-4 flex items-center gap-2 bg-muted rounded-lg px-4 py-3\">\n <code className=\"text-sm font-mono\">{settings.inboxAddress}</code>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </Button>\n </div>\n )}\n <ol className=\"mt-6 text-sm text-muted-foreground text-left space-y-2\">\n <li>1. {t('inbox_ops.empty.step1', 'Forward any email thread to this address')}</li>\n <li>2. {t('inbox_ops.empty.step2', \"We'll analyze it and propose actions\")}</li>\n <li>3. {t('inbox_ops.empty.step3', 'Review and accept with one click')}</li>\n </ol>\n </div>\n ) : undefined\n\n if (error && !initialLoadComplete) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable<ProposalRow>\n stickyActionsColumn\n title={t('inbox_ops.title', 'AI Inbox Actions')}\n refreshButton={{\n label: t('inbox_ops.list.actions.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n }}\n actions={(\n <div className=\"flex items-center gap-2\">\n {settings?.inboxAddress && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </span>\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" asChild>\n <Link href=\"/backend/inbox-ops/settings\">\n <Settings className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">{t('inbox_ops.list.actions.settings', 'Settings')}</span>\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={items}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('inbox_ops.list.searchPlaceholder', 'Search proposals...')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/inbox-ops/proposals/${row.id}`)}\n rowActions={(row) => (\n <RowActions items={[\n {\n id: 'view',\n label: t('inbox_ops.list.actions.view', 'View'),\n onSelect: () => router.push(`/backend/inbox-ops/proposals/${row.id}`),\n },\n ...(row.status === 'pending' || row.status === 'partial' ? [{\n id: 'reject',\n label: t('inbox_ops.list.actions.reject', 'Reject'),\n destructive: true,\n onSelect: () => handleRejectProposal(row.id),\n }] : []),\n ]} />\n )}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n emptyState={emptyStateContent}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\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 { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { Settings, Inbox, Copy } from 'lucide-react'\nimport { CategoryBadge, useCategoryLabels } from '../../components/proposals/CategoryBadge'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\n category?: string | null\n inboxEmailId: string\n createdAt: string\n participants?: { name: string; email: string }[]\n actionCount?: number\n pendingActionCount?: number\n discrepancyCount?: number\n emailSubject?: string | null\n emailFrom?: string | null\n receivedAt?: string | null\n}\n\ntype ProposalListResponse = {\n items?: ProposalRow[]\n total?: number\n page?: number\n totalPages?: number\n}\n\ntype StatusCounts = {\n pending: number\n partial: number\n accepted: number\n rejected: number\n byCategory?: Record<string, number>\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n pending: 'bg-yellow-100 text-yellow-800',\n partial: 'bg-blue-100 text-blue-800',\n accepted: 'bg-green-100 text-green-800',\n rejected: 'bg-red-100 text-red-800',\n processing: 'bg-purple-100 text-purple-800',\n}\n\nfunction ConfidenceBadge({ value }: { value: string }) {\n const num = parseFloat(value)\n const pct = Math.round(num * 100)\n const color = num >= 0.8 ? 'bg-green-100 text-green-800' : num >= 0.6 ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{pct}%</span>\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const t = useT()\n const statusLabels: Record<string, string> = {\n pending: t('inbox_ops.status.pending', 'Pending'),\n partial: t('inbox_ops.status.partial', 'Partial'),\n accepted: t('inbox_ops.status.accepted', 'Accepted'),\n rejected: t('inbox_ops.status.rejected', 'Rejected'),\n processing: t('inbox_ops.status.processing', 'Processing'),\n }\n const color = STATUS_COLORS[status] || 'bg-gray-100 text-gray-800'\n return <span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${color}`}>{statusLabels[status] || status}</span>\n}\n\nexport default function InboxOpsProposalsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { runMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: 'inbox-ops-proposals',\n })\n\n const [items, setItems] = React.useState<ProposalRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [page, setPage] = React.useState(1)\n const [pageSize] = React.useState(25)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [initialLoadComplete, setInitialLoadComplete] = React.useState(false)\n const [counts, setCounts] = React.useState<StatusCounts>({ pending: 0, partial: 0, accepted: 0, rejected: 0 })\n const [settings, setSettings] = React.useState<{ inboxAddress?: string } | null>(null)\n const [copied, setCopied] = React.useState(false)\n\n const statusFilter = typeof filterValues.status === 'string' ? filterValues.status : undefined\n const categoryFilter = typeof filterValues.category === 'string' ? filterValues.category : undefined\n\n const loadProposals = React.useCallback(async () => {\n setIsLoading(true)\n setError(null)\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (statusFilter) params.set('status', statusFilter)\n if (categoryFilter) params.set('category', categoryFilter)\n if (search.trim()) params.set('search', search.trim())\n\n try {\n const result = await apiCall<ProposalListResponse>(`/api/inbox_ops/proposals?${params}`)\n if (result?.ok && result.result?.items) {\n setItems(result.result.items)\n setTotal(result.result.total || 0)\n } else {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n } catch {\n setError(t('inbox_ops.flash.load_failed', 'Failed to load proposals'))\n }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, categoryFilter, search, scopeVersion, t])\n\n const loadCounts = React.useCallback(async () => {\n const result = await apiCall<StatusCounts>('/api/inbox_ops/proposals/counts')\n if (result?.ok && result.result) setCounts(result.result)\n }, [scopeVersion])\n\n const loadSettings = React.useCallback(async () => {\n const result = await apiCall<{ settings: { inboxAddress?: string } | null }>('/api/inbox_ops/settings')\n if (result?.ok && result.result?.settings) setSettings(result.result.settings)\n }, [scopeVersion])\n\n React.useEffect(() => {\n Promise.all([loadProposals(), loadCounts(), loadSettings()]).then(() => {\n setInitialLoadComplete(true)\n })\n }, []) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) loadProposals()\n }, [page, statusFilter, categoryFilter, search, scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n React.useEffect(() => {\n if (initialLoadComplete) {\n loadCounts()\n loadSettings()\n }\n }, [scopeVersion]) // eslint-disable-line react-hooks/exhaustive-deps\n\n const handleCopyAddress = React.useCallback(() => {\n if (settings?.inboxAddress) {\n navigator.clipboard.writeText(settings.inboxAddress)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n }\n }, [settings])\n\n const handleRefresh = React.useCallback(() => {\n loadProposals()\n loadCounts()\n }, [loadProposals, loadCounts])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRejectProposal = React.useCallback(async (proposalId: string) => {\n const confirmed = await confirm({\n title: t('inbox_ops.action.reject_all', 'Reject Proposal'),\n text: t('inbox_ops.action.reject_all_confirm', 'Reject all pending actions in this proposal?'),\n })\n if (!confirmed) return\n\n const result = await runMutation({\n operation: () => apiCall<{ ok: boolean }>(\n `/api/inbox_ops/proposals/${proposalId}/reject`,\n { method: 'POST' },\n ),\n context: {},\n })\n if (result?.ok && result.result?.ok) {\n flash(t('inbox_ops.action.proposal_rejected', 'Proposal rejected'), 'success')\n loadProposals()\n loadCounts()\n } else {\n flash(t('inbox_ops.flash.action_reject_failed', 'Failed to reject'), 'error')\n }\n }, [confirm, t, loadProposals, loadCounts, runMutation])\n\n const categoryLabels = useCategoryLabels()\n const byCategory = counts.byCategory || {}\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'status',\n label: t('inbox_ops.list.filters.status', 'Status'),\n type: 'select',\n options: [\n { value: 'pending', label: `${t('inbox_ops.status.pending', 'Pending')} (${counts.pending})` },\n { value: 'partial', label: `${t('inbox_ops.status.partial', 'Partial')} (${counts.partial})` },\n { value: 'accepted', label: `${t('inbox_ops.status.accepted', 'Accepted')} (${counts.accepted})` },\n { value: 'rejected', label: `${t('inbox_ops.status.rejected', 'Rejected')} (${counts.rejected})` },\n ],\n },\n {\n id: 'category',\n label: t('inbox_ops.category', 'Category'),\n type: 'select',\n options: [\n { value: 'rfq', label: `${categoryLabels.rfq} (${byCategory.rfq || 0})` },\n { value: 'order', label: `${categoryLabels.order} (${byCategory.order || 0})` },\n { value: 'order_update', label: `${categoryLabels.order_update} (${byCategory.order_update || 0})` },\n { value: 'complaint', label: `${categoryLabels.complaint} (${byCategory.complaint || 0})` },\n { value: 'shipping_update', label: `${categoryLabels.shipping_update} (${byCategory.shipping_update || 0})` },\n { value: 'inquiry', label: `${categoryLabels.inquiry} (${byCategory.inquiry || 0})` },\n { value: 'payment', label: `${categoryLabels.payment} (${byCategory.payment || 0})` },\n { value: 'other', label: `${categoryLabels.other} (${byCategory.other || 0})` },\n ],\n },\n ], [t, counts, categoryLabels, byCategory])\n\n const columns: ColumnDef<ProposalRow>[] = React.useMemo(() => [\n {\n accessorKey: 'summary',\n header: t('inbox_ops.summary', 'Summary'),\n cell: ({ row }) => (\n <div className=\"min-w-0\">\n <Link\n href={`/backend/inbox-ops/proposals/${row.original.id}`}\n className=\"text-sm font-medium text-primary hover:underline truncate max-w-[300px] block\"\n >\n {row.original.emailSubject || row.original.summary?.slice(0, 80) || t('inbox_ops.untitled_proposal', 'Untitled proposal')}\n </Link>\n {row.original.emailFrom && (\n <span className=\"text-xs text-muted-foreground truncate block\">{row.original.emailFrom}</span>\n )}\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: t('inbox_ops.list.status', 'Status'),\n cell: ({ row }) => <StatusBadge status={row.original.status} />,\n },\n {\n accessorKey: 'category',\n header: t('inbox_ops.category', 'Category'),\n cell: ({ row }) => <CategoryBadge category={row.original.category} />,\n },\n {\n id: 'actions_count',\n header: t('inbox_ops.list.progress', 'Progress'),\n cell: ({ row }) => {\n const pending = row.original.pendingActionCount ?? 0\n const total = row.original.actionCount ?? 0\n if (total === 0) return <span className=\"text-sm text-muted-foreground\">\u2014</span>\n return (\n <span className=\"text-sm text-muted-foreground\">\n {t('inbox_ops.list.action_summary', '{pending}/{total} actions')\n .replace('{pending}', String(pending))\n .replace('{total}', String(total))}\n </span>\n )\n },\n },\n {\n accessorKey: 'confidence',\n header: t('inbox_ops.confidence', 'Confidence'),\n cell: ({ row }) => <ConfidenceBadge value={row.original.confidence} />,\n },\n {\n accessorKey: 'receivedAt',\n header: t('inbox_ops.received_at', 'Received'),\n cell: ({ row }) => {\n const dateStr = row.original.receivedAt || row.original.createdAt\n const d = new Date(dateStr)\n return <span className=\"text-sm text-muted-foreground\">{d.toLocaleDateString()} {d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>\n },\n },\n ], [t])\n\n const totalCount = counts.pending + counts.partial + counts.accepted + counts.rejected\n\n const emptyStateContent = initialLoadComplete && totalCount === 0 ? (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <Inbox className=\"h-12 w-12 text-muted-foreground mb-4\" />\n <h2 className=\"text-lg font-semibold mb-2\">{t('inbox_ops.empty.title', 'Forward emails to start')}</h2>\n {settings?.inboxAddress && (\n <div className=\"mt-4 flex items-center gap-2 bg-muted rounded-lg px-4 py-3\">\n <code className=\"text-sm font-mono\">{settings.inboxAddress}</code>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </Button>\n </div>\n )}\n <ol className=\"mt-6 text-sm text-muted-foreground text-left space-y-2\">\n <li>1. {t('inbox_ops.empty.step1', 'Forward any email thread to this address')}</li>\n <li>2. {t('inbox_ops.empty.step2', \"We'll analyze it and propose actions\")}</li>\n <li>3. {t('inbox_ops.empty.step3', 'Review and accept with one click')}</li>\n </ol>\n </div>\n ) : undefined\n\n if (error && !initialLoadComplete) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <DataTable<ProposalRow>\n stickyActionsColumn\n title={t('inbox_ops.title', 'AI Inbox Actions')}\n refreshButton={{\n label: t('inbox_ops.list.actions.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n }}\n actions={(\n <div className=\"flex items-center gap-2\">\n {settings?.inboxAddress && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCopyAddress}>\n <Copy className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">\n {copied ? t('inbox_ops.settings.copied', 'Copied') : t('inbox_ops.settings.copy', 'Copy')}\n </span>\n </Button>\n )}\n <Button variant=\"outline\" size=\"sm\" asChild>\n <Link href=\"/backend/inbox-ops/settings\">\n <Settings className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">{t('inbox_ops.list.actions.settings', 'Settings')}</span>\n </Link>\n </Button>\n </div>\n )}\n columns={columns}\n data={items}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('inbox_ops.list.searchPlaceholder', 'Search proposals...')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n onRowClick={(row) => router.push(`/backend/inbox-ops/proposals/${row.id}`)}\n rowActions={(row) => (\n <RowActions items={[\n {\n id: 'view',\n label: t('inbox_ops.list.actions.view', 'View'),\n onSelect: () => router.push(`/backend/inbox-ops/proposals/${row.id}`),\n },\n ...(row.status === 'pending' || row.status === 'partial' ? [{\n id: 'reject',\n label: t('inbox_ops.list.actions.reject', 'Reject'),\n destructive: true,\n onSelect: () => handleRejectProposal(row.id),\n }] : []),\n ]} />\n )}\n pagination={{\n page,\n pageSize,\n total,\n totalPages: Math.ceil(total / pageSize),\n onPageChange: setPage,\n }}\n isLoading={isLoading}\n emptyState={emptyStateContent}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["total"]
|
|
7
7
|
}
|