@open-mercato/core 0.6.1-develop.3256.1.fe3dec2464 → 0.6.1-develop.3260.1.dc719cac84

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.
Files changed (120) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/authFixtures.js.map +1 -1
  3. package/dist/helpers/integration/authUi.js +10 -2
  4. package/dist/helpers/integration/authUi.js.map +2 -2
  5. package/dist/helpers/integration/salesUi.js +3 -1
  6. package/dist/helpers/integration/salesUi.js.map +2 -2
  7. package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
  8. package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
  9. package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
  10. package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
  11. package/dist/modules/auth/api/users/route.js +21 -3
  12. package/dist/modules/auth/api/users/route.js.map +2 -2
  13. package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
  14. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  15. package/dist/modules/auth/backend/users/create/page.js +4 -1
  16. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  17. package/dist/modules/auth/backend/users/page.js +56 -2
  18. package/dist/modules/auth/backend/users/page.js.map +3 -3
  19. package/dist/modules/auth/commands/users.js +14 -0
  20. package/dist/modules/auth/commands/users.js.map +2 -2
  21. package/dist/modules/auth/data/validators.js +8 -0
  22. package/dist/modules/auth/data/validators.js.map +2 -2
  23. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
  24. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  25. package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
  26. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  27. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
  28. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  29. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
  30. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  31. package/dist/modules/customers/components/PipelineSettings.js +108 -99
  32. package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
  33. package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
  34. package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
  35. package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
  36. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
  37. package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
  38. package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
  39. package/dist/modules/customers/components/detail/RolesSection.js +35 -22
  40. package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
  41. package/dist/modules/customers/components/detail/TasksSection.js +2 -2
  42. package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
  43. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
  44. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  45. package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
  46. package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
  47. package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
  48. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  49. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
  50. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  51. package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
  52. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  53. package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
  54. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  55. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
  56. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  57. package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
  58. package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
  59. package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
  60. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  61. package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
  62. package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
  63. package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
  64. package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
  65. package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
  66. package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
  67. package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
  68. package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
  69. package/dist/modules/staff/components/TeamForm.js +1 -1
  70. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  71. package/dist/modules/staff/components/TeamMemberForm.js +1 -1
  72. package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
  73. package/dist/modules/staff/components/TeamRoleForm.js +1 -1
  74. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  75. package/package.json +5 -5
  76. package/src/helpers/integration/authFixtures.ts +1 -1
  77. package/src/helpers/integration/authUi.ts +11 -2
  78. package/src/helpers/integration/salesUi.ts +10 -1
  79. package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
  80. package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
  81. package/src/modules/auth/api/users/route.ts +22 -3
  82. package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
  83. package/src/modules/auth/backend/users/create/page.tsx +6 -2
  84. package/src/modules/auth/backend/users/page.tsx +60 -3
  85. package/src/modules/auth/commands/users.ts +15 -0
  86. package/src/modules/auth/data/validators.ts +8 -0
  87. package/src/modules/auth/i18n/de.json +4 -0
  88. package/src/modules/auth/i18n/en.json +4 -0
  89. package/src/modules/auth/i18n/es.json +4 -0
  90. package/src/modules/auth/i18n/pl.json +4 -0
  91. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
  92. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
  93. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
  94. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
  95. package/src/modules/customers/components/PipelineSettings.tsx +95 -95
  96. package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
  97. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
  98. package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
  99. package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
  100. package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
  101. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
  102. package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
  103. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
  104. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
  105. package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
  106. package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
  107. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
  108. package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
  109. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
  110. package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
  111. package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
  112. package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
  113. package/src/modules/sales/i18n/de.json +2 -0
  114. package/src/modules/sales/i18n/en.json +2 -0
  115. package/src/modules/sales/i18n/es.json +2 -0
  116. package/src/modules/sales/i18n/pl.json +2 -0
  117. package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
  118. package/src/modules/staff/components/TeamForm.tsx +1 -1
  119. package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
  120. package/src/modules/staff/components/TeamRoleForm.tsx +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/dictionaries/components/DictionariesManager.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useSearchParams } from 'next/navigation'\nimport { Plus, Pencil, Trash2 } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { DictionaryEntriesEditor } from './DictionaryEntriesEditor'\n\nexport type DictionarySummary = {\n id: string\n key: string\n name: string\n description?: string | null\n isSystem?: boolean\n isActive?: boolean\n organizationId: string\n isInherited: boolean\n managerVisibility: 'default' | 'hidden'\n}\n\ntype DialogState = {\n mode: 'create' | 'edit'\n dictionary?: DictionarySummary\n}\n\nexport function DictionariesManager() {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const searchParams = useSearchParams()\n const [items, setItems] = React.useState<DictionarySummary[]>([])\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [form, setForm] = React.useState({ key: '', name: '', description: '' })\n const [errors, setErrors] = React.useState<{ key?: string; name?: string }>({})\n const [submitting, setSubmitting] = React.useState(false)\n const [deleting, setDeleting] = React.useState<string | null>(null)\n const selectionFromQueryApplied = React.useRef(false)\n const inheritedManageMessage = t('dictionaries.config.error.inheritedManage', 'Inherited dictionaries must be managed at the parent organization.')\n const requestedDictionaryId = searchParams?.get('dictionaryId') ?? null\n const requestedDictionaryKey = searchParams?.get('key')?.trim().toLowerCase() ?? null\n\n const loadDictionaries = React.useCallback(async () => {\n setLoading(true)\n try {\n const call = await apiCall<{ items?: unknown[]; error?: string }>('/api/dictionaries')\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to load dictionaries')\n }\n const resultItems = Array.isArray(call.result?.items) ? call.result!.items : []\n const list: DictionarySummary[] = Array.isArray(resultItems)\n ? resultItems.map((item: any): DictionarySummary => ({\n id: String(item.id),\n key: String(item.key),\n name: String(item.name ?? item.key),\n description: typeof item.description === 'string' ? item.description : null,\n isSystem: Boolean(item.isSystem),\n isActive: item.isActive !== false,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : '',\n isInherited: item.isInherited === true,\n managerVisibility:\n item.managerVisibility === 'hidden' ? 'hidden' : 'default',\n }))\n : []\n const filtered = list.filter((dictionary: DictionarySummary) => dictionary.managerVisibility !== 'hidden')\n setItems(filtered)\n if (!filtered.find((dict: DictionarySummary) => dict.id === selectedId)) {\n setSelectedId(filtered.length ? filtered[0].id : null)\n }\n } catch (err) {\n console.error('Failed to load dictionaries', err)\n flash(t('dictionaries.config.error.load', 'Failed to load dictionaries.'), 'error')\n } finally {\n setLoading(false)\n }\n }, [selectedId, t])\n\n React.useEffect(() => {\n loadDictionaries().catch(() => {})\n }, [loadDictionaries])\n\n React.useEffect(() => {\n if (selectionFromQueryApplied.current) return\n if (!items.length) return\n if (!requestedDictionaryId && !requestedDictionaryKey) return\n if (requestedDictionaryId) {\n const match = items.find((dictionary) => dictionary.id === requestedDictionaryId)\n if (match && selectedId !== match.id) {\n setSelectedId(match.id)\n }\n selectionFromQueryApplied.current = true\n return\n }\n if (requestedDictionaryKey) {\n const match = items.find((dictionary) => dictionary.key.toLowerCase() === requestedDictionaryKey)\n if (match && selectedId !== match.id) {\n setSelectedId(match.id)\n }\n selectionFromQueryApplied.current = true\n }\n }, [items, requestedDictionaryId, requestedDictionaryKey, selectedId])\n\n const openCreateDialog = React.useCallback(() => {\n setForm({ key: '', name: '', description: '' })\n setDialog({ mode: 'create' })\n setErrors({})\n }, [])\n\n const openEditDialog = React.useCallback((dictionary: DictionarySummary) => {\n if (dictionary.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n setForm({ key: dictionary.key, name: dictionary.name, description: dictionary.description ?? '' })\n setDialog({ mode: 'edit', dictionary })\n setErrors({})\n }, [inheritedManageMessage])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n setForm({ key: '', name: '', description: '' })\n setErrors({})\n }, [])\n\n const handleSubmit = React.useCallback(async () => {\n if (!dialog) return\n if (dialog.mode === 'edit' && dialog.dictionary?.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n const trimmedKey = form.key.trim()\n const trimmedName = form.name.trim()\n const nextErrors: { key?: string; name?: string } = {}\n if (!trimmedKey) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorRequired', 'Key is required.')\n } else if (trimmedKey.length > 100) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorLength', 'Key must be at most 100 characters long.')\n } else if (!/^[a-z0-9][a-z0-9_-]*$/.test(trimmedKey)) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorPattern', 'Use lowercase letters, numbers, hyphen, or underscore.')\n }\n if (!trimmedName) {\n nextErrors.name = t('dictionaries.config.dialog.nameErrorRequired', 'Name is required.')\n }\n if (nextErrors.key || nextErrors.name) {\n setErrors(nextErrors)\n return\n }\n setSubmitting(true)\n try {\n const payload = {\n key: trimmedKey,\n name: trimmedName,\n description: form.description.trim() || undefined,\n }\n if (dialog.mode === 'create') {\n const call = await apiCall<Record<string, unknown>>('/api/dictionaries', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary')\n }\n flash(t('dictionaries.config.success.create', 'Dictionary created.'), 'success')\n } else if (dialog.dictionary) {\n const call = await apiCall<Record<string, unknown>>(`/api/dictionaries/${dialog.dictionary.id}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to update dictionary')\n }\n flash(t('dictionaries.config.success.update', 'Dictionary updated.'), 'success')\n }\n closeDialog()\n await loadDictionaries()\n setErrors({})\n } catch (err) {\n console.error('Failed to save dictionary', err)\n flash(t('dictionaries.config.error.save', 'Failed to save dictionary.'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, form.description, form.key, form.name, inheritedManageMessage, loadDictionaries, t])\n\n const handleDelete = React.useCallback(\n async (dictionary: DictionarySummary) => {\n if (dictionary.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n if (dictionary.isSystem) {\n flash(t('dictionaries.config.error.system', 'System dictionaries cannot be deleted.'), 'error')\n return\n }\n const rawConfirm = t('dictionaries.config.delete.confirm', { name: dictionary.name })\n const confirmMessage = rawConfirm && rawConfirm !== 'dictionaries.config.delete.confirm'\n ? rawConfirm\n : `Delete dictionary \"${dictionary.name}\"?`\n const confirmed = await confirm({\n title: confirmMessage,\n variant: 'destructive',\n })\n if (!confirmed) return\n setDeleting(dictionary.id)\n try {\n const call = await apiCall<Record<string, unknown>>(`/api/dictionaries/${dictionary.id}`, { method: 'DELETE' })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary')\n }\n flash(t('dictionaries.config.success.delete', 'Dictionary deleted.'), 'success')\n await loadDictionaries()\n } catch (err) {\n console.error('Failed to delete dictionary', err)\n flash(t('dictionaries.config.error.delete', 'Failed to delete dictionary.'), 'error')\n } finally {\n setDeleting(null)\n }\n },\n [confirm, inheritedManageMessage, loadDictionaries, t],\n )\n\n const selectedDictionary = items.find((item) => item.id === selectedId) ?? null\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-[320px_1fr]\">\n <div className=\"rounded-lg border bg-card p-4 shadow-sm\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold\">\n {t('dictionaries.config.list.title', 'Dictionaries')}\n </h2>\n <Button type=\"button\" size=\"sm\" onClick={openCreateDialog}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.list.add', 'New dictionary')}\n </Button>\n </div>\n <div className=\"mt-4 space-y-2\">\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('dictionaries.config.list.loading', 'Loading dictionaries\u2026')}\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('dictionaries.config.list.empty', 'No dictionaries yet. Create one to get started.')}\n </p>\n ) : (\n <ul className=\"space-y-1\">\n {items.map((dictionary) => (\n <li key={dictionary.id}>\n <div\n role=\"button\"\n tabIndex={0}\n aria-pressed={dictionary.id === selectedId}\n className={`flex w-full cursor-pointer select-none items-center justify-between rounded border px-3 py-2 text-left text-sm transition ${\n dictionary.id === selectedId ? 'border-primary bg-primary/5 text-primary' : 'border-border hover:bg-muted'\n }`}\n onClick={() => setSelectedId(dictionary.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setSelectedId(dictionary.id)\n }\n }}\n >\n <div>\n <div className=\"flex items-center gap-2 font-medium\">\n <span>{dictionary.name}</span>\n {dictionary.isInherited ? (\n <span className=\"rounded-full border border-border px-2 py-0.5 text-overline font-normal uppercase tracking-wide text-muted-foreground\">\n {t('dictionaries.config.list.inherited', 'Inherited')}\n </span>\n ) : null}\n </div>\n <div className=\"text-xs text-muted-foreground\">{dictionary.key}</div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n disabled={dictionary.isInherited}\n title={dictionary.isInherited ? inheritedManageMessage : undefined}\n onClick={(event) => {\n event.stopPropagation()\n openEditDialog(dictionary)\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n disabled={dictionary.isInherited || deleting === dictionary.id}\n title={dictionary.isInherited ? inheritedManageMessage : undefined}\n onClick={(event) => {\n event.stopPropagation()\n handleDelete(dictionary)\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n <div>\n {selectedDictionary ? (\n <DictionaryEntriesEditor\n dictionaryId={selectedDictionary.id}\n dictionaryName={selectedDictionary.name}\n readOnly={selectedDictionary.isInherited}\n />\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center rounded border border-dashed p-10 text-center text-sm text-muted-foreground\">\n {t('dictionaries.config.entries.placeholder', 'Select a dictionary to manage its entries.')}\n </div>\n )}\n </div>\n\n <Dialog open={dialog != null} onOpenChange={(open) => (open ? undefined : closeDialog())}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {dialog?.mode === 'create'\n ? t('dictionaries.config.dialog.createTitle', 'Create dictionary')\n : t('dictionaries.config.dialog.editTitle', 'Edit dictionary')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.keyLabel', 'Key')}</label>\n <input\n value={form.key}\n onChange={(event) => {\n const next = event.target.value\n setForm((prev) => ({ ...prev, key: next }))\n if (errors.key) setErrors((prev) => ({ ...prev, key: undefined }))\n }}\n placeholder={t('dictionaries.config.dialog.keyPlaceholder', 'slug_name')}\n disabled={dialog?.mode === 'edit'}\n className={`w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:bg-muted ${errors.key ? 'border-destructive focus-visible:ring-destructive' : ''}`}\n aria-invalid={errors.key ? 'true' : 'false'}\n aria-describedby=\"dictionary-key-hint\"\n />\n <p\n id=\"dictionary-key-hint\"\n className={`text-xs ${errors.key ? 'text-destructive' : 'text-muted-foreground'}`}\n >\n {errors.key ?? t('dictionaries.config.dialog.keyHint', 'Use lowercase letters, numbers, hyphen, or underscore.')}\n </p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.nameLabel', 'Name')}</label>\n <input\n value={form.name}\n onChange={(event) => {\n const next = event.target.value\n setForm((prev) => ({ ...prev, name: next }))\n if (errors.name) setErrors((prev) => ({ ...prev, name: undefined }))\n }}\n placeholder={t('dictionaries.config.dialog.namePlaceholder', 'Display name')}\n className={`w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${errors.name ? 'border-destructive focus-visible:ring-destructive' : ''}`}\n aria-invalid={errors.name ? 'true' : 'false'}\n />\n {errors.name ? (\n <p className=\"text-xs text-destructive\">{errors.name}</p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.descriptionLabel', 'Description')}</label>\n <textarea\n value={form.description}\n onChange={(event) => setForm((prev) => ({ ...prev, description: event.target.value }))}\n className=\"min-h-[120px] w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={t('dictionaries.config.dialog.descriptionPlaceholder', 'Explain how this dictionary is used (optional).')}\n />\n </div>\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"ghost\" onClick={closeDialog} disabled={submitting}>\n {t('dictionaries.config.dialog.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSubmit} disabled={submitting}>\n {submitting ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useSearchParams } from 'next/navigation'\nimport { Book, Plus, Pencil, Trash2 } from 'lucide-react'\nimport { EmptyState } from '@open-mercato/ui/primitives/empty-state'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { DictionaryEntriesEditor } from './DictionaryEntriesEditor'\n\nexport type DictionarySummary = {\n id: string\n key: string\n name: string\n description?: string | null\n isSystem?: boolean\n isActive?: boolean\n organizationId: string\n isInherited: boolean\n managerVisibility: 'default' | 'hidden'\n}\n\ntype DialogState = {\n mode: 'create' | 'edit'\n dictionary?: DictionarySummary\n}\n\nexport function DictionariesManager() {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const searchParams = useSearchParams()\n const [items, setItems] = React.useState<DictionarySummary[]>([])\n const [selectedId, setSelectedId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [dialog, setDialog] = React.useState<DialogState | null>(null)\n const [form, setForm] = React.useState({ key: '', name: '', description: '' })\n const [errors, setErrors] = React.useState<{ key?: string; name?: string }>({})\n const [submitting, setSubmitting] = React.useState(false)\n const [deleting, setDeleting] = React.useState<string | null>(null)\n const selectionFromQueryApplied = React.useRef(false)\n const inheritedManageMessage = t('dictionaries.config.error.inheritedManage', 'Inherited dictionaries must be managed at the parent organization.')\n const requestedDictionaryId = searchParams?.get('dictionaryId') ?? null\n const requestedDictionaryKey = searchParams?.get('key')?.trim().toLowerCase() ?? null\n\n const loadDictionaries = React.useCallback(async () => {\n setLoading(true)\n try {\n const call = await apiCall<{ items?: unknown[]; error?: string }>('/api/dictionaries')\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to load dictionaries')\n }\n const resultItems = Array.isArray(call.result?.items) ? call.result!.items : []\n const list: DictionarySummary[] = Array.isArray(resultItems)\n ? resultItems.map((item: any): DictionarySummary => ({\n id: String(item.id),\n key: String(item.key),\n name: String(item.name ?? item.key),\n description: typeof item.description === 'string' ? item.description : null,\n isSystem: Boolean(item.isSystem),\n isActive: item.isActive !== false,\n organizationId: typeof item.organizationId === 'string' ? item.organizationId : '',\n isInherited: item.isInherited === true,\n managerVisibility:\n item.managerVisibility === 'hidden' ? 'hidden' : 'default',\n }))\n : []\n const filtered = list.filter((dictionary: DictionarySummary) => dictionary.managerVisibility !== 'hidden')\n setItems(filtered)\n if (!filtered.find((dict: DictionarySummary) => dict.id === selectedId)) {\n setSelectedId(filtered.length ? filtered[0].id : null)\n }\n } catch (err) {\n console.error('Failed to load dictionaries', err)\n flash(t('dictionaries.config.error.load', 'Failed to load dictionaries.'), 'error')\n } finally {\n setLoading(false)\n }\n }, [selectedId, t])\n\n React.useEffect(() => {\n loadDictionaries().catch(() => {})\n }, [loadDictionaries])\n\n React.useEffect(() => {\n if (selectionFromQueryApplied.current) return\n if (!items.length) return\n if (!requestedDictionaryId && !requestedDictionaryKey) return\n if (requestedDictionaryId) {\n const match = items.find((dictionary) => dictionary.id === requestedDictionaryId)\n if (match && selectedId !== match.id) {\n setSelectedId(match.id)\n }\n selectionFromQueryApplied.current = true\n return\n }\n if (requestedDictionaryKey) {\n const match = items.find((dictionary) => dictionary.key.toLowerCase() === requestedDictionaryKey)\n if (match && selectedId !== match.id) {\n setSelectedId(match.id)\n }\n selectionFromQueryApplied.current = true\n }\n }, [items, requestedDictionaryId, requestedDictionaryKey, selectedId])\n\n const openCreateDialog = React.useCallback(() => {\n setForm({ key: '', name: '', description: '' })\n setDialog({ mode: 'create' })\n setErrors({})\n }, [])\n\n const openEditDialog = React.useCallback((dictionary: DictionarySummary) => {\n if (dictionary.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n setForm({ key: dictionary.key, name: dictionary.name, description: dictionary.description ?? '' })\n setDialog({ mode: 'edit', dictionary })\n setErrors({})\n }, [inheritedManageMessage])\n\n const closeDialog = React.useCallback(() => {\n setDialog(null)\n setForm({ key: '', name: '', description: '' })\n setErrors({})\n }, [])\n\n const handleSubmit = React.useCallback(async () => {\n if (!dialog) return\n if (dialog.mode === 'edit' && dialog.dictionary?.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n const trimmedKey = form.key.trim()\n const trimmedName = form.name.trim()\n const nextErrors: { key?: string; name?: string } = {}\n if (!trimmedKey) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorRequired', 'Key is required.')\n } else if (trimmedKey.length > 100) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorLength', 'Key must be at most 100 characters long.')\n } else if (!/^[a-z0-9][a-z0-9_-]*$/.test(trimmedKey)) {\n nextErrors.key = t('dictionaries.config.dialog.keyErrorPattern', 'Use lowercase letters, numbers, hyphen, or underscore.')\n }\n if (!trimmedName) {\n nextErrors.name = t('dictionaries.config.dialog.nameErrorRequired', 'Name is required.')\n }\n if (nextErrors.key || nextErrors.name) {\n setErrors(nextErrors)\n return\n }\n setSubmitting(true)\n try {\n const payload = {\n key: trimmedKey,\n name: trimmedName,\n description: form.description.trim() || undefined,\n }\n if (dialog.mode === 'create') {\n const call = await apiCall<Record<string, unknown>>('/api/dictionaries', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary')\n }\n flash(t('dictionaries.config.success.create', 'Dictionary created.'), 'success')\n } else if (dialog.dictionary) {\n const call = await apiCall<Record<string, unknown>>(`/api/dictionaries/${dialog.dictionary.id}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to update dictionary')\n }\n flash(t('dictionaries.config.success.update', 'Dictionary updated.'), 'success')\n }\n closeDialog()\n await loadDictionaries()\n setErrors({})\n } catch (err) {\n console.error('Failed to save dictionary', err)\n flash(t('dictionaries.config.error.save', 'Failed to save dictionary.'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [closeDialog, dialog, form.description, form.key, form.name, inheritedManageMessage, loadDictionaries, t])\n\n const handleDelete = React.useCallback(\n async (dictionary: DictionarySummary) => {\n if (dictionary.isInherited) {\n flash(inheritedManageMessage, 'info')\n return\n }\n if (dictionary.isSystem) {\n flash(t('dictionaries.config.error.system', 'System dictionaries cannot be deleted.'), 'error')\n return\n }\n const rawConfirm = t('dictionaries.config.delete.confirm', { name: dictionary.name })\n const confirmMessage = rawConfirm && rawConfirm !== 'dictionaries.config.delete.confirm'\n ? rawConfirm\n : `Delete dictionary \"${dictionary.name}\"?`\n const confirmed = await confirm({\n title: confirmMessage,\n variant: 'destructive',\n })\n if (!confirmed) return\n setDeleting(dictionary.id)\n try {\n const call = await apiCall<Record<string, unknown>>(`/api/dictionaries/${dictionary.id}`, { method: 'DELETE' })\n if (!call.ok) {\n throw new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary')\n }\n flash(t('dictionaries.config.success.delete', 'Dictionary deleted.'), 'success')\n await loadDictionaries()\n } catch (err) {\n console.error('Failed to delete dictionary', err)\n flash(t('dictionaries.config.error.delete', 'Failed to delete dictionary.'), 'error')\n } finally {\n setDeleting(null)\n }\n },\n [confirm, inheritedManageMessage, loadDictionaries, t],\n )\n\n const selectedDictionary = items.find((item) => item.id === selectedId) ?? null\n\n return (\n <div className=\"grid gap-6 lg:grid-cols-[320px_1fr]\">\n <div className=\"rounded-lg border bg-card p-4 shadow-sm\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold\">\n {t('dictionaries.config.list.title', 'Dictionaries')}\n </h2>\n <Button type=\"button\" size=\"sm\" onClick={openCreateDialog}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.list.add', 'New dictionary')}\n </Button>\n </div>\n <div className=\"mt-4 space-y-2\">\n {loading ? (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner className=\"h-4 w-4\" />\n {t('dictionaries.config.list.loading', 'Loading dictionaries\u2026')}\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('dictionaries.config.list.empty', 'No dictionaries yet. Create one to get started.')}\n </p>\n ) : (\n <ul className=\"space-y-1\">\n {items.map((dictionary) => (\n <li key={dictionary.id}>\n <div\n role=\"button\"\n tabIndex={0}\n aria-pressed={dictionary.id === selectedId}\n className={`flex w-full cursor-pointer select-none items-center justify-between rounded border px-3 py-2 text-left text-sm transition ${\n dictionary.id === selectedId ? 'border-primary bg-primary/5 text-primary' : 'border-border hover:bg-muted'\n }`}\n onClick={() => setSelectedId(dictionary.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setSelectedId(dictionary.id)\n }\n }}\n >\n <div>\n <div className=\"flex items-center gap-2 font-medium\">\n <span>{dictionary.name}</span>\n {dictionary.isInherited ? (\n <span className=\"rounded-full border border-border px-2 py-0.5 text-overline font-normal uppercase tracking-wide text-muted-foreground\">\n {t('dictionaries.config.list.inherited', 'Inherited')}\n </span>\n ) : null}\n </div>\n <div className=\"text-xs text-muted-foreground\">{dictionary.key}</div>\n </div>\n <div className=\"flex items-center gap-2\">\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n disabled={dictionary.isInherited}\n title={dictionary.isInherited ? inheritedManageMessage : undefined}\n onClick={(event) => {\n event.stopPropagation()\n openEditDialog(dictionary)\n }}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n size=\"icon\"\n variant=\"ghost\"\n disabled={dictionary.isInherited || deleting === dictionary.id}\n title={dictionary.isInherited ? inheritedManageMessage : undefined}\n onClick={(event) => {\n event.stopPropagation()\n handleDelete(dictionary)\n }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n <div>\n {selectedDictionary ? (\n <DictionaryEntriesEditor\n dictionaryId={selectedDictionary.id}\n dictionaryName={selectedDictionary.name}\n readOnly={selectedDictionary.isInherited}\n />\n ) : (\n <EmptyState\n icon={<Book className=\"h-8 w-8\" aria-hidden=\"true\" />}\n title={t('dictionaries.config.entries.placeholder', 'Select a dictionary to manage its entries.')}\n className=\"h-full\"\n />\n )}\n </div>\n\n <Dialog open={dialog != null} onOpenChange={(open) => (open ? undefined : closeDialog())}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {dialog?.mode === 'create'\n ? t('dictionaries.config.dialog.createTitle', 'Create dictionary')\n : t('dictionaries.config.dialog.editTitle', 'Edit dictionary')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.keyLabel', 'Key')}</label>\n <input\n value={form.key}\n onChange={(event) => {\n const next = event.target.value\n setForm((prev) => ({ ...prev, key: next }))\n if (errors.key) setErrors((prev) => ({ ...prev, key: undefined }))\n }}\n placeholder={t('dictionaries.config.dialog.keyPlaceholder', 'slug_name')}\n disabled={dialog?.mode === 'edit'}\n className={`w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:bg-muted ${errors.key ? 'border-destructive focus-visible:ring-destructive' : ''}`}\n aria-invalid={errors.key ? 'true' : 'false'}\n aria-describedby=\"dictionary-key-hint\"\n />\n <p\n id=\"dictionary-key-hint\"\n className={`text-xs ${errors.key ? 'text-destructive' : 'text-muted-foreground'}`}\n >\n {errors.key ?? t('dictionaries.config.dialog.keyHint', 'Use lowercase letters, numbers, hyphen, or underscore.')}\n </p>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.nameLabel', 'Name')}</label>\n <input\n value={form.name}\n onChange={(event) => {\n const next = event.target.value\n setForm((prev) => ({ ...prev, name: next }))\n if (errors.name) setErrors((prev) => ({ ...prev, name: undefined }))\n }}\n placeholder={t('dictionaries.config.dialog.namePlaceholder', 'Display name')}\n className={`w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${errors.name ? 'border-destructive focus-visible:ring-destructive' : ''}`}\n aria-invalid={errors.name ? 'true' : 'false'}\n />\n {errors.name ? (\n <p className=\"text-xs text-destructive\">{errors.name}</p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">{t('dictionaries.config.dialog.descriptionLabel', 'Description')}</label>\n <textarea\n value={form.description}\n onChange={(event) => setForm((prev) => ({ ...prev, description: event.target.value }))}\n className=\"min-h-[120px] w-full rounded border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={t('dictionaries.config.dialog.descriptionPlaceholder', 'Explain how this dictionary is used (optional).')}\n />\n </div>\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"ghost\" onClick={closeDialog} disabled={submitting}>\n {t('dictionaries.config.dialog.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={handleSubmit} disabled={submitting}>\n {submitting ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -33,7 +33,9 @@ import {
33
33
  LEGACY_INTEGRATION_DETAIL_TABS_SPOT_ID
34
34
  } from "@open-mercato/shared/modules/integrations/types";
35
35
  import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
36
- import { Activity, AlertTriangle, Bell, Calendar, CheckCircle2, ChevronDown, ChevronRight, CreditCard, FileText, HardDrive, Key, MessageSquare, RefreshCw, Settings, Truck, Webhook, XCircle, Zap } from "lucide-react";
36
+ import { LogList } from "@open-mercato/ui/backend/LogList";
37
+ import { Activity, AlertTriangle, Bell, Calendar, CheckCircle2, CreditCard, FileText, FileX, HardDrive, Key, MessageSquare, RefreshCw, Settings, Truck, Webhook, XCircle, Zap } from "lucide-react";
38
+ import { EmptyState } from "@open-mercato/ui/primitives/empty-state";
37
39
  import { IntegrationScheduleTab } from "../../../../data_sync/components/IntegrationScheduleTab.js";
38
40
  import {
39
41
  buildIntegrationDetailInjectedTabs,
@@ -45,11 +47,6 @@ const UNSUPPORTED_CREDENTIAL_FIELD_TYPES = /* @__PURE__ */ new Set(["oauth", "ss
45
47
  function isEditableCredentialField(field) {
46
48
  return !UNSUPPORTED_CREDENTIAL_FIELD_TYPES.has(field.type);
47
49
  }
48
- const LOG_LEVEL_STYLES = {
49
- info: "bg-blue-100 text-blue-800",
50
- warn: "bg-yellow-100 text-yellow-800",
51
- error: "bg-red-100 text-red-800"
52
- };
53
50
  const HEALTH_STATUS_STYLES = {
54
51
  healthy: "bg-green-100 text-green-800",
55
52
  degraded: "bg-yellow-100 text-yellow-800",
@@ -218,7 +215,6 @@ function IntegrationDetailPage({ params }) {
218
215
  const [logs, setLogs] = React.useState([]);
219
216
  const [logLevel, setLogLevel] = React.useState("");
220
217
  const [isLoadingLogs, setIsLoadingLogs] = React.useState(false);
221
- const [expandedLogId, setExpandedLogId] = React.useState(null);
222
218
  const [isCheckingHealth, setIsCheckingHealth] = React.useState(false);
223
219
  const [isTogglingState, setIsTogglingState] = React.useState(false);
224
220
  const [latestHealthResult, setLatestHealthResult] = React.useState(null);
@@ -385,9 +381,6 @@ function IntegrationDetailPage({ params }) {
385
381
  React.useEffect(() => {
386
382
  void loadLogs();
387
383
  }, [loadLogs]);
388
- React.useEffect(() => {
389
- setExpandedLogId((current) => current && logs.some((log) => log.id === current) ? current : null);
390
- }, [logs]);
391
384
  const handleToggleState = React.useCallback(async (enabled) => {
392
385
  const currentIntegrationId = resolveCurrentIntegrationId();
393
386
  if (!currentIntegrationId) return;
@@ -924,94 +917,85 @@ function IntegrationDetailPage({ params }) {
924
917
  ]
925
918
  }
926
919
  ) }) }),
927
- isLoadingLogs ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsx(Spinner, {}) }) : logs.length === 0 ? /* @__PURE__ */ jsx("p", { className: "py-4 text-sm text-muted-foreground", children: t("integrations.detail.logs.empty") }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
928
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
929
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left font-medium", children: t("integrations.detail.logs.columns.time") }),
930
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left font-medium", children: t("integrations.detail.logs.columns.level") }),
931
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left font-medium", children: t("integrations.detail.logs.columns.message") })
932
- ] }) }),
933
- /* @__PURE__ */ jsx("tbody", { children: logs.map((log) => {
934
- const isExpanded = expandedLogId === log.id;
935
- const metadataEntries = [
936
- ["Time", new Date(log.createdAt).toLocaleString()],
937
- ["Level", log.level],
938
- ["Code", log.code ?? null],
939
- ["Run ID", log.runId ?? null],
940
- ["Entity Type", log.scopeEntityType ?? null],
941
- ["Entity ID", log.scopeEntityId ?? null]
942
- ].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);
943
- const { inlineEntries, nestedEntries } = splitLogPayload(log.payload);
944
- return /* @__PURE__ */ jsxs(React.Fragment, { children: [
945
- /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0", children: [
946
- /* @__PURE__ */ jsx("td", { className: "whitespace-nowrap px-4 py-2 text-muted-foreground", children: new Date(log.createdAt).toLocaleString() }),
947
- /* @__PURE__ */ jsx("td", { className: "px-4 py-2", children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: LOG_LEVEL_STYLES[log.level] ?? "", children: log.level }) }),
948
- /* @__PURE__ */ jsx("td", { className: "px-4 py-2", children: /* @__PURE__ */ jsxs(
949
- Button,
950
- {
951
- type: "button",
952
- variant: "ghost",
953
- size: "sm",
954
- className: "h-auto w-full justify-start gap-2 px-0 py-0 text-left hover:bg-transparent",
955
- onClick: () => setExpandedLogId((current) => current === log.id ? null : log.id),
956
- children: [
957
- isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 shrink-0" }),
958
- /* @__PURE__ */ jsx("span", { className: "truncate", children: log.message })
959
- ]
960
- }
961
- ) })
962
- ] }),
963
- isExpanded ? /* @__PURE__ */ jsx("tr", { className: "border-b bg-muted/30 last:border-0", children: /* @__PURE__ */ jsx("td", { colSpan: 3, className: "px-4 py-4", children: /* @__PURE__ */ jsx("div", { className: "space-y-4 rounded-lg border bg-card p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]", children: [
964
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
965
- /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
966
- /* @__PURE__ */ jsxs("div", { children: [
967
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: t("integrations.detail.logs.details.summary", "Summary") }),
968
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm font-medium", children: log.message })
920
+ isLoadingLogs ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsx(Spinner, {}) }) : /* @__PURE__ */ jsx(
921
+ LogList,
922
+ {
923
+ entries: logs.map((log) => {
924
+ const metadataEntries = [
925
+ ["Time", new Date(log.createdAt).toLocaleString()],
926
+ ["Level", log.level],
927
+ ["Code", log.code ?? null],
928
+ ["Run ID", log.runId ?? null],
929
+ ["Entity Type", log.scopeEntityType ?? null],
930
+ ["Entity ID", log.scopeEntityId ?? null]
931
+ ].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);
932
+ const { inlineEntries, nestedEntries } = splitLogPayload(log.payload);
933
+ return {
934
+ id: log.id,
935
+ time: new Date(log.createdAt).toLocaleString(),
936
+ level: log.level,
937
+ message: log.message,
938
+ body: /* @__PURE__ */ jsxs("div", { className: "grid gap-4 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]", children: [
939
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
940
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
941
+ /* @__PURE__ */ jsxs("div", { children: [
942
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: t("integrations.detail.logs.details.summary", "Summary") }),
943
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm font-medium", children: log.message })
944
+ ] }),
945
+ metadataEntries.length > 0 ? /* @__PURE__ */ jsx("dl", { className: "grid gap-3 sm:grid-cols-2", children: metadataEntries.map(([label, value]) => /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [
946
+ /* @__PURE__ */ jsx("dt", { className: "text-overline font-medium uppercase tracking-wide text-muted-foreground", children: label }),
947
+ /* @__PURE__ */ jsx("dd", { className: "mt-1 break-all text-sm", children: value })
948
+ ] }, label)) }) : null
969
949
  ] }),
970
- metadataEntries.length > 0 ? /* @__PURE__ */ jsx("dl", { className: "grid gap-3 sm:grid-cols-2", children: metadataEntries.map(([label, value]) => /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [
971
- /* @__PURE__ */ jsx("dt", { className: "text-overline font-medium uppercase tracking-wide text-muted-foreground", children: label }),
972
- /* @__PURE__ */ jsx("dd", { className: "mt-1 break-all text-sm", children: value })
973
- ] }, label)) }) : null
950
+ inlineEntries.length > 0 ? /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
951
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: t("integrations.detail.logs.details.fields", "Fields") }),
952
+ /* @__PURE__ */ jsx("dl", { className: "grid gap-3 sm:grid-cols-2", children: inlineEntries.map(([key, value]) => /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [
953
+ /* @__PURE__ */ jsx("dt", { className: "text-overline font-medium uppercase tracking-wide text-muted-foreground", children: formatLogDetailLabel(key) }),
954
+ /* @__PURE__ */ jsx("dd", { className: "mt-1 break-words text-sm", children: formatLogPrimitiveValue(value) })
955
+ ] }, key)) })
956
+ ] }) : null
974
957
  ] }),
