@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/authFixtures.js.map +1 -1
- package/dist/helpers/integration/authUi.js +10 -2
- package/dist/helpers/integration/authUi.js.map +2 -2
- package/dist/helpers/integration/salesUi.js +3 -1
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js +10 -1
- package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
- package/dist/modules/audit_logs/lib/display-helpers.js +28 -27
- package/dist/modules/audit_logs/lib/display-helpers.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +21 -3
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +6 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +4 -1
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +56 -2
- package/dist/modules/auth/backend/users/page.js.map +3 -3
- package/dist/modules/auth/commands/users.js +14 -0
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/data/validators.js +8 -0
- package/dist/modules/auth/data/validators.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +15 -9
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +26 -3
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +1 -1
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/components/PipelineSettings.js +108 -99
- package/dist/modules/customers/components/PipelineSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +13 -5
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +10 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +15 -8
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +35 -22
- package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js +2 -2
- package/dist/modules/customers/components/detail/TasksSection.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +73 -64
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +11 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +2 -9
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +14 -29
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +10 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +79 -95
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +49 -70
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js +1 -1
- package/dist/modules/planner/components/AvailabilityRuleSetForm.js.map +1 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -19
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/resources/components/ResourceCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceCrudForm.js.map +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js +1 -1
- package/dist/modules/resources/components/ResourceTypeCrudForm.js.map +2 -2
- package/dist/modules/sales/components/documents/ReturnDialog.js +11 -8
- package/dist/modules/sales/components/documents/ReturnDialog.js.map +2 -2
- package/dist/modules/staff/backend/staff/profile/create/page.js +1 -1
- package/dist/modules/staff/backend/staff/profile/create/page.js.map +2 -2
- package/dist/modules/staff/components/TeamForm.js +1 -1
- package/dist/modules/staff/components/TeamForm.js.map +2 -2
- package/dist/modules/staff/components/TeamMemberForm.js +1 -1
- package/dist/modules/staff/components/TeamMemberForm.js.map +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js +1 -1
- package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
- package/package.json +5 -5
- package/src/helpers/integration/authFixtures.ts +1 -1
- package/src/helpers/integration/authUi.ts +11 -2
- package/src/helpers/integration/salesUi.ts +10 -1
- package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +7 -3
- package/src/modules/audit_logs/lib/display-helpers.tsx +22 -14
- package/src/modules/auth/api/users/route.ts +22 -3
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +9 -1
- package/src/modules/auth/backend/users/create/page.tsx +6 -2
- package/src/modules/auth/backend/users/page.tsx +60 -3
- package/src/modules/auth/commands/users.ts +15 -0
- package/src/modules/auth/data/validators.ts +8 -0
- package/src/modules/auth/i18n/de.json +4 -0
- package/src/modules/auth/i18n/en.json +4 -0
- package/src/modules/auth/i18n/es.json +4 -0
- package/src/modules/auth/i18n/pl.json +4 -0
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +12 -13
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +17 -13
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +1 -1
- package/src/modules/customers/components/PipelineSettings.tsx +95 -95
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +7 -4
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +13 -8
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +16 -12
- package/src/modules/customers/components/detail/RolesSection.tsx +34 -31
- package/src/modules/customers/components/detail/TasksSection.tsx +16 -8
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +77 -51
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +7 -3
- package/src/modules/data_sync/backend/data-sync/page.tsx +4 -7
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -54
- package/src/modules/dictionaries/components/DictionariesManager.tsx +7 -4
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +101 -146
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +60 -103
- package/src/modules/planner/components/AvailabilityRuleSetForm.tsx +1 -1
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +17 -17
- package/src/modules/resources/components/ResourceCrudForm.tsx +1 -1
- package/src/modules/resources/components/ResourceTypeCrudForm.tsx +1 -1
- package/src/modules/sales/components/documents/ReturnDialog.tsx +10 -7
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/staff/backend/staff/profile/create/page.tsx +1 -1
- package/src/modules/staff/components/TeamForm.tsx +1 -1
- package/src/modules/staff/components/TeamMemberForm.tsx +1 -1
- 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": ";
|
|
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 {
|
|
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, {}) }) :
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
["
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
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
|
-
|
|
971
|
-
/* @__PURE__ */ jsx("
|
|
972
|
-
/* @__PURE__ */ jsx("
|
|
973
|
-
|
|
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
|
-
|
|
976
|
-
/* @__PURE__ */ jsx(
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
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
|
-
|
|
1012
|
-
|
|
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,
|