@open-mercato/core 0.4.5-develop-636d33c995 → 0.4.5-develop-3d8e759e45
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/catalog/backend/catalog/categories/[id]/edit/page.js +17 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +30 -0
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/inbox-actions.js +51 -0
- package/dist/modules/catalog/inbox-actions.js.map +7 -0
- package/dist/modules/catalog/lib/messageObjectPreviews.js +146 -0
- package/dist/modules/catalog/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/catalog/message-objects.js +95 -0
- package/dist/modules/catalog/message-objects.js.map +7 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js +21 -0
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/lib/messageObjectPreviews.js +51 -0
- package/dist/modules/currencies/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/currencies/message-objects.js +41 -0
- package/dist/modules/currencies/message-objects.js.map +7 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -1
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/[id]/page.js +20 -0
- package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyHighlights.js +18 -14
- package/dist/modules/customers/components/detail/CompanyHighlights.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonHighlights.js +18 -14
- package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
- package/dist/modules/customers/inbox-actions.js +230 -0
- package/dist/modules/customers/inbox-actions.js.map +7 -0
- package/dist/modules/customers/lib/messageObjectPreviews.js +41 -5
- package/dist/modules/customers/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/customers/message-objects.js +31 -11
- package/dist/modules/customers/message-objects.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js +40 -1
- package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/extract/route.js +87 -0
- package/dist/modules/inbox_ops/api/extract/route.js.map +7 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js +6 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +40 -14
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js +161 -79
- package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +109 -62
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +3 -3
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +36 -14
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js +2 -2
- package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js +65 -10
- package/dist/modules/inbox_ops/components/proposals/ActionCard.js.map +2 -2
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +58 -10
- package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
- package/dist/modules/inbox_ops/lib/constants.js.map +2 -2
- package/dist/modules/inbox_ops/lib/contactValidation.js +40 -0
- package/dist/modules/inbox_ops/lib/contactValidation.js.map +7 -0
- package/dist/modules/inbox_ops/lib/executionEngine.js +31 -826
- package/dist/modules/inbox_ops/lib/executionEngine.js.map +3 -3
- package/dist/modules/inbox_ops/lib/executionHelpers.js +368 -0
- package/dist/modules/inbox_ops/lib/executionHelpers.js.map +7 -0
- package/dist/modules/inbox_ops/lib/extractionPrompt.js +28 -35
- package/dist/modules/inbox_ops/lib/extractionPrompt.js.map +3 -3
- package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js +1 -0
- package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js.map +7 -0
- package/dist/modules/inbox_ops/lib/translationProvider.js +15 -10
- package/dist/modules/inbox_ops/lib/translationProvider.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js +16 -16
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +3 -0
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js +6 -1
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +2 -2
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +4 -1
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
- package/dist/modules/messages/frontend/messages/view/[token]/page.js +1 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -7
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/lib/messageObjectPreviews.js +43 -0
- package/dist/modules/resources/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/resources/message-objects.js +37 -0
- package/dist/modules/resources/message-objects.js.map +7 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +19 -0
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +23 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js +1 -1
- package/dist/modules/sales/backend/sales/quotes/[id]/page.js.map +2 -2
- package/dist/modules/sales/inbox-actions.js +278 -0
- package/dist/modules/sales/inbox-actions.js.map +7 -0
- package/dist/modules/sales/lib/messageObjectPreviews.js +49 -4
- package/dist/modules/sales/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/sales/message-objects.js +44 -2
- package/dist/modules/sales/message-objects.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +59 -30
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +2 -2
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +8 -30
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-availability/page.js +13 -0
- package/dist/modules/staff/backend/staff/my-availability/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +8 -31
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +32 -10
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +4 -2
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamRoleForm.js +4 -2
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js +111 -2
- package/dist/modules/staff/lib/messageObjectPreviews.js.map +2 -2
- package/dist/modules/staff/message-objects.js +79 -8
- package/dist/modules/staff/message-objects.js.map +2 -2
- package/jest.config.cjs +1 -0
- package/jest.mocks/inbox-actions.generated.js +5 -0
- package/package.json +2 -2
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +19 -5
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +14 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +40 -0
- package/src/modules/catalog/inbox-actions.ts +60 -0
- package/src/modules/catalog/lib/messageObjectPreviews.ts +176 -0
- package/src/modules/catalog/message-objects.ts +102 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -0
- package/src/modules/currencies/lib/messageObjectPreviews.ts +65 -0
- package/src/modules/currencies/message-objects.ts +40 -0
- package/src/modules/customers/backend/customers/companies/[id]/page.tsx +19 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +13 -0
- package/src/modules/customers/backend/customers/people/[id]/page.tsx +19 -0
- package/src/modules/customers/components/detail/CompanyHighlights.tsx +14 -9
- package/src/modules/customers/components/detail/PersonHighlights.tsx +14 -9
- package/src/modules/customers/inbox-actions.ts +285 -0
- package/src/modules/customers/lib/messageObjectPreviews.ts +43 -3
- package/src/modules/customers/message-objects.ts +31 -11
- package/src/modules/inbox_ops/api/emails/[id]/route.ts +44 -0
- package/src/modules/inbox_ops/api/extract/route.ts +94 -0
- package/src/modules/inbox_ops/api/proposals/[id]/translate/route.ts +6 -1
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +2 -0
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +43 -13
- package/src/modules/inbox_ops/backend/inbox-ops/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +176 -81
- package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +122 -68
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.meta.ts +2 -2
- package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +36 -14
- package/src/modules/inbox_ops/components/proposals/ActionCard.tsx +91 -7
- package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +64 -12
- package/src/modules/inbox_ops/lib/constants.ts +9 -0
- package/src/modules/inbox_ops/lib/contactValidation.ts +54 -0
- package/src/modules/inbox_ops/lib/executionEngine.ts +47 -1060
- package/src/modules/inbox_ops/lib/executionHelpers.ts +527 -0
- package/src/modules/inbox_ops/lib/extractionPrompt.ts +45 -34
- package/src/modules/inbox_ops/lib/inbox-actions-generated.d.ts +11 -0
- package/src/modules/inbox_ops/lib/translationProvider.ts +16 -10
- package/src/modules/inbox_ops/subscribers/extractionWorker.ts +16 -18
- package/src/modules/messages/commands/messages.ts +4 -0
- package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +8 -1
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +3 -0
- package/src/modules/messages/frontend/messages/view/[token]/page.tsx +1 -0
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +20 -4
- package/src/modules/resources/lib/messageObjectPreviews.ts +55 -0
- package/src/modules/resources/message-objects.ts +36 -0
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +18 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -0
- package/src/modules/sales/backend/sales/quotes/[id]/page.tsx +1 -1
- package/src/modules/sales/inbox-actions.ts +359 -0
- package/src/modules/sales/lib/messageObjectPreviews.ts +54 -4
- package/src/modules/sales/message-objects.ts +44 -2
- package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +72 -34
- package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +7 -29
- package/src/modules/staff/backend/staff/my-availability/page.tsx +14 -0
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +8 -30
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +28 -7
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +12 -0
- package/src/modules/staff/components/TeamForm.tsx +3 -0
- package/src/modules/staff/components/TeamRoleForm.tsx +3 -0
- package/src/modules/staff/lib/messageObjectPreviews.ts +133 -2
- package/src/modules/staff/message-objects.ts +79 -8
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +0 -51
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +0 -7
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +0 -35
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +0 -7
- package/dist/modules/customers/widgets/messages/index.js +0 -7
- package/dist/modules/customers/widgets/messages/index.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +0 -51
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +0 -7
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +0 -34
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +0 -7
- package/dist/modules/staff/widgets/messages/index.js +0 -7
- package/dist/modules/staff/widgets/messages/index.js.map +0 -7
- package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +0 -57
- package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +0 -49
- package/src/modules/customers/widgets/messages/index.ts +0 -2
- package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +0 -57
- package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +0 -44
- package/src/modules/staff/widgets/messages/index.ts +0 -2
|
@@ -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 { 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-blue-100 text-blue-800',\n processing: 'bg-purple-100 text-purple-800',\n processed: 'bg-green-100 text-green-800',\n needs_review: 'bg-amber-100 text-amber-800',\n failed: 'bg-red-100 text-red-800',\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 [retryingEmailId, setRetryingEmailId] = React.useState<string | null>(null)\n\n const loadEmails = React.useCallback(async () => {\n setIsLoading(true)\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 const result = await apiCall<EmailListResponse>(`/api/inbox_ops/emails?${params}`)\n
|
|
5
|
-
"mappings": ";
|
|
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-blue-100 text-blue-800',\n processing: 'bg-purple-100 text-purple-800',\n processed: 'bg-green-100 text-green-800',\n needs_review: 'bg-amber-100 text-amber-800',\n failed: 'bg-red-100 text-red-800',\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-red-600 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
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,12 +3,12 @@ const metadata = {
|
|
|
3
3
|
requireFeatures: ["inbox_ops.log.view"],
|
|
4
4
|
pageTitle: "Processing Log",
|
|
5
5
|
pageTitleKey: "inbox_ops.nav.log",
|
|
6
|
-
pageGroup: "
|
|
6
|
+
pageGroup: "AI Inbox Actions",
|
|
7
7
|
pageGroupKey: "inbox_ops.nav.group",
|
|
8
8
|
pageOrder: 910,
|
|
9
9
|
navHidden: true,
|
|
10
10
|
breadcrumb: [
|
|
11
|
-
{ label: "
|
|
11
|
+
{ label: "AI Inbox Actions", labelKey: "inbox_ops.nav.group", href: "/backend/inbox-ops" },
|
|
12
12
|
{ label: "Processing Log", labelKey: "inbox_ops.nav.log" }
|
|
13
13
|
]
|
|
14
14
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/inbox_ops/backend/inbox-ops/log/page.meta.ts"],
|
|
4
|
-
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.log.view'],\n pageTitle: 'Processing Log',\n pageTitleKey: 'inbox_ops.nav.log',\n pageGroup: '
|
|
5
|
-
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,oBAAoB;AAAA,EACtC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.log.view'],\n pageTitle: 'Processing Log',\n pageTitleKey: 'inbox_ops.nav.log',\n pageGroup: 'AI Inbox Actions',\n pageGroupKey: 'inbox_ops.nav.group',\n pageOrder: 910,\n navHidden: true,\n breadcrumb: [\n { label: 'AI Inbox Actions', labelKey: 'inbox_ops.nav.group', href: '/backend/inbox-ops' },\n { label: 'Processing Log', labelKey: 'inbox_ops.nav.log' },\n ],\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,oBAAoB;AAAA,EACtC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,IACV,EAAE,OAAO,oBAAoB,UAAU,uBAAuB,MAAM,qBAAqB;AAAA,IACzF,EAAE,OAAO,kBAAkB,UAAU,oBAAoB;AAAA,EAC3D;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
6
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
7
7
|
import { DataTable } from "@open-mercato/ui/backend/DataTable";
|
|
8
|
+
import { RowActions } from "@open-mercato/ui/backend/RowActions";
|
|
8
9
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
9
10
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
11
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
10
12
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
11
13
|
import { useOrganizationScopeVersion } from "@open-mercato/shared/lib/frontend/useOrganizationScope";
|
|
14
|
+
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
15
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
16
|
+
import { ErrorMessage } from "@open-mercato/ui/backend/detail";
|
|
12
17
|
import { Settings, Inbox, Copy } from "lucide-react";
|
|
13
18
|
const STATUS_COLORS = {
|
|
14
19
|
pending: "bg-yellow-100 text-yellow-800",
|
|
@@ -42,30 +47,44 @@ function InboxOpsProposalsPage() {
|
|
|
42
47
|
const t = useT();
|
|
43
48
|
const router = useRouter();
|
|
44
49
|
const scopeVersion = useOrganizationScopeVersion();
|
|
50
|
+
const { confirm, ConfirmDialogElement } = useConfirmDialog();
|
|
51
|
+
const { runMutation } = useGuardedMutation({
|
|
52
|
+
contextId: "inbox-ops-proposals"
|
|
53
|
+
});
|
|
45
54
|
const [items, setItems] = React.useState([]);
|
|
46
55
|
const [total, setTotal] = React.useState(0);
|
|
47
56
|
const [page, setPage] = React.useState(1);
|
|
48
57
|
const [pageSize] = React.useState(25);
|
|
49
|
-
const [
|
|
58
|
+
const [filterValues, setFilterValues] = React.useState({});
|
|
50
59
|
const [search, setSearch] = React.useState("");
|
|
51
60
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
61
|
+
const [error, setError] = React.useState(null);
|
|
62
|
+
const [initialLoadComplete, setInitialLoadComplete] = React.useState(false);
|
|
52
63
|
const [counts, setCounts] = React.useState({ pending: 0, partial: 0, accepted: 0, rejected: 0 });
|
|
53
64
|
const [settings, setSettings] = React.useState(null);
|
|
54
65
|
const [copied, setCopied] = React.useState(false);
|
|
66
|
+
const statusFilter = typeof filterValues.status === "string" ? filterValues.status : void 0;
|
|
55
67
|
const loadProposals = React.useCallback(async () => {
|
|
56
68
|
setIsLoading(true);
|
|
69
|
+
setError(null);
|
|
57
70
|
const params = new URLSearchParams();
|
|
58
71
|
params.set("page", String(page));
|
|
59
72
|
params.set("pageSize", String(pageSize));
|
|
60
73
|
if (statusFilter) params.set("status", statusFilter);
|
|
61
|
-
if (search) params.set("search", search);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
if (search.trim()) params.set("search", search.trim());
|
|
75
|
+
try {
|
|
76
|
+
const result = await apiCall(`/api/inbox_ops/proposals?${params}`);
|
|
77
|
+
if (result?.ok && result.result?.items) {
|
|
78
|
+
setItems(result.result.items);
|
|
79
|
+
setTotal(result.result.total || 0);
|
|
80
|
+
} else {
|
|
81
|
+
setError(t("inbox_ops.flash.load_failed", "Failed to load proposals"));
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
setError(t("inbox_ops.flash.load_failed", "Failed to load proposals"));
|
|
66
85
|
}
|
|
67
86
|
setIsLoading(false);
|
|
68
|
-
}, [page, pageSize, statusFilter, search, scopeVersion]);
|
|
87
|
+
}, [page, pageSize, statusFilter, search, scopeVersion, t]);
|
|
69
88
|
const loadCounts = React.useCallback(async () => {
|
|
70
89
|
const result = await apiCall("/api/inbox_ops/proposals/counts");
|
|
71
90
|
if (result?.ok && result.result) setCounts(result.result);
|
|
@@ -75,10 +94,13 @@ function InboxOpsProposalsPage() {
|
|
|
75
94
|
if (result?.ok && result.result?.settings) setSettings(result.result.settings);
|
|
76
95
|
}, [scopeVersion]);
|
|
77
96
|
React.useEffect(() => {
|
|
78
|
-
loadProposals()
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}, [
|
|
97
|
+
Promise.all([loadProposals(), loadCounts(), loadSettings()]).then(() => {
|
|
98
|
+
setInitialLoadComplete(true);
|
|
99
|
+
});
|
|
100
|
+
}, []);
|
|
101
|
+
React.useEffect(() => {
|
|
102
|
+
if (initialLoadComplete) loadProposals();
|
|
103
|
+
}, [page, statusFilter, search, scopeVersion]);
|
|
82
104
|
const handleCopyAddress = React.useCallback(() => {
|
|
83
105
|
if (settings?.inboxAddress) {
|
|
84
106
|
navigator.clipboard.writeText(settings.inboxAddress);
|
|
@@ -86,6 +108,52 @@ function InboxOpsProposalsPage() {
|
|
|
86
108
|
setTimeout(() => setCopied(false), 2e3);
|
|
87
109
|
}
|
|
88
110
|
}, [settings]);
|
|
111
|
+
const handleRefresh = React.useCallback(() => {
|
|
112
|
+
loadProposals();
|
|
113
|
+
loadCounts();
|
|
114
|
+
}, [loadProposals, loadCounts]);
|
|
115
|
+
const handleFiltersApply = React.useCallback((values) => {
|
|
116
|
+
setFilterValues(values);
|
|
117
|
+
setPage(1);
|
|
118
|
+
}, []);
|
|
119
|
+
const handleFiltersClear = React.useCallback(() => {
|
|
120
|
+
setFilterValues({});
|
|
121
|
+
setPage(1);
|
|
122
|
+
}, []);
|
|
123
|
+
const handleRejectProposal = React.useCallback(async (proposalId) => {
|
|
124
|
+
const confirmed = await confirm({
|
|
125
|
+
title: t("inbox_ops.action.reject_all", "Reject Proposal"),
|
|
126
|
+
text: t("inbox_ops.action.reject_all_confirm", "Reject all pending actions in this proposal?")
|
|
127
|
+
});
|
|
128
|
+
if (!confirmed) return;
|
|
129
|
+
const result = await runMutation({
|
|
130
|
+
operation: () => apiCall(
|
|
131
|
+
`/api/inbox_ops/proposals/${proposalId}/reject`,
|
|
132
|
+
{ method: "POST" }
|
|
133
|
+
),
|
|
134
|
+
context: {}
|
|
135
|
+
});
|
|
136
|
+
if (result?.ok && result.result?.ok) {
|
|
137
|
+
flash(t("inbox_ops.action.proposal_rejected", "Proposal rejected"), "success");
|
|
138
|
+
loadProposals();
|
|
139
|
+
loadCounts();
|
|
140
|
+
} else {
|
|
141
|
+
flash(t("inbox_ops.flash.action_reject_failed", "Failed to reject"), "error");
|
|
142
|
+
}
|
|
143
|
+
}, [confirm, t, loadProposals, loadCounts, runMutation]);
|
|
144
|
+
const filters = React.useMemo(() => [
|
|
145
|
+
{
|
|
146
|
+
id: "status",
|
|
147
|
+
label: t("inbox_ops.list.filters.status", "Status"),
|
|
148
|
+
type: "select",
|
|
149
|
+
options: [
|
|
150
|
+
{ value: "pending", label: `${t("inbox_ops.status.pending", "Pending")} (${counts.pending})` },
|
|
151
|
+
{ value: "partial", label: `${t("inbox_ops.status.partial", "Partial")} (${counts.partial})` },
|
|
152
|
+
{ value: "accepted", label: `${t("inbox_ops.status.accepted", "Accepted")} (${counts.accepted})` },
|
|
153
|
+
{ value: "rejected", label: `${t("inbox_ops.status.rejected", "Rejected")} (${counts.rejected})` }
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
], [t, counts]);
|
|
89
157
|
const columns = React.useMemo(() => [
|
|
90
158
|
{
|
|
91
159
|
accessorKey: "summary",
|
|
@@ -109,7 +177,7 @@ function InboxOpsProposalsPage() {
|
|
|
109
177
|
},
|
|
110
178
|
{
|
|
111
179
|
id: "actions_count",
|
|
112
|
-
header: t("inbox_ops.
|
|
180
|
+
header: t("inbox_ops.list.progress", "Progress"),
|
|
113
181
|
cell: ({ row }) => {
|
|
114
182
|
const pending = row.original.pendingActionCount ?? 0;
|
|
115
183
|
const total2 = row.original.actionCount ?? 0;
|
|
@@ -137,77 +205,91 @@ function InboxOpsProposalsPage() {
|
|
|
137
205
|
}
|
|
138
206
|
], [t]);
|
|
139
207
|
const totalCount = counts.pending + counts.partial + counts.accepted + counts.rejected;
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
{
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-3 md:px-6 md:py-4", children: [
|
|
150
|
-
/* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold", children: t("inbox_ops.title", "InboxOps") }),
|
|
151
|
-
/* @__PURE__ */ jsx(Link, { href: "/backend/inbox-ops/settings", children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", children: [
|
|
152
|
-
/* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
|
|
153
|
-
/* @__PURE__ */ jsx("span", { className: "hidden md:inline ml-1", children: t("inbox_ops.settings.title", "Settings") })
|
|
154
|
-
] }) })
|
|
208
|
+
const emptyStateContent = initialLoadComplete && totalCount === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
209
|
+
/* @__PURE__ */ jsx(Inbox, { className: "h-12 w-12 text-muted-foreground mb-4" }),
|
|
210
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold mb-2", children: t("inbox_ops.empty.title", "Forward emails to start") }),
|
|
211
|
+
settings?.inboxAddress && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2 bg-muted rounded-lg px-4 py-3", children: [
|
|
212
|
+
/* @__PURE__ */ jsx("code", { className: "text-sm font-mono", children: settings.inboxAddress }),
|
|
213
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleCopyAddress, children: [
|
|
214
|
+
/* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
|
|
215
|
+
copied ? t("inbox_ops.settings.copied", "Copied") : t("inbox_ops.settings.copy", "Copy")
|
|
216
|
+
] })
|
|
155
217
|
] }),
|
|
156
|
-
/* @__PURE__ */
|
|
157
|
-
/* @__PURE__ */
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
/* @__PURE__ */ jsx("code", { className: "text-sm font-mono", children: settings.inboxAddress }),
|
|
161
|
-
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: handleCopyAddress, children: [
|
|
162
|
-
/* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
|
|
163
|
-
copied ? t("inbox_ops.settings.copied", "Copied") : t("inbox_ops.settings.copy", "Copy")
|
|
164
|
-
] })
|
|
218
|
+
/* @__PURE__ */ jsxs("ol", { className: "mt-6 text-sm text-muted-foreground text-left space-y-2", children: [
|
|
219
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
220
|
+
"1. ",
|
|
221
|
+
t("inbox_ops.empty.step1", "Forward any email thread to this address")
|
|
165
222
|
] }),
|
|
166
|
-
/* @__PURE__ */ jsxs("
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
t("inbox_ops.empty.step2", "We'll analyze it and propose actions")
|
|
174
|
-
] }),
|
|
175
|
-
/* @__PURE__ */ jsxs("li", { children: [
|
|
176
|
-
"3. ",
|
|
177
|
-
t("inbox_ops.empty.step3", "Review and accept with one click")
|
|
178
|
-
] })
|
|
223
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
224
|
+
"2. ",
|
|
225
|
+
t("inbox_ops.empty.step2", "We'll analyze it and propose actions")
|
|
226
|
+
] }),
|
|
227
|
+
/* @__PURE__ */ jsxs("li", { children: [
|
|
228
|
+
"3. ",
|
|
229
|
+
t("inbox_ops.empty.step3", "Review and accept with one click")
|
|
179
230
|
] })
|
|
180
|
-
] })
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
231
|
+
] })
|
|
232
|
+
] }) : void 0;
|
|
233
|
+
if (error && !initialLoadComplete) {
|
|
234
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error }) }) });
|
|
235
|
+
}
|
|
236
|
+
return /* @__PURE__ */ jsxs(Page, { children: [
|
|
237
|
+
/* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
238
|
+
DataTable,
|
|
239
|
+
{
|
|
240
|
+
title: t("inbox_ops.title", "AI Inbox Actions"),
|
|
241
|
+
refreshButton: {
|
|
242
|
+
label: t("inbox_ops.list.actions.refresh", "Refresh"),
|
|
243
|
+
onRefresh: handleRefresh
|
|
244
|
+
},
|
|
245
|
+
actions: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
246
|
+
settings?.inboxAddress && /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleCopyAddress, children: [
|
|
247
|
+
/* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" }),
|
|
248
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline ml-1", children: copied ? t("inbox_ops.settings.copied", "Copied") : t("inbox_ops.settings.copy", "Copy") })
|
|
249
|
+
] }),
|
|
250
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", asChild: true, children: /* @__PURE__ */ jsxs(Link, { href: "/backend/inbox-ops/settings", children: [
|
|
251
|
+
/* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" }),
|
|
252
|
+
/* @__PURE__ */ jsx("span", { className: "hidden md:inline ml-1", children: t("inbox_ops.list.actions.settings", "Settings") })
|
|
253
|
+
] }) })
|
|
254
|
+
] }),
|
|
255
|
+
columns,
|
|
256
|
+
data: items,
|
|
257
|
+
searchValue: search,
|
|
258
|
+
onSearchChange: (value) => {
|
|
259
|
+
setSearch(value);
|
|
260
|
+
setPage(1);
|
|
261
|
+
},
|
|
262
|
+
searchPlaceholder: t("inbox_ops.list.searchPlaceholder", "Search proposals..."),
|
|
263
|
+
filters,
|
|
264
|
+
filterValues,
|
|
265
|
+
onFiltersApply: handleFiltersApply,
|
|
266
|
+
onFiltersClear: handleFiltersClear,
|
|
267
|
+
onRowClick: (row) => router.push(`/backend/inbox-ops/proposals/${row.id}`),
|
|
268
|
+
rowActions: (row) => /* @__PURE__ */ jsx(RowActions, { items: [
|
|
269
|
+
{
|
|
270
|
+
id: "view",
|
|
271
|
+
label: t("inbox_ops.list.actions.view", "View"),
|
|
272
|
+
onSelect: () => router.push(`/backend/inbox-ops/proposals/${row.id}`)
|
|
189
273
|
},
|
|
190
|
-
|
|
274
|
+
...row.status === "pending" || row.status === "partial" ? [{
|
|
275
|
+
id: "reject",
|
|
276
|
+
label: t("inbox_ops.list.actions.reject", "Reject"),
|
|
277
|
+
destructive: true,
|
|
278
|
+
onSelect: () => handleRejectProposal(row.id)
|
|
279
|
+
}] : []
|
|
280
|
+
] }),
|
|
281
|
+
pagination: {
|
|
282
|
+
page,
|
|
283
|
+
pageSize,
|
|
284
|
+
total,
|
|
285
|
+
totalPages: Math.ceil(total / pageSize),
|
|
286
|
+
onPageChange: setPage
|
|
191
287
|
},
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
columns,
|
|
198
|
-
data: items,
|
|
199
|
-
isLoading,
|
|
200
|
-
onRowClick: (row) => router.push(`/backend/inbox-ops/proposals/${row.id}`),
|
|
201
|
-
pagination: {
|
|
202
|
-
page,
|
|
203
|
-
pageSize,
|
|
204
|
-
total,
|
|
205
|
-
totalPages: Math.ceil(total / pageSize),
|
|
206
|
-
onPageChange: setPage
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
) }) })
|
|
210
|
-
] }) })
|
|
288
|
+
isLoading,
|
|
289
|
+
emptyState: emptyStateContent
|
|
290
|
+
}
|
|
291
|
+
) }),
|
|
292
|
+
ConfirmDialogElement
|
|
211
293
|
] });
|
|
212
294
|
}
|
|
213
295
|
export {
|
|
@@ -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 type { ColumnDef } from '@tanstack/react-table'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Settings, Inbox, Copy } from 'lucide-react'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\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}\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\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 [statusFilter, setStatusFilter] = React.useState<string | undefined>()\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\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 loadProposals = React.useCallback(async () => {\n setIsLoading(true)\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 (search) params.set('search', search)\n\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 }\n setIsLoading(false)\n }, [page, pageSize, statusFilter, search, scopeVersion])\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 loadProposals()\n loadCounts()\n loadSettings()\n }, [loadProposals, loadCounts, loadSettings])\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 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 id: 'actions_count',\n header: t('inbox_ops.actions_count', 'Actions'),\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 const isEmpty = totalCount === 0 && !isLoading\n\n const tabs = [\n { label: `${t('common.all', 'All')} (${totalCount})`, value: undefined },\n { label: `${t('inbox_ops.status.pending', 'Pending')} (${counts.pending})`, value: 'pending' },\n { label: `${t('inbox_ops.status.partial', 'Partial')} (${counts.partial})`, value: 'partial' },\n { label: `${t('inbox_ops.status.accepted', 'Accepted')} (${counts.accepted})`, value: 'accepted' },\n { label: `${t('inbox_ops.status.rejected', 'Rejected')} (${counts.rejected})`, value: 'rejected' },\n ]\n\n return (\n <Page>\n <div className=\"flex items-center justify-between px-3 py-3 md:px-6 md:py-4\">\n <h1 className=\"text-lg font-semibold\">{t('inbox_ops.title', 'InboxOps')}</h1>\n <Link href=\"/backend/inbox-ops/settings\">\n <Button variant=\"outline\" size=\"sm\">\n <Settings className=\"h-4 w-4\" />\n <span className=\"hidden md:inline ml-1\">{t('inbox_ops.settings.title', 'Settings')}</span>\n </Button>\n </Link>\n </div>\n\n <PageBody>\n {isEmpty ? (\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 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 ) : (\n <>\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 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 <div className=\"overflow-auto\">\n <div className=\"min-w-[640px]\">\n <DataTable\n columns={columns}\n data={items}\n isLoading={isLoading}\n onRowClick={(row) => router.push(`/backend/inbox-ops/proposals/${row.id}`)}\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 )}\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
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'\n\ntype ProposalRow = {\n id: string\n summary: string\n confidence: string\n status: string\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}\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\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 (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, 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, search, 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 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 ], [t, counts])\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 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 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
|
+
"mappings": "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",
|
|
6
6
|
"names": ["total"]
|
|
7
7
|
}
|
|
@@ -10,12 +10,12 @@ const metadata = {
|
|
|
10
10
|
requireFeatures: ["inbox_ops.proposals.view"],
|
|
11
11
|
pageTitle: "Proposals",
|
|
12
12
|
pageTitleKey: "inbox_ops.nav.proposals",
|
|
13
|
-
pageGroup: "
|
|
13
|
+
pageGroup: "AI Inbox Actions",
|
|
14
14
|
pageGroupKey: "inbox_ops.nav.group",
|
|
15
15
|
pagePriority: 45,
|
|
16
16
|
pageOrder: 100,
|
|
17
17
|
icon: inboxIcon,
|
|
18
|
-
breadcrumb: [{ label: "
|
|
18
|
+
breadcrumb: [{ label: "AI Inbox Actions", labelKey: "inbox_ops.nav.group" }]
|
|
19
19
|
};
|
|
20
20
|
export {
|
|
21
21
|
metadata
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/inbox_ops/backend/inbox-ops/page.meta.ts"],
|
|
4
|
-
"sourcesContent": ["import React from 'react'\n\nconst inboxIcon = React.createElement(\n 'svg',\n { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },\n React.createElement('polyline', { points: '22 12 16 12 14 15 10 15 8 12 2 12' }),\n React.createElement('path', { d: 'M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z' }),\n)\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.proposals.view'],\n pageTitle: 'Proposals',\n pageTitleKey: 'inbox_ops.nav.proposals',\n pageGroup: '
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;AAElB,MAAM,YAAY,MAAM;AAAA,EACtB;AAAA,EACA,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,aAAa,MAAM,QAAQ,QAAQ,gBAAgB,aAAa,EAAE;AAAA,EACpG,MAAM,cAAc,YAAY,EAAE,QAAQ,oCAAoC,CAAC;AAAA,EAC/E,MAAM,cAAc,QAAQ,EAAE,GAAG,6GAA6G,CAAC;AACjJ;AAEO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY,CAAC,EAAE,OAAO,
|
|
4
|
+
"sourcesContent": ["import React from 'react'\n\nconst inboxIcon = React.createElement(\n 'svg',\n { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2 },\n React.createElement('polyline', { points: '22 12 16 12 14 15 10 15 8 12 2 12' }),\n React.createElement('path', { d: 'M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z' }),\n)\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['inbox_ops.proposals.view'],\n pageTitle: 'Proposals',\n pageTitleKey: 'inbox_ops.nav.proposals',\n pageGroup: 'AI Inbox Actions',\n pageGroupKey: 'inbox_ops.nav.group',\n pagePriority: 45,\n pageOrder: 100,\n icon: inboxIcon,\n breadcrumb: [{ label: 'AI Inbox Actions', labelKey: 'inbox_ops.nav.group' }],\n} as const\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAElB,MAAM,YAAY,MAAM;AAAA,EACtB;AAAA,EACA,EAAE,OAAO,IAAI,QAAQ,IAAI,SAAS,aAAa,MAAM,QAAQ,QAAQ,gBAAgB,aAAa,EAAE;AAAA,EACpG,MAAM,cAAc,YAAY,EAAE,QAAQ,oCAAoC,CAAC;AAAA,EAC/E,MAAM,cAAc,QAAQ,EAAE,GAAG,6GAA6G,CAAC;AACjJ;AAEO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,0BAA0B;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY,CAAC,EAAE,OAAO,oBAAoB,UAAU,sBAAsB,CAAC;AAC7E;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|