975
- inlineEntries.length > 0 ? /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
976
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: t("integrations.detail.logs.details.fields", "Fields") }),
977
- /* @__PURE__ */ jsx("dl", { className: "grid gap-3 sm:grid-cols-2", children: inlineEntries.map(([key, value]) => /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted/30 px-3 py-2", children: [
978
- /* @__PURE__ */ jsx("dt", { className: "text-overline font-medium uppercase tracking-wide text-muted-foreground", children: formatLogDetailLabel(key) }),
979
- /* @__PURE__ */ jsx("dd", { className: "mt-1 break-words text-sm", children: formatLogPrimitiveValue(value) })
980
- ] }, key)) })
981
- ] }) : null
982
- ] }),
983
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
984
- nestedEntries.map(([key, value]) => /* @__PURE__ */ jsx(
985
- JsonDisplay,
986
- {
987
- data: value,
988
- title: formatLogDetailLabel(key),
989
- defaultExpanded: true,
990
- maxInitialDepth: 1,
991
- theme: "dark",
992
- maxHeight: "16rem",
993
- className: "p-4"
994
- },
995
- key
996
- )),
997
- log.payload && nestedEntries.length === 0 ? /* @__PURE__ */ jsx(
998
- JsonDisplay,
999
- {
1000
- data: log.payload,
1001
- title: t("integrations.detail.logs.details.payload", "Payload"),
1002
- defaultExpanded: true,
1003
- maxInitialDepth: 1,
1004
- theme: "dark",
1005
- maxHeight: "16rem",
1006
- className: "p-4"
1007
- }
1008
- ) : null,
1009
- !log.payload ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed px-4 py-6 text-sm text-muted-foreground", children: t("integrations.detail.logs.details.noPayload", "No structured payload was stored for this log entry.") }) : null
958
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
959
+ nestedEntries.map(([key, value]) => /* @__PURE__ */ jsx(
960
+ JsonDisplay,
961
+ {
962
+ data: value,
963
+ title: formatLogDetailLabel(key),
964
+ defaultExpanded: true,
965
+ maxInitialDepth: 1,
966
+ theme: "dark",
967
+ maxHeight: "16rem",
968
+ className: "p-4"
969
+ },
970
+ key
971
+ )),
972
+ log.payload && nestedEntries.length === 0 ? /* @__PURE__ */ jsx(
973
+ JsonDisplay,
974
+ {
975
+ data: log.payload,
976
+ title: t("integrations.detail.logs.details.payload", "Payload"),
977
+ defaultExpanded: true,
978
+ maxInitialDepth: 1,
979
+ theme: "dark",
980
+ maxHeight: "16rem",
981
+ className: "p-4"
982
+ }
983
+ ) : null,
984
+ !log.payload ? /* @__PURE__ */ jsx(
985
+ EmptyState,
986
+ {
987
+ size: "sm",
988
+ icon: /* @__PURE__ */ jsx(FileX, { className: "h-8 w-8", "aria-hidden": "true" }),
989
+ title: t("integrations.detail.logs.details.noPayload", "No structured payload was stored for this log entry.")
990
+ }
991
+ ) : null
992
+ ] })
1010
993
  ] })
1011
- ] }) }) }) }) : null
1012
- ] }, log.id);
1013
- }) })
1014
- ] }) })
994
+ };
995
+ }),
996
+ emptyMessage: t("integrations.detail.logs.empty")
997
+ }
998
+ )
1015
999
  ] }) : null,
1016
1000
  injectedTabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, { value: tab.id, className: "mt-0 space-y-4", children: /* @__PURE__ */ jsx(
1017
1001
  InjectionSpot,