@open-mercato/core 0.4.2-canary-15e78de280 → 0.4.2-canary-f075c3eb92

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 (87) hide show
  1. package/dist/modules/api_keys/setup.js +11 -0
  2. package/dist/modules/api_keys/setup.js.map +7 -0
  3. package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
  4. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  5. package/dist/modules/attachments/lib/assignmentDetails.js +31 -17
  6. package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
  7. package/dist/modules/attachments/lib/partitions.js +3 -3
  8. package/dist/modules/attachments/lib/partitions.js.map +2 -2
  9. package/dist/modules/attachments/setup.js +11 -0
  10. package/dist/modules/attachments/setup.js.map +7 -0
  11. package/dist/modules/audit_logs/setup.js +12 -0
  12. package/dist/modules/audit_logs/setup.js.map +7 -0
  13. package/dist/modules/auth/lib/setup-app.js +29 -159
  14. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  15. package/dist/modules/auth/setup.js +11 -0
  16. package/dist/modules/auth/setup.js.map +7 -0
  17. package/dist/modules/business_rules/setup.js +11 -0
  18. package/dist/modules/business_rules/setup.js.map +7 -0
  19. package/dist/modules/catalog/setup.js +22 -0
  20. package/dist/modules/catalog/setup.js.map +7 -0
  21. package/dist/modules/configs/lib/upgrade-actions.js +65 -15
  22. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  23. package/dist/modules/configs/setup.js +16 -0
  24. package/dist/modules/configs/setup.js.map +7 -0
  25. package/dist/modules/currencies/setup.js +16 -0
  26. package/dist/modules/currencies/setup.js.map +7 -0
  27. package/dist/modules/customers/setup.js +36 -0
  28. package/dist/modules/customers/setup.js.map +7 -0
  29. package/dist/modules/dashboards/setup.js +12 -0
  30. package/dist/modules/dashboards/setup.js.map +7 -0
  31. package/dist/modules/dictionaries/setup.js +12 -0
  32. package/dist/modules/dictionaries/setup.js.map +7 -0
  33. package/dist/modules/directory/setup.js +12 -0
  34. package/dist/modules/directory/setup.js.map +7 -0
  35. package/dist/modules/entities/setup.js +11 -0
  36. package/dist/modules/entities/setup.js.map +7 -0
  37. package/dist/modules/feature_toggles/setup.js +11 -0
  38. package/dist/modules/feature_toggles/setup.js.map +7 -0
  39. package/dist/modules/perspectives/setup.js +12 -0
  40. package/dist/modules/perspectives/setup.js.map +7 -0
  41. package/dist/modules/planner/setup.js +21 -0
  42. package/dist/modules/planner/setup.js.map +7 -0
  43. package/dist/modules/query_index/setup.js +11 -0
  44. package/dist/modules/query_index/setup.js.map +7 -0
  45. package/dist/modules/resources/setup.js +21 -0
  46. package/dist/modules/resources/setup.js.map +7 -0
  47. package/dist/modules/sales/setup.js +99 -0
  48. package/dist/modules/sales/setup.js.map +7 -0
  49. package/dist/modules/staff/setup.js +27 -0
  50. package/dist/modules/staff/setup.js.map +7 -0
  51. package/dist/modules/workflows/lib/seeds.js +3 -15
  52. package/dist/modules/workflows/lib/seeds.js.map +2 -2
  53. package/dist/modules/workflows/migrations/Migration20251207131955.js +76 -72
  54. package/dist/modules/workflows/migrations/Migration20251207131955.js.map +2 -2
  55. package/dist/modules/workflows/setup.js +16 -0
  56. package/dist/modules/workflows/setup.js.map +7 -0
  57. package/package.json +2 -2
  58. package/src/__tests__/module-decoupling.test.ts +356 -0
  59. package/src/modules/api_keys/setup.ts +9 -0
  60. package/src/modules/attachments/components/AttachmentLibrary.tsx +2 -2
  61. package/src/modules/attachments/lib/assignmentDetails.ts +32 -16
  62. package/src/modules/attachments/lib/partitions.ts +3 -3
  63. package/src/modules/attachments/setup.ts +9 -0
  64. package/src/modules/audit_logs/setup.ts +10 -0
  65. package/src/modules/auth/__tests__/cli-setup-acl.test.ts +30 -0
  66. package/src/modules/auth/lib/setup-app.ts +40 -177
  67. package/src/modules/auth/setup.ts +9 -0
  68. package/src/modules/business_rules/setup.ts +9 -0
  69. package/src/modules/catalog/setup.ts +22 -0
  70. package/src/modules/configs/lib/upgrade-actions.ts +78 -17
  71. package/src/modules/configs/setup.ts +14 -0
  72. package/src/modules/currencies/setup.ts +15 -0
  73. package/src/modules/customers/setup.ts +36 -0
  74. package/src/modules/dashboards/setup.ts +10 -0
  75. package/src/modules/dictionaries/setup.ts +10 -0
  76. package/src/modules/directory/setup.ts +10 -0
  77. package/src/modules/entities/setup.ts +9 -0
  78. package/src/modules/feature_toggles/setup.ts +9 -0
  79. package/src/modules/perspectives/setup.ts +10 -0
  80. package/src/modules/planner/setup.ts +21 -0
  81. package/src/modules/query_index/setup.ts +9 -0
  82. package/src/modules/resources/setup.ts +21 -0
  83. package/src/modules/sales/setup.ts +108 -0
  84. package/src/modules/staff/setup.ts +27 -0
  85. package/src/modules/workflows/lib/seeds.ts +4 -16
  86. package/src/modules/workflows/migrations/Migration20251207131955.ts +77 -143
  87. package/src/modules/workflows/setup.ts +15 -0
@@ -0,0 +1,11 @@
1
+ const setup = {
2
+ defaultRoleFeatures: {
3
+ admin: ["api_keys.*"]
4
+ }
5
+ };
6
+ var setup_default = setup;
7
+ export {
8
+ setup_default as default,
9
+ setup
10
+ };
11
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/api_keys/setup.ts"],
4
+ "sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n admin: ['api_keys.*'],\n },\n}\n\nexport default setup\n"],
5
+ "mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,OAAO,CAAC,YAAY;AAAA,EACtB;AACF;AAEA,IAAO,gBAAQ;",
6
+ "names": []
7
+ }
@@ -727,7 +727,7 @@ function AttachmentLibrary() {
727
727
  if (!assignments.length) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" });
728
728
  return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: assignments.map((assignment) => {
729
729
  const label = assignment.label?.trim() || assignment.id;
730
- const hideType = assignment.type === E.catalog.catalog_product || assignment.type === E.catalog.catalog_product_variant;
730
+ const hideType = assignment.type === E.catalog?.catalog_product || assignment.type === E.catalog?.catalog_product_variant;
731
731
  const content = hideType ? label : `${assignment.type}: ${label}`;
732
732
  return assignment.href ? /* @__PURE__ */ jsx(
733
733
  "a",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/components/AttachmentLibrary.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { TagsInput } from '@open-mercato/ui/backend/inputs/TagsInput'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudCustomFieldRenderProps } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { z } from 'zod'\nimport { E } from '#generated/entities.ids.generated'\nimport type { LucideIcon } from 'lucide-react'\nimport { Download, Plus, Upload, Trash2, File, FileText, FileSpreadsheet, FileArchive, FileAudio, FileVideo, FileCode } from 'lucide-react'\nimport { buildAttachmentFileUrl, buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { AttachmentDeleteDialog, AttachmentMetadataDialog, type AttachmentItem, type AttachmentMetadataSavePayload, type AssignmentDraft } from '@open-mercato/ui/backend/detail'\n\ntype AttachmentAssignment = {\n type: string\n id: string\n href?: string | null\n label?: string | null\n}\n\ntype AttachmentRow = AttachmentItem\n\ntype AttachmentLibraryResponse = {\n items: AttachmentRow[]\n page: number\n pageSize: number\n total: number\n totalPages: number\n availableTags: string[]\n partitions: Array<{ code: string; title: string; description?: string | null; isPublic?: boolean }>\n error?: string\n}\n\nconst PAGE_SIZE = 25\nconst ENV_APP_URL = (process.env.NEXT_PUBLIC_APP_URL || '').replace(/\\/$/, '')\nconst LIBRARY_ENTITY_ID = 'attachments:library'\n\nfunction filterLibraryAssignments(assignments?: AttachmentAssignment[] | null): AttachmentAssignment[] {\n return (assignments ?? []).filter((assignment) => assignment.type !== LIBRARY_ENTITY_ID)\n}\n\nfunction formatFileSize(value: number): string {\n if (!Number.isFinite(value)) return '\u2014'\n if (value <= 0) return '0 B'\n const units = ['B', 'KB', 'MB', 'GB', 'TB']\n let idx = 0\n let current = value\n while (current >= 1024 && idx < units.length - 1) {\n current /= 1024\n idx += 1\n }\n return `${current.toFixed(idx === 0 ? 0 : 1)} ${units[idx]}`\n}\n\nfunction humanDate(value: string, locale?: string): string {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleString(locale ?? undefined)\n}\n\nfunction buildFilterSignature(values: FilterValues): string {\n return JSON.stringify(values, Object.keys(values).sort())\n}\n\nfunction resolveAbsoluteUrl(path: string): string {\n if (!path) return path\n if (/^https?:\\/\\//i.test(path)) return path\n const base =\n ENV_APP_URL ||\n (typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '')\n if (!base) return path\n const normalizedBase = base.replace(/\\/$/, '')\n return `${normalizedBase}${path.startsWith('/') ? path : `/${path}`}`\n}\n\nfunction resolveFileExtension(fileName?: string | null): string {\n if (!fileName) return ''\n const normalized = fileName.trim()\n if (!normalized) return ''\n const lastDot = normalized.lastIndexOf('.')\n if (lastDot === -1 || lastDot === normalized.length - 1) return ''\n return normalized.slice(lastDot + 1).toLowerCase()\n}\n\nconst EXTENSION_ICON_MAP: Record<string, LucideIcon> = {\n pdf: FileText,\n doc: FileText,\n docx: FileText,\n txt: FileText,\n md: FileText,\n rtf: FileText,\n xls: FileSpreadsheet,\n xlsx: FileSpreadsheet,\n csv: FileSpreadsheet,\n ods: FileSpreadsheet,\n ppt: FileText,\n pptx: FileText,\n zip: FileArchive,\n gz: FileArchive,\n rar: FileArchive,\n tgz: FileArchive,\n '7z': FileArchive,\n tar: FileArchive,\n json: FileCode,\n js: FileCode,\n ts: FileCode,\n jsx: FileCode,\n tsx: FileCode,\n html: FileCode,\n css: FileCode,\n xml: FileCode,\n yaml: FileCode,\n yml: FileCode,\n mp3: FileAudio,\n wav: FileAudio,\n flac: FileAudio,\n ogg: FileAudio,\n mp4: FileVideo,\n mov: FileVideo,\n avi: FileVideo,\n webm: FileVideo,\n}\n\nconst MIME_FALLBACK_ICONS: Record<string, LucideIcon> = {\n audio: FileAudio,\n video: FileVideo,\n text: FileText,\n application: FileText,\n}\n\nfunction resolveAttachmentPlaceholder(mimeType?: string | null, fileName?: string | null): { icon: LucideIcon; label: string } {\n const extension = resolveFileExtension(fileName)\n const normalizedMime = typeof mimeType === 'string' ? mimeType.toLowerCase() : ''\n if (extension && EXTENSION_ICON_MAP[extension]) {\n return { icon: EXTENSION_ICON_MAP[extension], label: extension.toUpperCase() }\n }\n if (!extension && normalizedMime.includes('pdf')) {\n return { icon: FileText, label: 'PDF' }\n }\n if (!extension && normalizedMime.includes('zip')) {\n return { icon: FileArchive, label: 'ZIP' }\n }\n if (!extension && normalizedMime.includes('json')) {\n return { icon: FileCode, label: 'JSON' }\n }\n const mimeRoot = normalizedMime.split('/')[0] || ''\n if (mimeRoot && MIME_FALLBACK_ICONS[mimeRoot]) {\n return { icon: MIME_FALLBACK_ICONS[mimeRoot], label: mimeRoot.toUpperCase() }\n }\n const fallbackSource = extension || mimeRoot || 'file'\n const fallbackLabel = fallbackSource.slice(0, 6).toUpperCase()\n return { icon: File, label: fallbackLabel }\n}\n\nfunction normalizeCustomFieldSubmitValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.filter((entry) => entry !== undefined)\n }\n if (value === undefined) return null\n return value\n}\n\n\ntype AttachmentUploadFormValues = {\n files: File[]\n partitionCode?: string\n tags?: string[]\n assignments?: AssignmentDraft[]\n} & Record<string, unknown>\n\ntype AssignmentsEditorProps = {\n value: AssignmentDraft[]\n onChange: (next: AssignmentDraft[]) => void\n labels: {\n title: string\n description: string\n type: string\n id: string\n href: string\n label?: string\n add: string\n remove: string\n }\n disabled?: boolean\n}\n\nfunction AttachmentAssignmentsEditor({ value, onChange, labels, disabled }: AssignmentsEditorProps) {\n const handleChange = React.useCallback(\n (index: number, patch: Partial<AssignmentDraft>) => {\n onChange(value.map((entry, idx) => (idx === index ? { ...entry, ...patch } : entry)))\n },\n [onChange, value],\n )\n\n const handleRemove = React.useCallback(\n (index: number) => {\n onChange(value.filter((_, idx) => idx !== index))\n },\n [onChange, value],\n )\n\n const handleAdd = React.useCallback(() => {\n onChange([...value, { type: '', id: '', href: '', label: '' }])\n }, [onChange, value])\n\n return (\n <div className=\"space-y-2\">\n <div>\n <div className=\"text-sm font-medium\">{labels.title}</div>\n <div className=\"text-xs text-muted-foreground\">{labels.description}</div>\n </div>\n <div className=\"space-y-3\">\n {value.length === 0 ? (\n <div className=\"text-xs text-muted-foreground\">No assignments yet.</div>\n ) : (\n value.map((entry, index) => (\n <div key={`${index}-${entry.type}-${entry.id}`} className=\"rounded border p-3 space-y-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.type}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.type}\n disabled={disabled}\n onChange={(event) => handleChange(index, { type: event.target.value })}\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.id}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.id}\n disabled={disabled}\n onChange={(event) => handleChange(index, { id: event.target.value })}\n />\n </div>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.href}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.href ?? ''}\n disabled={disabled}\n onChange={(event) => handleChange(index, { href: event.target.value })}\n />\n </div>\n {labels.label ? (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.label}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.label ?? ''}\n disabled={disabled}\n onChange={(event) => handleChange(index, { label: event.target.value })}\n />\n </div>\n ) : null}\n </div>\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => handleRemove(index)}\n className=\"inline-flex items-center gap-1 text-muted-foreground\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {labels.remove}\n </Button>\n </div>\n </div>\n ))\n )}\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={disabled} onClick={handleAdd} className=\"inline-flex items-center gap-1\">\n <Plus className=\"h-4 w-4\" />\n {labels.add}\n </Button>\n </div>\n )\n}\n\ntype AttachmentFilesFieldProps = CrudCustomFieldRenderProps & {\n labels: {\n dropHint: string\n choose: string\n uploading: string\n empty: string\n }\n uploading: boolean\n}\n\nfunction AttachmentFilesField({\n value,\n setValue,\n disabled,\n error,\n labels,\n uploading,\n}: AttachmentFilesFieldProps) {\n const files = React.useMemo(() => (Array.isArray(value) ? (value as File[]) : []), [value])\n const [isDragOver, setDragOver] = React.useState(false)\n const fileInputRef = React.useRef<HTMLInputElement | null>(null)\n\n const acceptFiles = React.useCallback(\n (list: FileList | null) => {\n if (!list?.length) return\n const dedupe = new Map<string, File>(files.map((file) => [`${file.name}:${file.size}`, file]))\n Array.from(list).forEach((file) => {\n dedupe.set(`${file.name}:${file.size}`, file)\n })\n setValue(Array.from(dedupe.values()))\n },\n [files, setValue],\n )\n\n const handleDrop = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n if (disabled || uploading) return\n event.preventDefault()\n event.stopPropagation()\n setDragOver(false)\n acceptFiles(event.dataTransfer?.files ?? null)\n },\n [acceptFiles, disabled, uploading],\n )\n\n const handleDragOver = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n if (disabled || uploading) return\n event.preventDefault()\n event.stopPropagation()\n setDragOver(true)\n },\n [disabled, uploading],\n )\n\n const handleDragLeave = React.useCallback((event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.stopPropagation()\n setDragOver(false)\n }, [])\n\n const removeFile = React.useCallback(\n (name: string, size: number) => {\n if (disabled || uploading) return\n setValue(files.filter((file) => !(file.name === name && file.size === size)))\n },\n [disabled, files, setValue, uploading],\n )\n\n const pickFiles = React.useCallback(() => {\n if (disabled || uploading) return\n fileInputRef.current?.click()\n }, [disabled, uploading])\n\n const renderFileList = () => {\n if (!files.length) {\n return <p className=\"text-xs text-muted-foreground\">{labels.empty}</p>\n }\n return (\n <div className=\"space-y-2\">\n {files.map((candidate) => (\n <div key={`${candidate.name}-${candidate.size}`} className=\"flex items-center justify-between rounded border px-3 py-2 text-sm\">\n <div>\n <div className=\"font-medium\">{candidate.name}</div>\n <div className=\"text-xs text-muted-foreground\">{formatFileSize(candidate.size)}</div>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => removeFile(candidate.name, candidate.size)}\n disabled={disabled || uploading}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div\n className={cn(\n 'flex flex-col items-center justify-center rounded-lg border border-dashed p-6 text-center transition-colors',\n isDragOver ? 'border-primary bg-primary/5' : 'border-muted-foreground/30',\n disabled || uploading ? 'opacity-70' : '',\n )}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n role=\"presentation\"\n >\n <Upload className=\"mx-auto h-6 w-6 text-muted-foreground\" />\n <p className=\"mt-2 text-sm text-muted-foreground\">{labels.dropHint}</p>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"mt-4\" onClick={pickFiles} disabled={disabled || uploading}>\n {uploading ? labels.uploading : labels.choose}\n </Button>\n <input\n ref={fileInputRef}\n type=\"file\"\n className=\"hidden\"\n multiple\n onChange={(event) => {\n acceptFiles(event.target.files)\n event.currentTarget.value = ''\n }}\n disabled={disabled || uploading}\n />\n </div>\n {renderFileList()}\n {error ? <p className=\"text-xs font-medium text-red-600\">{error}</p> : null}\n </div>\n )\n}\n\ntype AttachmentUploadFormProps = {\n partitions: Array<{ code: string; title: string }>\n availableTags: string[]\n onUploaded: () => void\n onCancel: () => void\n}\n\nfunction AttachmentUploadForm({ partitions, availableTags, onUploaded, onCancel }: AttachmentUploadFormProps) {\n const t = useT()\n const [isUploading, setIsUploading] = React.useState(false)\n const [uploadProgress, setUploadProgress] = React.useState<{ completed: number; total: number }>({ completed: 0, total: 0 })\n\n const partitionOptions = React.useMemo(\n () =>\n partitions.map((entry) => ({\n value: entry.code,\n label: entry.title || entry.code,\n })),\n [partitions],\n )\n\n const assignmentLabels = React.useMemo(\n () => ({\n title: t('attachments.library.upload.assignments.title', 'Assignments'),\n description: t(\n 'attachments.library.upload.assignments.description',\n 'Optionally link this file to existing records now or add them later.',\n ),\n type: t('attachments.library.upload.assignments.type', 'Type'),\n id: t('attachments.library.upload.assignments.id', 'Record ID'),\n href: t('attachments.library.upload.assignments.href', 'Link'),\n label: t('attachments.library.upload.assignments.label', 'Label'),\n add: t('attachments.library.upload.assignments.add', 'Add assignment'),\n remove: t('attachments.library.upload.assignments.remove', 'Remove'),\n }),\n [t],\n )\n\n const formSchema = React.useMemo(\n () =>\n z\n .object({\n files: z.array(z.any()).min(1, { message: t('attachments.library.upload.fileRequired', 'Select at least one file to upload.') }),\n partitionCode: z.string().optional(),\n tags: z.array(z.string()).optional(),\n assignments: z\n .array(\n z.object({\n type: z.string().min(1),\n id: z.string().min(1),\n href: z.string().optional(),\n label: z.string().optional(),\n }),\n )\n .optional(),\n })\n .passthrough(),\n [t],\n )\n\n const fields = React.useMemo<CrudField[]>(() => {\n return [\n {\n id: 'files',\n label: t('attachments.library.upload.file', 'Files'),\n type: 'custom',\n component: (props) => (\n <AttachmentFilesField\n {...props}\n uploading={isUploading}\n labels={{\n dropHint: t('attachments.library.upload.dropHint', 'Drag and drop files here or click to upload.'),\n choose: t('attachments.library.upload.choose', 'Choose files'),\n uploading: t('attachments.library.upload.submitting', 'Uploading\u2026'),\n empty: t('attachments.library.upload.noFiles', 'No files selected yet.'),\n }}\n />\n ),\n },\n {\n id: 'partitionCode',\n label: t('attachments.library.upload.partition', 'Partition'),\n type: 'select',\n options: [\n { value: '', label: t('attachments.library.upload.partitionDefault', 'Default (private)') },\n ...partitionOptions,\n ],\n },\n {\n id: 'tags',\n label: t('attachments.library.table.tags', 'Tags'),\n type: 'custom',\n component: ({ value, setValue, disabled }) => (\n <TagsInput\n value={Array.isArray(value) ? (value as string[]) : []}\n onChange={(next) => setValue(next)}\n suggestions={availableTags}\n placeholder={t('attachments.library.upload.tagsPlaceholder', 'Add tags')}\n disabled={Boolean(disabled) || isUploading}\n />\n ),\n },\n {\n id: 'assignments',\n label: '',\n type: 'custom',\n component: ({ value, setValue, disabled }) => (\n <AttachmentAssignmentsEditor\n value={Array.isArray(value) ? (value as AssignmentDraft[]) : []}\n onChange={(next) => setValue(next)}\n labels={assignmentLabels}\n disabled={Boolean(disabled) || isUploading}\n />\n ),\n },\n ]\n }, [assignmentLabels, availableTags, isUploading, partitionOptions, t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n return [\n {\n id: 'details',\n title: t('attachments.library.upload.title', 'Upload attachment'),\n column: 1,\n fields: ['files', 'partitionCode', 'tags', 'assignments'],\n },\n {\n id: 'customFields',\n title: t('entities.customFields.title', 'Custom attributes'),\n column: 2,\n kind: 'customFields',\n },\n ]\n }, [t])\n\n const uploadPercentage = uploadProgress.total\n ? Math.min(100, Math.round((uploadProgress.completed / uploadProgress.total) * 100))\n : 0\n\n const handleSubmit = React.useCallback(\n async (values: AttachmentUploadFormValues) => {\n const files = Array.isArray(values.files) ? values.files : []\n if (!files.length) {\n throw new Error(t('attachments.library.upload.fileRequired', 'Select at least one file to upload.'))\n }\n setUploadProgress({ completed: 0, total: files.length })\n setIsUploading(true)\n try {\n const tags = Array.isArray(values.tags)\n ? values.tags\n .map((tag) => (typeof tag === 'string' ? tag.trim() : ''))\n .filter((tag) => tag.length > 0)\n : []\n const cleanedAssignments =\n Array.isArray(values.assignments) && values.assignments.length\n ? values.assignments\n .map((assignment) => ({\n type: assignment.type?.trim() ?? '',\n id: assignment.id?.trim() ?? '',\n href: assignment.href?.trim() || undefined,\n label: assignment.label?.trim() || undefined,\n }))\n .filter((assignment) => assignment.type && assignment.id)\n : []\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n let completed = 0\n for (const file of files) {\n const fd = new FormData()\n fd.set('entityId', LIBRARY_ENTITY_ID)\n fd.set(\n 'recordId',\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : String(Date.now()),\n )\n fd.set('file', file)\n if (typeof values.partitionCode === 'string' && values.partitionCode.trim().length) {\n fd.set('partitionCode', values.partitionCode.trim())\n }\n if (tags.length) fd.set('tags', JSON.stringify(tags))\n if (cleanedAssignments.length) fd.set('assignments', JSON.stringify(cleanedAssignments))\n if (Object.keys(customFields).length) fd.set('customFields', JSON.stringify(customFields))\n const call = await apiCall<{ error?: string }>('/api/attachments', {\n method: 'POST',\n body: fd,\n })\n if (!call.ok) {\n const message = call.result?.error || t('attachments.library.upload.failed', 'Upload failed.')\n throw new Error(message)\n }\n completed += 1\n setUploadProgress({ completed, total: files.length })\n }\n flash(t('attachments.library.upload.success', 'Attachment uploaded.'), 'success')\n onUploaded()\n onCancel()\n } catch (err: any) {\n const message = err?.message || t('attachments.library.upload.failed', 'Upload failed.')\n flash(message, 'error')\n throw new Error(message)\n } finally {\n setIsUploading(false)\n }\n },\n [onCancel, onUploaded, t],\n )\n\n return (\n <div className=\"relative\">\n <CrudForm<AttachmentUploadFormValues>\n embedded\n schema={formSchema}\n entityId={E.attachments.attachment}\n fields={fields}\n groups={groups}\n initialValues={{ files: [], tags: [], assignments: [], partitionCode: '' }}\n submitLabel={\n isUploading\n ? t('attachments.library.upload.submitting', 'Uploading\u2026')\n : t('attachments.library.upload.submit', 'Upload')\n }\n extraActions={\n <Button type=\"button\" variant=\"outline\" onClick={onCancel} disabled={isUploading}>\n {t('attachments.library.upload.cancel', 'Cancel')}\n </Button>\n }\n onSubmit={handleSubmit}\n />\n {isUploading ? (\n <div className=\"pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-background/90 px-6 text-center backdrop-blur\">\n <div className=\"flex w-full max-w-sm flex-col items-center gap-4 rounded-xl border border-border/50 bg-card/95 px-6 py-8 shadow-2xl\">\n <Spinner size=\"lg\" className=\"border-primary/50 border-t-primary\" />\n <div className=\"w-full space-y-3\">\n <p className=\"text-base font-semibold\">\n {t('attachments.library.upload.progressLabel', 'Uploading files')}\n </p>\n {uploadProgress.total > 0 ? (\n <>\n <p className=\"text-sm text-muted-foreground\">\n {uploadProgress.completed}/{uploadProgress.total}\n </p>\n <div className=\"h-2 w-full rounded bg-muted\">\n <div\n className=\"h-2 rounded bg-primary transition-all\"\n style={{\n width: `${uploadPercentage}%`,\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n )\n}\ntype UploadDialogProps = {\n open: boolean\n onOpenChange: (next: boolean) => void\n partitions: Array<{ code: string; title: string }>\n availableTags: string[]\n onUploaded: () => void\n}\n\nfunction AttachmentUploadDialog({ open, onOpenChange, partitions, availableTags, onUploaded }: UploadDialogProps) {\n const t = useT()\n const [formResetKey, setFormResetKey] = React.useState(0)\n const previousOpen = React.useRef(open)\n\n React.useEffect(() => {\n if (previousOpen.current && !open) {\n setFormResetKey((prev) => prev + 1)\n }\n previousOpen.current = open\n }, [open])\n\n const handleDialogChange = React.useCallback(\n (next: boolean) => {\n onOpenChange(next)\n },\n [onOpenChange],\n )\n\n const handleUploaded = React.useCallback(() => {\n onUploaded()\n }, [onUploaded])\n\n return (\n <Dialog open={open} onOpenChange={handleDialogChange}>\n <DialogContent className=\"sm:max-w-[54.6rem]\">\n <DialogHeader>\n <DialogTitle>{t('attachments.library.upload.title', 'Upload attachment')}</DialogTitle>\n </DialogHeader>\n <AttachmentUploadForm\n key={formResetKey}\n partitions={partitions}\n availableTags={availableTags}\n onUploaded={handleUploaded}\n onCancel={() => handleDialogChange(false)}\n />\n </DialogContent>\n </Dialog>\n )\n}\n\nexport function AttachmentLibrary() {\n const t = useT()\n const queryClient = useQueryClient()\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'createdAt', desc: true }])\n const [metadataDialogOpen, setMetadataDialogOpen] = React.useState(false)\n const [selectedRow, setSelectedRow] = React.useState<AttachmentRow | null>(null)\n const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false)\n const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)\n const [deleteTarget, setDeleteTarget] = React.useState<AttachmentRow | null>(null)\n const [deletePending, setDeletePending] = React.useState(false)\n const filterSignature = React.useMemo(() => buildFilterSignature(filterValues), [filterValues])\n const sortingSignature = React.useMemo(() => JSON.stringify(sorting), [sorting])\n\n const { data, isLoading, error, refetch } = useQuery({\n queryKey: ['attachments-library', page, search, filterSignature, sortingSignature],\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n if (search.trim().length > 0) params.set('search', search.trim())\n const partition = typeof filterValues.partition === 'string' ? filterValues.partition : ''\n if (partition) params.set('partition', partition)\n const tags = Array.isArray(filterValues.tags) ? filterValues.tags : []\n if (tags.length > 0) params.set('tags', tags.join(','))\n if (sorting.length > 0) {\n const primary = sorting[0]\n params.set('sortField', primary.id)\n params.set('sortDir', primary.desc ? 'desc' : 'asc')\n }\n const call = await apiCall<AttachmentLibraryResponse>(`/api/attachments/library?${params.toString()}`)\n if (!call.ok || !call.result) {\n const message = call.result?.error || t('attachments.library.errors.load', 'Failed to load attachments.')\n throw new Error(message)\n }\n return call.result\n },\n })\n\n const partitions = data?.partitions ?? []\n const availableTags = data?.availableTags ?? []\n\n const filters = React.useMemo<FilterDef[]>(() => {\n const partitionOptions = partitions.map((entry) => ({\n value: entry.code,\n label: entry.title || entry.code,\n }))\n return [\n {\n id: 'partition',\n label: t('attachments.library.filters.partition', 'Partition'),\n type: 'select',\n options: partitionOptions,\n },\n {\n id: 'tags',\n label: t('attachments.library.filters.tags', 'Tags'),\n type: 'tags',\n placeholder: t('attachments.library.filters.tagsPlaceholder', 'Filter by tag'),\n options: availableTags.map((tag) => ({ value: tag, label: tag })),\n },\n ]\n }, [availableTags, partitions, t])\n\n const items = data?.items ?? []\n\n const columns = React.useMemo<ColumnDef<AttachmentRow>[]>(() => {\n return [\n {\n id: 'preview',\n header: '',\n enableSorting: false,\n cell: ({ row }) => {\n const value = row.original\n if (value.thumbnailUrl) {\n return (\n <div className=\"h-16 w-16 overflow-hidden rounded border bg-muted\">\n <img\n src={value.thumbnailUrl}\n alt={value.fileName}\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n )\n }\n const placeholder = resolveAttachmentPlaceholder(value.mimeType, value.fileName)\n const PlaceholderIcon = placeholder.icon\n return (\n <div className=\"flex h-16 w-16 flex-col items-center justify-center rounded border bg-muted text-[10px] font-semibold uppercase text-muted-foreground\">\n <PlaceholderIcon className=\"mb-1 h-5 w-5 text-muted-foreground\" aria-hidden />\n {placeholder.label}\n </div>\n )\n },\n },\n {\n id: 'fileName',\n accessorKey: 'fileName',\n header: t('attachments.library.table.file', 'File'),\n cell: ({ row }) => {\n const value = row.original\n return (\n <div className=\"space-y-1 min-w-0 max-w-[280px]\">\n <div className=\"font-medium truncate\" title={value.fileName}>\n {value.fileName}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {formatFileSize(value.fileSize)} \u2022 {value.mimeType || 'application/octet-stream'}\n </div>\n <div className=\"text-xs text-muted-foreground line-clamp-2\">\n {value.content?.trim()\n ? value.content\n : t('attachments.library.metadata.noContent', 'No text extracted')}\n </div>\n </div>\n )\n },\n },\n {\n id: 'tags',\n accessorKey: 'tags',\n header: t('attachments.library.table.tags', 'Tags'),\n enableSorting: false,\n cell: ({ row }) => {\n const tags = row.original.tags ?? []\n if (!tags.length) return <span className=\"text-xs text-muted-foreground\">\u2014</span>\n return (\n <div className=\"flex flex-wrap gap-1\">\n {tags.map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n </div>\n )\n },\n },\n {\n id: 'assignments',\n accessorKey: 'assignments',\n header: t('attachments.library.table.assignments', 'Assignments'),\n enableSorting: false,\n cell: ({ row }) => {\n const assignments = filterLibraryAssignments(row.original.assignments)\n if (!assignments.length) return <span className=\"text-xs text-muted-foreground\">\u2014</span>\n return (\n <div className=\"flex flex-col gap-1\">\n {assignments.map((assignment) => {\n const label = assignment.label?.trim() || assignment.id\n const hideType =\n assignment.type === E.catalog.catalog_product ||\n assignment.type === E.catalog.catalog_product_variant\n const content = hideType ? label : `${assignment.type}: ${label}`\n return assignment.href ? (\n <a\n key={`${assignment.type}-${assignment.id}-${assignment.href}`}\n href={assignment.href}\n className=\"text-sm text-blue-600 underline\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {content}\n </a>\n ) : (\n <div key={`${assignment.type}-${assignment.id}`} className=\"text-sm\">\n {content}\n </div>\n )\n })}\n </div>\n )\n },\n },\n {\n id: 'partitionCode',\n accessorKey: 'partitionCode',\n header: t('attachments.library.table.partition', 'Partition'),\n cell: ({ row }) => (\n <div className=\"text-sm text-muted-foreground\">\n {row.original.partitionTitle ?? row.original.partitionCode}\n </div>\n ),\n },\n {\n id: 'createdAt',\n accessorKey: 'createdAt',\n header: t('attachments.library.table.created', 'Created'),\n cell: ({ row }) => {\n const createdAt = row.original.createdAt\n return (\n <div className=\"text-sm text-muted-foreground\">\n {createdAt ? humanDate(createdAt) : '\u2014'}\n </div>\n )\n },\n },\n {\n id: 'download',\n header: t('attachments.library.table.download', 'Download'),\n enableSorting: false,\n cell: ({ row }) => {\n const downloadPath = buildAttachmentFileUrl(row.original.id, { download: true })\n const absolute = resolveAbsoluteUrl(downloadPath)\n return (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a href={absolute} download aria-label={t('attachments.library.table.download', 'Download')}>\n <Download className=\"h-4 w-4\" />\n </a>\n </Button>\n )\n },\n },\n ]\n }, [t])\n\n const openMetadataDialog = React.useCallback((row: AttachmentRow) => {\n setSelectedRow(row)\n setMetadataDialogOpen(true)\n }, [])\n\n const openDeleteDialog = React.useCallback((row: AttachmentRow) => {\n setDeleteTarget(row)\n setDeleteDialogOpen(true)\n }, [])\n\n const handleMetadataSave = React.useCallback(\n async (id: string, payload: AttachmentMetadataSavePayload) => {\n try {\n const body: Record<string, unknown> = {\n tags: payload.tags,\n assignments: payload.assignments,\n }\n if (payload.customFields && Object.keys(payload.customFields).length) {\n body.customFields = payload.customFields\n }\n const call = await apiCall<{ error?: string }>(`/api/attachments/library/${encodeURIComponent(id)}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!call.ok) {\n const message =\n call.result?.error || t('attachments.library.metadata.error', 'Failed to update metadata.')\n flash(message, 'error')\n return\n }\n flash(t('attachments.library.metadata.success', 'Attachment updated.'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n setMetadataDialogOpen(false)\n } catch (err: any) {\n flash(err?.message || t('attachments.library.metadata.error', 'Failed to update metadata.'), 'error')\n }\n },\n [queryClient, t],\n )\n\n const handleUploadCompleted = React.useCallback(async () => {\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n }, [queryClient])\n\n const handleDelete = React.useCallback(async () => {\n if (!deleteTarget) return\n try {\n setDeletePending(true)\n const call = await apiCall<{ error?: string }>(\n `/api/attachments/library/${encodeURIComponent(deleteTarget.id)}`,\n { method: 'DELETE' },\n )\n if (!call.ok) {\n const message =\n call.result?.error || t('attachments.library.errors.delete', 'Failed to delete attachment.')\n flash(message, 'error')\n return\n }\n flash(t('attachments.library.messages.deleted', 'Attachment removed.'), 'success')\n if (selectedRow?.id === deleteTarget.id) {\n setSelectedRow(null)\n setMetadataDialogOpen(false)\n }\n setDeleteDialogOpen(false)\n setDeleteTarget(null)\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n } catch (err: any) {\n flash(err?.message || t('attachments.library.errors.delete', 'Failed to delete attachment.'), 'error')\n } finally {\n setDeletePending(false)\n }\n }, [deleteTarget, queryClient, selectedRow, t])\n\n const total = data?.total ?? 0\n const totalPages = data?.totalPages ?? 1\n return (\n <>\n <DataTable<AttachmentRow>\n title={t('attachments.library.title', 'Attachments')}\n refreshButton={{\n label: t('attachments.library.actions.refresh', 'Refresh'),\n onRefresh: () => { void refetch() },\n isRefreshing: isLoading,\n }}\n actions={(\n <Button onClick={() => setUploadDialogOpen(true)}>\n {t('attachments.library.actions.upload', 'Upload')}\n </Button>\n )}\n columns={columns}\n data={items}\n sorting={sorting}\n onSortingChange={setSorting}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n label: t('attachments.library.actions.open', 'Open'),\n onSelect: () => {\n if (!row.url) return\n window.open(row.url, '_blank', 'noopener,noreferrer')\n },\n },\n {\n label: t('attachments.library.actions.edit', 'Edit metadata'),\n onSelect: () => openMetadataDialog(row),\n },\n {\n label: t('attachments.library.actions.copyUrl', 'Copy URL'),\n onSelect: () => {\n if (!row.url) {\n flash(t('attachments.library.actions.copyError', 'Unable to copy link.'), 'error')\n return\n }\n const absolute = resolveAbsoluteUrl(row.url)\n navigator.clipboard\n .writeText(absolute)\n .then(() =>\n flash(\n t('attachments.library.actions.copied', 'Link copied.'),\n 'success',\n ),\n )\n .catch(() =>\n flash(\n t('attachments.library.actions.copyError', 'Unable to copy link.'),\n 'error',\n ),\n )\n },\n },\n {\n label: t('attachments.library.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => openDeleteDialog(row),\n },\n ]}\n />\n )}\n onRowClick={(row) => openMetadataDialog(row)}\n isLoading={isLoading}\n error={error?.message}\n emptyState={\n <div className=\"py-10 text-center text-sm text-muted-foreground\">\n {t('attachments.library.table.empty', 'No attachments found.')}\n </div>\n }\n searchValue={search}\n onSearchChange={(value) => {\n setPage(1)\n setSearch(value)\n }}\n searchPlaceholder={t('attachments.library.table.search', 'Search files\u2026')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(values) => {\n setFilterValues(values)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: (next) => setPage(next),\n }}\n />\n <AttachmentMetadataDialog\n open={metadataDialogOpen}\n onOpenChange={setMetadataDialogOpen}\n item={selectedRow}\n availableTags={availableTags}\n onSave={handleMetadataSave}\n />\n <AttachmentDeleteDialog\n open={deleteDialogOpen}\n onOpenChange={setDeleteDialogOpen}\n fileName={deleteTarget?.fileName}\n onConfirm={handleDelete}\n isDeleting={deletePending}\n />\n <AttachmentUploadDialog\n open={uploadDialogOpen}\n onOpenChange={setUploadDialogOpen}\n partitions={partitions}\n availableTags={availableTags}\n onUploaded={handleUploadCompleted}\n />\n </>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { TagsInput } from '@open-mercato/ui/backend/inputs/TagsInput'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudCustomFieldRenderProps } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { z } from 'zod'\nimport { E } from '#generated/entities.ids.generated'\nimport type { LucideIcon } from 'lucide-react'\nimport { Download, Plus, Upload, Trash2, File, FileText, FileSpreadsheet, FileArchive, FileAudio, FileVideo, FileCode } from 'lucide-react'\nimport { buildAttachmentFileUrl, buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { AttachmentDeleteDialog, AttachmentMetadataDialog, type AttachmentItem, type AttachmentMetadataSavePayload, type AssignmentDraft } from '@open-mercato/ui/backend/detail'\n\ntype AttachmentAssignment = {\n type: string\n id: string\n href?: string | null\n label?: string | null\n}\n\ntype AttachmentRow = AttachmentItem\n\ntype AttachmentLibraryResponse = {\n items: AttachmentRow[]\n page: number\n pageSize: number\n total: number\n totalPages: number\n availableTags: string[]\n partitions: Array<{ code: string; title: string; description?: string | null; isPublic?: boolean }>\n error?: string\n}\n\nconst PAGE_SIZE = 25\nconst ENV_APP_URL = (process.env.NEXT_PUBLIC_APP_URL || '').replace(/\\/$/, '')\nconst LIBRARY_ENTITY_ID = 'attachments:library'\n\nfunction filterLibraryAssignments(assignments?: AttachmentAssignment[] | null): AttachmentAssignment[] {\n return (assignments ?? []).filter((assignment) => assignment.type !== LIBRARY_ENTITY_ID)\n}\n\nfunction formatFileSize(value: number): string {\n if (!Number.isFinite(value)) return '\u2014'\n if (value <= 0) return '0 B'\n const units = ['B', 'KB', 'MB', 'GB', 'TB']\n let idx = 0\n let current = value\n while (current >= 1024 && idx < units.length - 1) {\n current /= 1024\n idx += 1\n }\n return `${current.toFixed(idx === 0 ? 0 : 1)} ${units[idx]}`\n}\n\nfunction humanDate(value: string, locale?: string): string {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleString(locale ?? undefined)\n}\n\nfunction buildFilterSignature(values: FilterValues): string {\n return JSON.stringify(values, Object.keys(values).sort())\n}\n\nfunction resolveAbsoluteUrl(path: string): string {\n if (!path) return path\n if (/^https?:\\/\\//i.test(path)) return path\n const base =\n ENV_APP_URL ||\n (typeof window !== 'undefined' && window.location?.origin ? window.location.origin : '')\n if (!base) return path\n const normalizedBase = base.replace(/\\/$/, '')\n return `${normalizedBase}${path.startsWith('/') ? path : `/${path}`}`\n}\n\nfunction resolveFileExtension(fileName?: string | null): string {\n if (!fileName) return ''\n const normalized = fileName.trim()\n if (!normalized) return ''\n const lastDot = normalized.lastIndexOf('.')\n if (lastDot === -1 || lastDot === normalized.length - 1) return ''\n return normalized.slice(lastDot + 1).toLowerCase()\n}\n\nconst EXTENSION_ICON_MAP: Record<string, LucideIcon> = {\n pdf: FileText,\n doc: FileText,\n docx: FileText,\n txt: FileText,\n md: FileText,\n rtf: FileText,\n xls: FileSpreadsheet,\n xlsx: FileSpreadsheet,\n csv: FileSpreadsheet,\n ods: FileSpreadsheet,\n ppt: FileText,\n pptx: FileText,\n zip: FileArchive,\n gz: FileArchive,\n rar: FileArchive,\n tgz: FileArchive,\n '7z': FileArchive,\n tar: FileArchive,\n json: FileCode,\n js: FileCode,\n ts: FileCode,\n jsx: FileCode,\n tsx: FileCode,\n html: FileCode,\n css: FileCode,\n xml: FileCode,\n yaml: FileCode,\n yml: FileCode,\n mp3: FileAudio,\n wav: FileAudio,\n flac: FileAudio,\n ogg: FileAudio,\n mp4: FileVideo,\n mov: FileVideo,\n avi: FileVideo,\n webm: FileVideo,\n}\n\nconst MIME_FALLBACK_ICONS: Record<string, LucideIcon> = {\n audio: FileAudio,\n video: FileVideo,\n text: FileText,\n application: FileText,\n}\n\nfunction resolveAttachmentPlaceholder(mimeType?: string | null, fileName?: string | null): { icon: LucideIcon; label: string } {\n const extension = resolveFileExtension(fileName)\n const normalizedMime = typeof mimeType === 'string' ? mimeType.toLowerCase() : ''\n if (extension && EXTENSION_ICON_MAP[extension]) {\n return { icon: EXTENSION_ICON_MAP[extension], label: extension.toUpperCase() }\n }\n if (!extension && normalizedMime.includes('pdf')) {\n return { icon: FileText, label: 'PDF' }\n }\n if (!extension && normalizedMime.includes('zip')) {\n return { icon: FileArchive, label: 'ZIP' }\n }\n if (!extension && normalizedMime.includes('json')) {\n return { icon: FileCode, label: 'JSON' }\n }\n const mimeRoot = normalizedMime.split('/')[0] || ''\n if (mimeRoot && MIME_FALLBACK_ICONS[mimeRoot]) {\n return { icon: MIME_FALLBACK_ICONS[mimeRoot], label: mimeRoot.toUpperCase() }\n }\n const fallbackSource = extension || mimeRoot || 'file'\n const fallbackLabel = fallbackSource.slice(0, 6).toUpperCase()\n return { icon: File, label: fallbackLabel }\n}\n\nfunction normalizeCustomFieldSubmitValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.filter((entry) => entry !== undefined)\n }\n if (value === undefined) return null\n return value\n}\n\n\ntype AttachmentUploadFormValues = {\n files: File[]\n partitionCode?: string\n tags?: string[]\n assignments?: AssignmentDraft[]\n} & Record<string, unknown>\n\ntype AssignmentsEditorProps = {\n value: AssignmentDraft[]\n onChange: (next: AssignmentDraft[]) => void\n labels: {\n title: string\n description: string\n type: string\n id: string\n href: string\n label?: string\n add: string\n remove: string\n }\n disabled?: boolean\n}\n\nfunction AttachmentAssignmentsEditor({ value, onChange, labels, disabled }: AssignmentsEditorProps) {\n const handleChange = React.useCallback(\n (index: number, patch: Partial<AssignmentDraft>) => {\n onChange(value.map((entry, idx) => (idx === index ? { ...entry, ...patch } : entry)))\n },\n [onChange, value],\n )\n\n const handleRemove = React.useCallback(\n (index: number) => {\n onChange(value.filter((_, idx) => idx !== index))\n },\n [onChange, value],\n )\n\n const handleAdd = React.useCallback(() => {\n onChange([...value, { type: '', id: '', href: '', label: '' }])\n }, [onChange, value])\n\n return (\n <div className=\"space-y-2\">\n <div>\n <div className=\"text-sm font-medium\">{labels.title}</div>\n <div className=\"text-xs text-muted-foreground\">{labels.description}</div>\n </div>\n <div className=\"space-y-3\">\n {value.length === 0 ? (\n <div className=\"text-xs text-muted-foreground\">No assignments yet.</div>\n ) : (\n value.map((entry, index) => (\n <div key={`${index}-${entry.type}-${entry.id}`} className=\"rounded border p-3 space-y-2\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.type}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.type}\n disabled={disabled}\n onChange={(event) => handleChange(index, { type: event.target.value })}\n />\n </div>\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.id}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.id}\n disabled={disabled}\n onChange={(event) => handleChange(index, { id: event.target.value })}\n />\n </div>\n </div>\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.href}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.href ?? ''}\n disabled={disabled}\n onChange={(event) => handleChange(index, { href: event.target.value })}\n />\n </div>\n {labels.label ? (\n <div className=\"space-y-1\">\n <label className=\"text-xs font-medium\">{labels.label}</label>\n <input\n className=\"w-full rounded border px-2 py-1 text-sm\"\n value={entry.label ?? ''}\n disabled={disabled}\n onChange={(event) => handleChange(index, { label: event.target.value })}\n />\n </div>\n ) : null}\n </div>\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => handleRemove(index)}\n className=\"inline-flex items-center gap-1 text-muted-foreground\"\n >\n <Trash2 className=\"h-4 w-4\" />\n {labels.remove}\n </Button>\n </div>\n </div>\n ))\n )}\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" disabled={disabled} onClick={handleAdd} className=\"inline-flex items-center gap-1\">\n <Plus className=\"h-4 w-4\" />\n {labels.add}\n </Button>\n </div>\n )\n}\n\ntype AttachmentFilesFieldProps = CrudCustomFieldRenderProps & {\n labels: {\n dropHint: string\n choose: string\n uploading: string\n empty: string\n }\n uploading: boolean\n}\n\nfunction AttachmentFilesField({\n value,\n setValue,\n disabled,\n error,\n labels,\n uploading,\n}: AttachmentFilesFieldProps) {\n const files = React.useMemo(() => (Array.isArray(value) ? (value as File[]) : []), [value])\n const [isDragOver, setDragOver] = React.useState(false)\n const fileInputRef = React.useRef<HTMLInputElement | null>(null)\n\n const acceptFiles = React.useCallback(\n (list: FileList | null) => {\n if (!list?.length) return\n const dedupe = new Map<string, File>(files.map((file) => [`${file.name}:${file.size}`, file]))\n Array.from(list).forEach((file) => {\n dedupe.set(`${file.name}:${file.size}`, file)\n })\n setValue(Array.from(dedupe.values()))\n },\n [files, setValue],\n )\n\n const handleDrop = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n if (disabled || uploading) return\n event.preventDefault()\n event.stopPropagation()\n setDragOver(false)\n acceptFiles(event.dataTransfer?.files ?? null)\n },\n [acceptFiles, disabled, uploading],\n )\n\n const handleDragOver = React.useCallback(\n (event: React.DragEvent<HTMLDivElement>) => {\n if (disabled || uploading) return\n event.preventDefault()\n event.stopPropagation()\n setDragOver(true)\n },\n [disabled, uploading],\n )\n\n const handleDragLeave = React.useCallback((event: React.DragEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.stopPropagation()\n setDragOver(false)\n }, [])\n\n const removeFile = React.useCallback(\n (name: string, size: number) => {\n if (disabled || uploading) return\n setValue(files.filter((file) => !(file.name === name && file.size === size)))\n },\n [disabled, files, setValue, uploading],\n )\n\n const pickFiles = React.useCallback(() => {\n if (disabled || uploading) return\n fileInputRef.current?.click()\n }, [disabled, uploading])\n\n const renderFileList = () => {\n if (!files.length) {\n return <p className=\"text-xs text-muted-foreground\">{labels.empty}</p>\n }\n return (\n <div className=\"space-y-2\">\n {files.map((candidate) => (\n <div key={`${candidate.name}-${candidate.size}`} className=\"flex items-center justify-between rounded border px-3 py-2 text-sm\">\n <div>\n <div className=\"font-medium\">{candidate.name}</div>\n <div className=\"text-xs text-muted-foreground\">{formatFileSize(candidate.size)}</div>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => removeFile(candidate.name, candidate.size)}\n disabled={disabled || uploading}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n <div\n className={cn(\n 'flex flex-col items-center justify-center rounded-lg border border-dashed p-6 text-center transition-colors',\n isDragOver ? 'border-primary bg-primary/5' : 'border-muted-foreground/30',\n disabled || uploading ? 'opacity-70' : '',\n )}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n role=\"presentation\"\n >\n <Upload className=\"mx-auto h-6 w-6 text-muted-foreground\" />\n <p className=\"mt-2 text-sm text-muted-foreground\">{labels.dropHint}</p>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"mt-4\" onClick={pickFiles} disabled={disabled || uploading}>\n {uploading ? labels.uploading : labels.choose}\n </Button>\n <input\n ref={fileInputRef}\n type=\"file\"\n className=\"hidden\"\n multiple\n onChange={(event) => {\n acceptFiles(event.target.files)\n event.currentTarget.value = ''\n }}\n disabled={disabled || uploading}\n />\n </div>\n {renderFileList()}\n {error ? <p className=\"text-xs font-medium text-red-600\">{error}</p> : null}\n </div>\n )\n}\n\ntype AttachmentUploadFormProps = {\n partitions: Array<{ code: string; title: string }>\n availableTags: string[]\n onUploaded: () => void\n onCancel: () => void\n}\n\nfunction AttachmentUploadForm({ partitions, availableTags, onUploaded, onCancel }: AttachmentUploadFormProps) {\n const t = useT()\n const [isUploading, setIsUploading] = React.useState(false)\n const [uploadProgress, setUploadProgress] = React.useState<{ completed: number; total: number }>({ completed: 0, total: 0 })\n\n const partitionOptions = React.useMemo(\n () =>\n partitions.map((entry) => ({\n value: entry.code,\n label: entry.title || entry.code,\n })),\n [partitions],\n )\n\n const assignmentLabels = React.useMemo(\n () => ({\n title: t('attachments.library.upload.assignments.title', 'Assignments'),\n description: t(\n 'attachments.library.upload.assignments.description',\n 'Optionally link this file to existing records now or add them later.',\n ),\n type: t('attachments.library.upload.assignments.type', 'Type'),\n id: t('attachments.library.upload.assignments.id', 'Record ID'),\n href: t('attachments.library.upload.assignments.href', 'Link'),\n label: t('attachments.library.upload.assignments.label', 'Label'),\n add: t('attachments.library.upload.assignments.add', 'Add assignment'),\n remove: t('attachments.library.upload.assignments.remove', 'Remove'),\n }),\n [t],\n )\n\n const formSchema = React.useMemo(\n () =>\n z\n .object({\n files: z.array(z.any()).min(1, { message: t('attachments.library.upload.fileRequired', 'Select at least one file to upload.') }),\n partitionCode: z.string().optional(),\n tags: z.array(z.string()).optional(),\n assignments: z\n .array(\n z.object({\n type: z.string().min(1),\n id: z.string().min(1),\n href: z.string().optional(),\n label: z.string().optional(),\n }),\n )\n .optional(),\n })\n .passthrough(),\n [t],\n )\n\n const fields = React.useMemo<CrudField[]>(() => {\n return [\n {\n id: 'files',\n label: t('attachments.library.upload.file', 'Files'),\n type: 'custom',\n component: (props) => (\n <AttachmentFilesField\n {...props}\n uploading={isUploading}\n labels={{\n dropHint: t('attachments.library.upload.dropHint', 'Drag and drop files here or click to upload.'),\n choose: t('attachments.library.upload.choose', 'Choose files'),\n uploading: t('attachments.library.upload.submitting', 'Uploading\u2026'),\n empty: t('attachments.library.upload.noFiles', 'No files selected yet.'),\n }}\n />\n ),\n },\n {\n id: 'partitionCode',\n label: t('attachments.library.upload.partition', 'Partition'),\n type: 'select',\n options: [\n { value: '', label: t('attachments.library.upload.partitionDefault', 'Default (private)') },\n ...partitionOptions,\n ],\n },\n {\n id: 'tags',\n label: t('attachments.library.table.tags', 'Tags'),\n type: 'custom',\n component: ({ value, setValue, disabled }) => (\n <TagsInput\n value={Array.isArray(value) ? (value as string[]) : []}\n onChange={(next) => setValue(next)}\n suggestions={availableTags}\n placeholder={t('attachments.library.upload.tagsPlaceholder', 'Add tags')}\n disabled={Boolean(disabled) || isUploading}\n />\n ),\n },\n {\n id: 'assignments',\n label: '',\n type: 'custom',\n component: ({ value, setValue, disabled }) => (\n <AttachmentAssignmentsEditor\n value={Array.isArray(value) ? (value as AssignmentDraft[]) : []}\n onChange={(next) => setValue(next)}\n labels={assignmentLabels}\n disabled={Boolean(disabled) || isUploading}\n />\n ),\n },\n ]\n }, [assignmentLabels, availableTags, isUploading, partitionOptions, t])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => {\n return [\n {\n id: 'details',\n title: t('attachments.library.upload.title', 'Upload attachment'),\n column: 1,\n fields: ['files', 'partitionCode', 'tags', 'assignments'],\n },\n {\n id: 'customFields',\n title: t('entities.customFields.title', 'Custom attributes'),\n column: 2,\n kind: 'customFields',\n },\n ]\n }, [t])\n\n const uploadPercentage = uploadProgress.total\n ? Math.min(100, Math.round((uploadProgress.completed / uploadProgress.total) * 100))\n : 0\n\n const handleSubmit = React.useCallback(\n async (values: AttachmentUploadFormValues) => {\n const files = Array.isArray(values.files) ? values.files : []\n if (!files.length) {\n throw new Error(t('attachments.library.upload.fileRequired', 'Select at least one file to upload.'))\n }\n setUploadProgress({ completed: 0, total: files.length })\n setIsUploading(true)\n try {\n const tags = Array.isArray(values.tags)\n ? values.tags\n .map((tag) => (typeof tag === 'string' ? tag.trim() : ''))\n .filter((tag) => tag.length > 0)\n : []\n const cleanedAssignments =\n Array.isArray(values.assignments) && values.assignments.length\n ? values.assignments\n .map((assignment) => ({\n type: assignment.type?.trim() ?? '',\n id: assignment.id?.trim() ?? '',\n href: assignment.href?.trim() || undefined,\n label: assignment.label?.trim() || undefined,\n }))\n .filter((assignment) => assignment.type && assignment.id)\n : []\n const customFields = collectCustomFieldValues(values, {\n transform: (value) => normalizeCustomFieldSubmitValue(value),\n })\n let completed = 0\n for (const file of files) {\n const fd = new FormData()\n fd.set('entityId', LIBRARY_ENTITY_ID)\n fd.set(\n 'recordId',\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function' ? crypto.randomUUID() : String(Date.now()),\n )\n fd.set('file', file)\n if (typeof values.partitionCode === 'string' && values.partitionCode.trim().length) {\n fd.set('partitionCode', values.partitionCode.trim())\n }\n if (tags.length) fd.set('tags', JSON.stringify(tags))\n if (cleanedAssignments.length) fd.set('assignments', JSON.stringify(cleanedAssignments))\n if (Object.keys(customFields).length) fd.set('customFields', JSON.stringify(customFields))\n const call = await apiCall<{ error?: string }>('/api/attachments', {\n method: 'POST',\n body: fd,\n })\n if (!call.ok) {\n const message = call.result?.error || t('attachments.library.upload.failed', 'Upload failed.')\n throw new Error(message)\n }\n completed += 1\n setUploadProgress({ completed, total: files.length })\n }\n flash(t('attachments.library.upload.success', 'Attachment uploaded.'), 'success')\n onUploaded()\n onCancel()\n } catch (err: any) {\n const message = err?.message || t('attachments.library.upload.failed', 'Upload failed.')\n flash(message, 'error')\n throw new Error(message)\n } finally {\n setIsUploading(false)\n }\n },\n [onCancel, onUploaded, t],\n )\n\n return (\n <div className=\"relative\">\n <CrudForm<AttachmentUploadFormValues>\n embedded\n schema={formSchema}\n entityId={E.attachments.attachment}\n fields={fields}\n groups={groups}\n initialValues={{ files: [], tags: [], assignments: [], partitionCode: '' }}\n submitLabel={\n isUploading\n ? t('attachments.library.upload.submitting', 'Uploading\u2026')\n : t('attachments.library.upload.submit', 'Upload')\n }\n extraActions={\n <Button type=\"button\" variant=\"outline\" onClick={onCancel} disabled={isUploading}>\n {t('attachments.library.upload.cancel', 'Cancel')}\n </Button>\n }\n onSubmit={handleSubmit}\n />\n {isUploading ? (\n <div className=\"pointer-events-none absolute inset-0 z-20 flex items-center justify-center bg-background/90 px-6 text-center backdrop-blur\">\n <div className=\"flex w-full max-w-sm flex-col items-center gap-4 rounded-xl border border-border/50 bg-card/95 px-6 py-8 shadow-2xl\">\n <Spinner size=\"lg\" className=\"border-primary/50 border-t-primary\" />\n <div className=\"w-full space-y-3\">\n <p className=\"text-base font-semibold\">\n {t('attachments.library.upload.progressLabel', 'Uploading files')}\n </p>\n {uploadProgress.total > 0 ? (\n <>\n <p className=\"text-sm text-muted-foreground\">\n {uploadProgress.completed}/{uploadProgress.total}\n </p>\n <div className=\"h-2 w-full rounded bg-muted\">\n <div\n className=\"h-2 rounded bg-primary transition-all\"\n style={{\n width: `${uploadPercentage}%`,\n }}\n />\n </div>\n </>\n ) : null}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n )\n}\ntype UploadDialogProps = {\n open: boolean\n onOpenChange: (next: boolean) => void\n partitions: Array<{ code: string; title: string }>\n availableTags: string[]\n onUploaded: () => void\n}\n\nfunction AttachmentUploadDialog({ open, onOpenChange, partitions, availableTags, onUploaded }: UploadDialogProps) {\n const t = useT()\n const [formResetKey, setFormResetKey] = React.useState(0)\n const previousOpen = React.useRef(open)\n\n React.useEffect(() => {\n if (previousOpen.current && !open) {\n setFormResetKey((prev) => prev + 1)\n }\n previousOpen.current = open\n }, [open])\n\n const handleDialogChange = React.useCallback(\n (next: boolean) => {\n onOpenChange(next)\n },\n [onOpenChange],\n )\n\n const handleUploaded = React.useCallback(() => {\n onUploaded()\n }, [onUploaded])\n\n return (\n <Dialog open={open} onOpenChange={handleDialogChange}>\n <DialogContent className=\"sm:max-w-[54.6rem]\">\n <DialogHeader>\n <DialogTitle>{t('attachments.library.upload.title', 'Upload attachment')}</DialogTitle>\n </DialogHeader>\n <AttachmentUploadForm\n key={formResetKey}\n partitions={partitions}\n availableTags={availableTags}\n onUploaded={handleUploaded}\n onCancel={() => handleDialogChange(false)}\n />\n </DialogContent>\n </Dialog>\n )\n}\n\nexport function AttachmentLibrary() {\n const t = useT()\n const queryClient = useQueryClient()\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'createdAt', desc: true }])\n const [metadataDialogOpen, setMetadataDialogOpen] = React.useState(false)\n const [selectedRow, setSelectedRow] = React.useState<AttachmentRow | null>(null)\n const [uploadDialogOpen, setUploadDialogOpen] = React.useState(false)\n const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false)\n const [deleteTarget, setDeleteTarget] = React.useState<AttachmentRow | null>(null)\n const [deletePending, setDeletePending] = React.useState(false)\n const filterSignature = React.useMemo(() => buildFilterSignature(filterValues), [filterValues])\n const sortingSignature = React.useMemo(() => JSON.stringify(sorting), [sorting])\n\n const { data, isLoading, error, refetch } = useQuery({\n queryKey: ['attachments-library', page, search, filterSignature, sortingSignature],\n queryFn: async () => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n if (search.trim().length > 0) params.set('search', search.trim())\n const partition = typeof filterValues.partition === 'string' ? filterValues.partition : ''\n if (partition) params.set('partition', partition)\n const tags = Array.isArray(filterValues.tags) ? filterValues.tags : []\n if (tags.length > 0) params.set('tags', tags.join(','))\n if (sorting.length > 0) {\n const primary = sorting[0]\n params.set('sortField', primary.id)\n params.set('sortDir', primary.desc ? 'desc' : 'asc')\n }\n const call = await apiCall<AttachmentLibraryResponse>(`/api/attachments/library?${params.toString()}`)\n if (!call.ok || !call.result) {\n const message = call.result?.error || t('attachments.library.errors.load', 'Failed to load attachments.')\n throw new Error(message)\n }\n return call.result\n },\n })\n\n const partitions = data?.partitions ?? []\n const availableTags = data?.availableTags ?? []\n\n const filters = React.useMemo<FilterDef[]>(() => {\n const partitionOptions = partitions.map((entry) => ({\n value: entry.code,\n label: entry.title || entry.code,\n }))\n return [\n {\n id: 'partition',\n label: t('attachments.library.filters.partition', 'Partition'),\n type: 'select',\n options: partitionOptions,\n },\n {\n id: 'tags',\n label: t('attachments.library.filters.tags', 'Tags'),\n type: 'tags',\n placeholder: t('attachments.library.filters.tagsPlaceholder', 'Filter by tag'),\n options: availableTags.map((tag) => ({ value: tag, label: tag })),\n },\n ]\n }, [availableTags, partitions, t])\n\n const items = data?.items ?? []\n\n const columns = React.useMemo<ColumnDef<AttachmentRow>[]>(() => {\n return [\n {\n id: 'preview',\n header: '',\n enableSorting: false,\n cell: ({ row }) => {\n const value = row.original\n if (value.thumbnailUrl) {\n return (\n <div className=\"h-16 w-16 overflow-hidden rounded border bg-muted\">\n <img\n src={value.thumbnailUrl}\n alt={value.fileName}\n className=\"h-full w-full object-cover\"\n loading=\"lazy\"\n />\n </div>\n )\n }\n const placeholder = resolveAttachmentPlaceholder(value.mimeType, value.fileName)\n const PlaceholderIcon = placeholder.icon\n return (\n <div className=\"flex h-16 w-16 flex-col items-center justify-center rounded border bg-muted text-[10px] font-semibold uppercase text-muted-foreground\">\n <PlaceholderIcon className=\"mb-1 h-5 w-5 text-muted-foreground\" aria-hidden />\n {placeholder.label}\n </div>\n )\n },\n },\n {\n id: 'fileName',\n accessorKey: 'fileName',\n header: t('attachments.library.table.file', 'File'),\n cell: ({ row }) => {\n const value = row.original\n return (\n <div className=\"space-y-1 min-w-0 max-w-[280px]\">\n <div className=\"font-medium truncate\" title={value.fileName}>\n {value.fileName}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {formatFileSize(value.fileSize)} \u2022 {value.mimeType || 'application/octet-stream'}\n </div>\n <div className=\"text-xs text-muted-foreground line-clamp-2\">\n {value.content?.trim()\n ? value.content\n : t('attachments.library.metadata.noContent', 'No text extracted')}\n </div>\n </div>\n )\n },\n },\n {\n id: 'tags',\n accessorKey: 'tags',\n header: t('attachments.library.table.tags', 'Tags'),\n enableSorting: false,\n cell: ({ row }) => {\n const tags = row.original.tags ?? []\n if (!tags.length) return <span className=\"text-xs text-muted-foreground\">\u2014</span>\n return (\n <div className=\"flex flex-wrap gap-1\">\n {tags.map((tag) => (\n <Badge key={tag} variant=\"outline\">\n {tag}\n </Badge>\n ))}\n </div>\n )\n },\n },\n {\n id: 'assignments',\n accessorKey: 'assignments',\n header: t('attachments.library.table.assignments', 'Assignments'),\n enableSorting: false,\n cell: ({ row }) => {\n const assignments = filterLibraryAssignments(row.original.assignments)\n if (!assignments.length) return <span className=\"text-xs text-muted-foreground\">\u2014</span>\n return (\n <div className=\"flex flex-col gap-1\">\n {assignments.map((assignment) => {\n const label = assignment.label?.trim() || assignment.id\n const hideType =\n assignment.type === (E as any).catalog?.catalog_product ||\n assignment.type === (E as any).catalog?.catalog_product_variant\n const content = hideType ? label : `${assignment.type}: ${label}`\n return assignment.href ? (\n <a\n key={`${assignment.type}-${assignment.id}-${assignment.href}`}\n href={assignment.href}\n className=\"text-sm text-blue-600 underline\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {content}\n </a>\n ) : (\n <div key={`${assignment.type}-${assignment.id}`} className=\"text-sm\">\n {content}\n </div>\n )\n })}\n </div>\n )\n },\n },\n {\n id: 'partitionCode',\n accessorKey: 'partitionCode',\n header: t('attachments.library.table.partition', 'Partition'),\n cell: ({ row }) => (\n <div className=\"text-sm text-muted-foreground\">\n {row.original.partitionTitle ?? row.original.partitionCode}\n </div>\n ),\n },\n {\n id: 'createdAt',\n accessorKey: 'createdAt',\n header: t('attachments.library.table.created', 'Created'),\n cell: ({ row }) => {\n const createdAt = row.original.createdAt\n return (\n <div className=\"text-sm text-muted-foreground\">\n {createdAt ? humanDate(createdAt) : '\u2014'}\n </div>\n )\n },\n },\n {\n id: 'download',\n header: t('attachments.library.table.download', 'Download'),\n enableSorting: false,\n cell: ({ row }) => {\n const downloadPath = buildAttachmentFileUrl(row.original.id, { download: true })\n const absolute = resolveAbsoluteUrl(downloadPath)\n return (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a href={absolute} download aria-label={t('attachments.library.table.download', 'Download')}>\n <Download className=\"h-4 w-4\" />\n </a>\n </Button>\n )\n },\n },\n ]\n }, [t])\n\n const openMetadataDialog = React.useCallback((row: AttachmentRow) => {\n setSelectedRow(row)\n setMetadataDialogOpen(true)\n }, [])\n\n const openDeleteDialog = React.useCallback((row: AttachmentRow) => {\n setDeleteTarget(row)\n setDeleteDialogOpen(true)\n }, [])\n\n const handleMetadataSave = React.useCallback(\n async (id: string, payload: AttachmentMetadataSavePayload) => {\n try {\n const body: Record<string, unknown> = {\n tags: payload.tags,\n assignments: payload.assignments,\n }\n if (payload.customFields && Object.keys(payload.customFields).length) {\n body.customFields = payload.customFields\n }\n const call = await apiCall<{ error?: string }>(`/api/attachments/library/${encodeURIComponent(id)}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!call.ok) {\n const message =\n call.result?.error || t('attachments.library.metadata.error', 'Failed to update metadata.')\n flash(message, 'error')\n return\n }\n flash(t('attachments.library.metadata.success', 'Attachment updated.'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n setMetadataDialogOpen(false)\n } catch (err: any) {\n flash(err?.message || t('attachments.library.metadata.error', 'Failed to update metadata.'), 'error')\n }\n },\n [queryClient, t],\n )\n\n const handleUploadCompleted = React.useCallback(async () => {\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n }, [queryClient])\n\n const handleDelete = React.useCallback(async () => {\n if (!deleteTarget) return\n try {\n setDeletePending(true)\n const call = await apiCall<{ error?: string }>(\n `/api/attachments/library/${encodeURIComponent(deleteTarget.id)}`,\n { method: 'DELETE' },\n )\n if (!call.ok) {\n const message =\n call.result?.error || t('attachments.library.errors.delete', 'Failed to delete attachment.')\n flash(message, 'error')\n return\n }\n flash(t('attachments.library.messages.deleted', 'Attachment removed.'), 'success')\n if (selectedRow?.id === deleteTarget.id) {\n setSelectedRow(null)\n setMetadataDialogOpen(false)\n }\n setDeleteDialogOpen(false)\n setDeleteTarget(null)\n await queryClient.invalidateQueries({ queryKey: ['attachments-library'], exact: false })\n } catch (err: any) {\n flash(err?.message || t('attachments.library.errors.delete', 'Failed to delete attachment.'), 'error')\n } finally {\n setDeletePending(false)\n }\n }, [deleteTarget, queryClient, selectedRow, t])\n\n const total = data?.total ?? 0\n const totalPages = data?.totalPages ?? 1\n return (\n <>\n <DataTable<AttachmentRow>\n title={t('attachments.library.title', 'Attachments')}\n refreshButton={{\n label: t('attachments.library.actions.refresh', 'Refresh'),\n onRefresh: () => { void refetch() },\n isRefreshing: isLoading,\n }}\n actions={(\n <Button onClick={() => setUploadDialogOpen(true)}>\n {t('attachments.library.actions.upload', 'Upload')}\n </Button>\n )}\n columns={columns}\n data={items}\n sorting={sorting}\n onSortingChange={setSorting}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n label: t('attachments.library.actions.open', 'Open'),\n onSelect: () => {\n if (!row.url) return\n window.open(row.url, '_blank', 'noopener,noreferrer')\n },\n },\n {\n label: t('attachments.library.actions.edit', 'Edit metadata'),\n onSelect: () => openMetadataDialog(row),\n },\n {\n label: t('attachments.library.actions.copyUrl', 'Copy URL'),\n onSelect: () => {\n if (!row.url) {\n flash(t('attachments.library.actions.copyError', 'Unable to copy link.'), 'error')\n return\n }\n const absolute = resolveAbsoluteUrl(row.url)\n navigator.clipboard\n .writeText(absolute)\n .then(() =>\n flash(\n t('attachments.library.actions.copied', 'Link copied.'),\n 'success',\n ),\n )\n .catch(() =>\n flash(\n t('attachments.library.actions.copyError', 'Unable to copy link.'),\n 'error',\n ),\n )\n },\n },\n {\n label: t('attachments.library.actions.delete', 'Delete'),\n destructive: true,\n onSelect: () => openDeleteDialog(row),\n },\n ]}\n />\n )}\n onRowClick={(row) => openMetadataDialog(row)}\n isLoading={isLoading}\n error={error?.message}\n emptyState={\n <div className=\"py-10 text-center text-sm text-muted-foreground\">\n {t('attachments.library.table.empty', 'No attachments found.')}\n </div>\n }\n searchValue={search}\n onSearchChange={(value) => {\n setPage(1)\n setSearch(value)\n }}\n searchPlaceholder={t('attachments.library.table.search', 'Search files\u2026')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(values) => {\n setFilterValues(values)\n setPage(1)\n }}\n onFiltersClear={() => {\n setFilterValues({})\n setPage(1)\n }}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: (next) => setPage(next),\n }}\n />\n <AttachmentMetadataDialog\n open={metadataDialogOpen}\n onOpenChange={setMetadataDialogOpen}\n item={selectedRow}\n availableTags={availableTags}\n onSave={handleMetadataSave}\n />\n <AttachmentDeleteDialog\n open={deleteDialogOpen}\n onOpenChange={setDeleteDialogOpen}\n fileName={deleteTarget?.fileName}\n onConfirm={handleDelete}\n isDeleting={deletePending}\n />\n <AttachmentUploadDialog\n open={uploadDialogOpen}\n onOpenChange={setUploadDialogOpen}\n partitions={partitions}\n availableTags={availableTags}\n onUploaded={handleUploadCompleted}\n />\n </>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,12 +4,15 @@ let _entityLinkSpecsCache = null;
4
4
  function getEntityLinkSpecs() {
5
5
  if (_entityLinkSpecsCache) return _entityLinkSpecsCache;
6
6
  const E = getEntityIds();
7
- _entityLinkSpecsCache = {
8
- [E.catalog.catalog_product]: {
7
+ const specs = {};
8
+ if (E.catalog?.catalog_product) {
9
+ specs[E.catalog.catalog_product] = {
9
10
  labelFields: ["title", "sku", "handle"],
10
11
  buildHref: (record) => buildSimpleHref("/backend/catalog/products", record.id)
11
- },
12
- [E.catalog.catalog_product_variant]: {
12
+ };
13
+ }
14
+ if (E.catalog?.catalog_product_variant) {
15
+ specs[E.catalog.catalog_product_variant] = {
13
16
  labelFields: ["name", "sku"],
14
17
  extraFields: ["product_id"],
15
18
  buildHref: (record) => {
@@ -17,8 +20,10 @@ function getEntityLinkSpecs() {
17
20
  if (!productId) return null;
18
21
  return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ""))}`;
19
22
  }
20
- },
21
- [E.customers.customer_entity]: {
23
+ };
24
+ }
25
+ if (E.customers?.customer_entity) {
26
+ specs[E.customers.customer_entity] = {
22
27
  labelFields: ["display_name"],
23
28
  extraFields: ["kind"],
24
29
  buildHref: (record) => {
@@ -27,32 +32,41 @@ function getEntityLinkSpecs() {
27
32
  if (kind === "person") return buildSimpleHref("/backend/customers/people", record.id);
28
33
  return null;
29
34
  }
30
- },
31
- [E.customers.customer_person_profile]: {
35
+ };
36
+ }
37
+ if (E.customers?.customer_person_profile) {
38
+ specs[E.customers.customer_person_profile] = {
32
39
  labelFields: ["preferred_name", "display_name", "first_name", "last_name"],
33
40
  extraFields: ["entity_id", "first_name", "last_name"],
34
41
  buildHref: (record) => {
35
42
  const entityId = readRecordValue(record, "entity_id");
36
43
  return entityId ? buildSimpleHref("/backend/customers/people", entityId) : null;
37
44
  }
38
- },
39
- [E.customers.customer_company_profile]: {
45
+ };
46
+ }
47
+ if (E.customers?.customer_company_profile) {
48
+ specs[E.customers.customer_company_profile] = {
40
49
  labelFields: ["brand_name", "display_name", "legal_name"],
41
50
  extraFields: ["entity_id"],
42
51
  buildHref: (record) => {
43
52
  const entityId = readRecordValue(record, "entity_id");
44
53
  return entityId ? buildSimpleHref("/backend/customers/companies", entityId) : null;
45
54
  }
46
- },
47
- [E.customers.customer_deal]: {
55
+ };
56
+ }
57
+ if (E.customers?.customer_deal) {
58
+ specs[E.customers.customer_deal] = {
48
59
  labelFields: ["title"],
49
60
  buildHref: (record) => buildSimpleHref("/backend/customers/deals", record.id)
50
- },
51
- [E.sales.sales_channel]: {
61
+ };
62
+ }
63
+ if (E.sales?.sales_channel) {
64
+ specs[E.sales.sales_channel] = {
52
65
  labelFields: ["name", "title"],
53
66
  buildHref: (record) => buildSimpleHref("/backend/sales/channels", record.id, "/edit")
54
- }
55
- };
67
+ };
68
+ }
69
+ _entityLinkSpecsCache = specs;
56
70
  return _entityLinkSpecsCache;
57
71
  }
58
72
  const LIBRARY_ENTITY_ID = "attachments:library";
@@ -128,7 +142,7 @@ function isUuid(value) {
128
142
  }
129
143
  function filterIdsForEntity(entityId, ids) {
130
144
  const E = getEntityIds();
131
- if (entityId === E.catalog.catalog_product_variant || entityId === E.catalog.catalog_product) {
145
+ if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {
132
146
  return ids.filter((id) => isUuid(id));
133
147
  }
134
148
  return ids;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/assignmentDetails.ts"],
4
- "sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n _entityLinkSpecsCache = {\n [E.catalog.catalog_product]: {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n },\n [E.catalog.catalog_product_variant]: {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n },\n [E.customers.customer_entity]: {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n },\n [E.customers.customer_person_profile]: {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n },\n [E.customers.customer_company_profile]: {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n },\n [E.customers.customer_deal]: {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n },\n [E.sales.sales_channel]: {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n },\n }\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog.catalog_product_variant || entityId === E.catalog.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n console.warn('[attachments] Failed to resolve assignment details for', entityId, error)\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { AttachmentAssignment } from './metadata'\nimport type { CustomEntitySpec } from '@open-mercato/shared/modules/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\n\ntype AssignmentLinkSpec = {\n labelFields?: string[]\n extraFields?: string[]\n buildHref?: (record: Record<string, unknown>) => string | null | undefined\n}\n\nlet _entityLinkSpecsCache: Record<string, AssignmentLinkSpec> | null = null\n\nfunction getEntityLinkSpecs(): Record<string, AssignmentLinkSpec> {\n if (_entityLinkSpecsCache) return _entityLinkSpecsCache\n const E = getEntityIds() as any\n const specs: Record<string, AssignmentLinkSpec> = {}\n\n if (E.catalog?.catalog_product) {\n specs[E.catalog.catalog_product] = {\n labelFields: ['title', 'sku', 'handle'],\n buildHref: (record) => buildSimpleHref('/backend/catalog/products', record.id),\n }\n }\n if (E.catalog?.catalog_product_variant) {\n specs[E.catalog.catalog_product_variant] = {\n labelFields: ['name', 'sku'],\n extraFields: ['product_id'],\n buildHref: (record) => {\n const productId = readRecordValue(record, 'product_id')\n if (!productId) return null\n return `/backend/catalog/products/${encodeURIComponent(productId)}/variants/${encodeURIComponent(String(record.id ?? ''))}`\n },\n }\n }\n if (E.customers?.customer_entity) {\n specs[E.customers.customer_entity] = {\n labelFields: ['display_name'],\n extraFields: ['kind'],\n buildHref: (record) => {\n const kind = String(readRecordValue(record, 'kind') || '').toLowerCase()\n if (kind === 'company') return buildSimpleHref('/backend/customers/companies', record.id)\n if (kind === 'person') return buildSimpleHref('/backend/customers/people', record.id)\n return null\n },\n }\n }\n if (E.customers?.customer_person_profile) {\n specs[E.customers.customer_person_profile] = {\n labelFields: ['preferred_name', 'display_name', 'first_name', 'last_name'],\n extraFields: ['entity_id', 'first_name', 'last_name'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/people', entityId) : null\n },\n }\n }\n if (E.customers?.customer_company_profile) {\n specs[E.customers.customer_company_profile] = {\n labelFields: ['brand_name', 'display_name', 'legal_name'],\n extraFields: ['entity_id'],\n buildHref: (record) => {\n const entityId = readRecordValue(record, 'entity_id')\n return entityId ? buildSimpleHref('/backend/customers/companies', entityId) : null\n },\n }\n }\n if (E.customers?.customer_deal) {\n specs[E.customers.customer_deal] = {\n labelFields: ['title'],\n buildHref: (record) => buildSimpleHref('/backend/customers/deals', record.id),\n }\n }\n if (E.sales?.sales_channel) {\n specs[E.sales.sales_channel] = {\n labelFields: ['name', 'title'],\n buildHref: (record) => buildSimpleHref('/backend/sales/channels', record.id, '/edit'),\n }\n }\n\n _entityLinkSpecsCache = specs\n return _entityLinkSpecsCache\n}\n\nconst LIBRARY_ENTITY_ID = 'attachments:library'\nconst DEFAULT_LABEL_FIELDS = [\n 'label',\n 'title',\n 'name',\n 'display_name',\n 'displayName',\n 'subject',\n 'sku',\n 'handle',\n 'order_number',\n 'quote_number',\n 'invoice_number',\n 'email',\n 'company_name',\n 'legal_name',\n 'brand_name',\n]\n\nlet entitySpecsPromise: Promise<Map<string, CustomEntitySpec>> | null = null\n\nasync function loadEntitySpecs(): Promise<Map<string, CustomEntitySpec>> {\n if (!entitySpecsPromise) {\n entitySpecsPromise = Promise.resolve()\n .then(() => {\n const map = new Map<string, CustomEntitySpec>()\n const mods = getModules()\n for (const mod of mods) {\n const specs = ((mod as any).customEntities as CustomEntitySpec[] | undefined) ?? []\n for (const spec of specs) {\n if (spec?.id && !map.has(spec.id)) {\n map.set(spec.id, spec)\n }\n }\n }\n return map\n })\n .catch(() => new Map<string, CustomEntitySpec>())\n }\n return entitySpecsPromise\n}\n\nexport type AssignmentEnrichment = {\n label?: string\n href?: string\n}\n\nexport type AssignmentEnrichmentMap = Map<string, AssignmentEnrichment>\n\nfunction camelToSnake(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[\\s-]+/g, '_')\n .toLowerCase()\n}\n\nfunction snakeToCamel(value: string): string {\n return value.replace(/[_-](\\w)/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction normalizeValue(value: unknown): string | null {\n if (value === undefined || value === null) return null\n if (typeof value === 'string') {\n const trimmed = value.trim()\n return trimmed.length ? trimmed : null\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value)\n }\n return null\n}\n\nfunction readRecordValue(record: Record<string, unknown>, field: string): string | null {\n if (!field) return null\n if (record[field] !== undefined) return normalizeValue(record[field])\n const snake = camelToSnake(field)\n if (snake !== field && record[snake] !== undefined) return normalizeValue(record[snake])\n const camel = snakeToCamel(field)\n if (camel !== field && record[camel] !== undefined) return normalizeValue(record[camel])\n return null\n}\n\nfunction buildSimpleHref(base: string, idValue: unknown, suffix: string = ''): string | null {\n const id = normalizeValue(idValue)\n if (!id) return null\n return `${base}/${encodeURIComponent(id)}${suffix}`\n}\n\nfunction isUuid(value: string | null | undefined): boolean {\n return typeof value === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value.trim())\n}\n\nfunction filterIdsForEntity(entityId: string, ids: string[]): string[] {\n const E = getEntityIds() as any\n if (entityId === E.catalog?.catalog_product_variant || entityId === E.catalog?.catalog_product) {\n return ids.filter((id) => isUuid(id))\n }\n return ids\n}\n\nfunction resolveLabelCandidates(entityId: string, linkSpec: AssignmentLinkSpec | undefined, entitySpecs: Map<string, CustomEntitySpec>): string[] {\n const candidates = new Set<string>()\n const spec = entitySpecs.get(entityId)\n if (spec?.labelField) {\n candidates.add(spec.labelField)\n candidates.add(camelToSnake(spec.labelField))\n }\n for (const field of linkSpec?.labelFields ?? []) {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n }\n DEFAULT_LABEL_FIELDS.forEach((field) => {\n candidates.add(field)\n candidates.add(camelToSnake(field))\n })\n return Array.from(candidates).filter((field) => field.length > 0)\n}\n\nfunction buildLabel(\n record: Record<string, unknown>,\n entityId: string,\n linkSpec: AssignmentLinkSpec | undefined,\n entitySpecs: Map<string, CustomEntitySpec>\n): string | null {\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n for (const candidate of candidates) {\n const value = readRecordValue(record, candidate)\n if (value) return value\n }\n const fullName = [readRecordValue(record, 'first_name'), readRecordValue(record, 'last_name')]\n .filter((part): part is string => Boolean(part))\n .join(' ')\n .trim()\n if (fullName.length) return fullName\n return null\n}\n\nexport async function resolveAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n opts: { queryEngine?: QueryEngine | null; tenantId: string; organizationId: string },\n): Promise<AssignmentEnrichmentMap> {\n const map: AssignmentEnrichmentMap = new Map()\n if (!assignments.length || !opts.queryEngine) return map\n const entitySpecs = await loadEntitySpecs()\n const grouped = new Map<string, Set<string>>()\n for (const assignment of assignments) {\n if (!assignment || assignment.type === LIBRARY_ENTITY_ID) continue\n const type = assignment.type?.trim()\n const id = assignment.id?.trim()\n if (!type || !id) continue\n if (!grouped.has(type)) grouped.set(type, new Set())\n grouped.get(type)!.add(id)\n }\n if (!grouped.size) return map\n\n const entityLinkSpecs = getEntityLinkSpecs()\n for (const [entityId, idsSet] of grouped.entries()) {\n const ids = filterIdsForEntity(entityId, Array.from(idsSet.values()))\n if (!ids.length) continue\n const linkSpec = entityLinkSpecs[entityId]\n const fields = new Set<string>(['id'])\n const candidates = resolveLabelCandidates(entityId, linkSpec, entitySpecs)\n candidates.forEach((field) => fields.add(field))\n for (const extra of linkSpec?.extraFields ?? []) {\n fields.add(extra)\n fields.add(camelToSnake(extra))\n }\n try {\n const result = await opts.queryEngine.query(entityId as any, {\n fields: Array.from(fields),\n filters: { id: ids.length === 1 ? { $eq: ids[0] } : { $in: ids } },\n tenantId: opts.tenantId,\n organizationId: opts.organizationId,\n page: { pageSize: Math.max(ids.length, 20) },\n })\n for (const record of result.items ?? []) {\n const recordId = normalizeValue((record as Record<string, unknown>).id)\n if (!recordId) continue\n const label = buildLabel(record as Record<string, unknown>, entityId, linkSpec, entitySpecs)\n const href = linkSpec?.buildHref?.(record as Record<string, unknown>) ?? null\n if (label || href) {\n map.set(`${entityId}:${recordId}`, {\n label: label ?? undefined,\n href: href ?? undefined,\n })\n }\n }\n } catch (error) {\n console.warn('[attachments] Failed to resolve assignment details for', entityId, error)\n }\n }\n return map\n}\n\nexport function applyAssignmentEnrichments(\n assignments: AttachmentAssignment[],\n enrichments: AssignmentEnrichmentMap,\n): AttachmentAssignment[] {\n if (!enrichments.size) return assignments\n return assignments.map((assignment) => {\n if (!assignment || !assignment.type || !assignment.id) return assignment\n const key = `${assignment.type}:${assignment.id}`\n const detail = enrichments.get(key)\n if (!detail) return assignment\n const next: AttachmentAssignment = { ...assignment }\n if (!next.label && detail.label) next.label = detail.label\n if (!next.href && detail.href) next.href = detail.href\n return next\n })\n}\n"],
5
+ "mappings": "AAGA,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAQ3B,IAAI,wBAAmE;AAEvE,SAAS,qBAAyD;AAChE,MAAI,sBAAuB,QAAO;AAClC,QAAM,IAAI,aAAa;AACvB,QAAM,QAA4C,CAAC;AAEnD,MAAI,EAAE,SAAS,iBAAiB;AAC9B,UAAM,EAAE,QAAQ,eAAe,IAAI;AAAA,MACjC,aAAa,CAAC,SAAS,OAAO,QAAQ;AAAA,MACtC,WAAW,CAAC,WAAW,gBAAgB,6BAA6B,OAAO,EAAE;AAAA,IAC/E;AAAA,EACF;AACA,MAAI,EAAE,SAAS,yBAAyB;AACtC,UAAM,EAAE,QAAQ,uBAAuB,IAAI;AAAA,MACzC,aAAa,CAAC,QAAQ,KAAK;AAAA,MAC3B,aAAa,CAAC,YAAY;AAAA,MAC1B,WAAW,CAAC,WAAW;AACrB,cAAM,YAAY,gBAAgB,QAAQ,YAAY;AACtD,YAAI,CAAC,UAAW,QAAO;AACvB,eAAO,6BAA6B,mBAAmB,SAAS,CAAC,aAAa,mBAAmB,OAAO,OAAO,MAAM,EAAE,CAAC,CAAC;AAAA,MAC3H;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,iBAAiB;AAChC,UAAM,EAAE,UAAU,eAAe,IAAI;AAAA,MACnC,aAAa,CAAC,cAAc;AAAA,MAC5B,aAAa,CAAC,MAAM;AAAA,MACpB,WAAW,CAAC,WAAW;AACrB,cAAM,OAAO,OAAO,gBAAgB,QAAQ,MAAM,KAAK,EAAE,EAAE,YAAY;AACvE,YAAI,SAAS,UAAW,QAAO,gBAAgB,gCAAgC,OAAO,EAAE;AACxF,YAAI,SAAS,SAAU,QAAO,gBAAgB,6BAA6B,OAAO,EAAE;AACpF,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,yBAAyB;AACxC,UAAM,EAAE,UAAU,uBAAuB,IAAI;AAAA,MAC3C,aAAa,CAAC,kBAAkB,gBAAgB,cAAc,WAAW;AAAA,MACzE,aAAa,CAAC,aAAa,cAAc,WAAW;AAAA,MACpD,WAAW,CAAC,WAAW;AACrB,cAAM,WAAW,gBAAgB,QAAQ,WAAW;AACpD,eAAO,WAAW,gBAAgB,6BAA6B,QAAQ,IAAI;AAAA,MAC7E;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,0BAA0B;AACzC,UAAM,EAAE,UAAU,wBAAwB,IAAI;AAAA,MAC5C,aAAa,CAAC,cAAc,gBAAgB,YAAY;AAAA,MACxD,aAAa,CAAC,WAAW;AAAA,MACzB,WAAW,CAAC,WAAW;AACrB,cAAM,WAAW,gBAAgB,QAAQ,WAAW;AACpD,eAAO,WAAW,gBAAgB,gCAAgC,QAAQ,IAAI;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AACA,MAAI,EAAE,WAAW,eAAe;AAC9B,UAAM,EAAE,UAAU,aAAa,IAAI;AAAA,MACjC,aAAa,CAAC,OAAO;AAAA,MACrB,WAAW,CAAC,WAAW,gBAAgB,4BAA4B,OAAO,EAAE;AAAA,IAC9E;AAAA,EACF;AACA,MAAI,EAAE,OAAO,eAAe;AAC1B,UAAM,EAAE,MAAM,aAAa,IAAI;AAAA,MAC7B,aAAa,CAAC,QAAQ,OAAO;AAAA,MAC7B,WAAW,CAAC,WAAW,gBAAgB,2BAA2B,OAAO,IAAI,OAAO;AAAA,IACtF;AAAA,EACF;AAEA,0BAAwB;AACxB,SAAO;AACT;AAEA,MAAM,oBAAoB;AAC1B,MAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAI,qBAAoE;AAExE,eAAe,kBAA0D;AACvE,MAAI,CAAC,oBAAoB;AACvB,yBAAqB,QAAQ,QAAQ,EAClC,KAAK,MAAM;AACV,YAAM,MAAM,oBAAI,IAA8B;AAC9C,YAAM,OAAO,WAAW;AACxB,iBAAW,OAAO,MAAM;AACtB,cAAM,QAAU,IAAY,kBAAqD,CAAC;AAClF,mBAAW,QAAQ,OAAO;AACxB,cAAI,MAAM,MAAM,CAAC,IAAI,IAAI,KAAK,EAAE,GAAG;AACjC,gBAAI,IAAI,KAAK,IAAI,IAAI;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC,EACA,MAAM,MAAM,oBAAI,IAA8B,CAAC;AAAA,EACpD;AACA,SAAO;AACT;AASA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MACJ,QAAQ,sBAAsB,OAAO,EACrC,QAAQ,WAAW,GAAG,EACtB,YAAY;AACjB;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,aAAa,CAAC,GAAG,MAAc,EAAE,YAAY,CAAC;AACrE;AAEA,SAAS,eAAe,OAA+B;AACrD,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,WAAO,QAAQ,SAAS,UAAU;AAAA,EACpC;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AAC3D,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAiC,OAA8B;AACtF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,KAAK,MAAM,OAAW,QAAO,eAAe,OAAO,KAAK,CAAC;AACpE,QAAM,QAAQ,aAAa,KAAK;AAChC,MAAI,UAAU,SAAS,OAAO,KAAK,MAAM,OAAW,QAAO,eAAe,OAAO,KAAK,CAAC;AACvF,QAAM,QAAQ,aAAa,KAAK;AAChC,MAAI,UAAU,SAAS,OAAO,KAAK,MAAM,OAAW,QAAO,eAAe,OAAO,KAAK,CAAC;AACvF,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAc,SAAkB,SAAiB,IAAmB;AAC3F,QAAM,KAAK,eAAe,OAAO;AACjC,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,GAAG,IAAI,IAAI,mBAAmB,EAAE,CAAC,GAAG,MAAM;AACnD;AAEA,SAAS,OAAO,OAA2C;AACzD,SAAO,OAAO,UAAU,YAAY,6EAA6E,KAAK,MAAM,KAAK,CAAC;AACpI;AAEA,SAAS,mBAAmB,UAAkB,KAAyB;AACrE,QAAM,IAAI,aAAa;AACvB,MAAI,aAAa,EAAE,SAAS,2BAA2B,aAAa,EAAE,SAAS,iBAAiB;AAC9F,WAAO,IAAI,OAAO,CAAC,OAAO,OAAO,EAAE,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAEA,SAAS,uBAAuB,UAAkB,UAA0C,aAAsD;AAChJ,QAAM,aAAa,oBAAI,IAAY;AACnC,QAAM,OAAO,YAAY,IAAI,QAAQ;AACrC,MAAI,MAAM,YAAY;AACpB,eAAW,IAAI,KAAK,UAAU;AAC9B,eAAW,IAAI,aAAa,KAAK,UAAU,CAAC;AAAA,EAC9C;AACA,aAAW,SAAS,UAAU,eAAe,CAAC,GAAG;AAC/C,eAAW,IAAI,KAAK;AACpB,eAAW,IAAI,aAAa,KAAK,CAAC;AAAA,EACpC;AACA,uBAAqB,QAAQ,CAAC,UAAU;AACtC,eAAW,IAAI,KAAK;AACpB,eAAW,IAAI,aAAa,KAAK,CAAC;AAAA,EACpC,CAAC;AACD,SAAO,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAClE;AAEA,SAAS,WACP,QACA,UACA,UACA,aACe;AACf,QAAM,aAAa,uBAAuB,UAAU,UAAU,WAAW;AACzE,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,gBAAgB,QAAQ,SAAS;AAC/C,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,QAAM,WAAW,CAAC,gBAAgB,QAAQ,YAAY,GAAG,gBAAgB,QAAQ,WAAW,CAAC,EAC1F,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC,EAC9C,KAAK,GAAG,EACR,KAAK;AACR,MAAI,SAAS,OAAQ,QAAO;AAC5B,SAAO;AACT;AAEA,eAAsB,6BACpB,aACA,MACkC;AAClC,QAAM,MAA+B,oBAAI,IAAI;AAC7C,MAAI,CAAC,YAAY,UAAU,CAAC,KAAK,YAAa,QAAO;AACrD,QAAM,cAAc,MAAM,gBAAgB;AAC1C,QAAM,UAAU,oBAAI,IAAyB;AAC7C,aAAW,cAAc,aAAa;AACpC,QAAI,CAAC,cAAc,WAAW,SAAS,kBAAmB;AAC1D,UAAM,OAAO,WAAW,MAAM,KAAK;AACnC,UAAM,KAAK,WAAW,IAAI,KAAK;AAC/B,QAAI,CAAC,QAAQ,CAAC,GAAI;AAClB,QAAI,CAAC,QAAQ,IAAI,IAAI,EAAG,SAAQ,IAAI,MAAM,oBAAI,IAAI,CAAC;AACnD,YAAQ,IAAI,IAAI,EAAG,IAAI,EAAE;AAAA,EAC3B;AACA,MAAI,CAAC,QAAQ,KAAM,QAAO;AAE1B,QAAM,kBAAkB,mBAAmB;AAC3C,aAAW,CAAC,UAAU,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAClD,UAAM,MAAM,mBAAmB,UAAU,MAAM,KAAK,OAAO,OAAO,CAAC,CAAC;AACpE,QAAI,CAAC,IAAI,OAAQ;AACjB,UAAM,WAAW,gBAAgB,QAAQ;AACzC,UAAM,SAAS,oBAAI,IAAY,CAAC,IAAI,CAAC;AACrC,UAAM,aAAa,uBAAuB,UAAU,UAAU,WAAW;AACzE,eAAW,QAAQ,CAAC,UAAU,OAAO,IAAI,KAAK,CAAC;AAC/C,eAAW,SAAS,UAAU,eAAe,CAAC,GAAG;AAC/C,aAAO,IAAI,KAAK;AAChB,aAAO,IAAI,aAAa,KAAK,CAAC;AAAA,IAChC;AACA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,YAAY,MAAM,UAAiB;AAAA,QAC3D,QAAQ,MAAM,KAAK,MAAM;AAAA,QACzB,SAAS,EAAE,IAAI,IAAI,WAAW,IAAI,EAAE,KAAK,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;AAAA,QACjE,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,MAAM,EAAE,UAAU,KAAK,IAAI,IAAI,QAAQ,EAAE,EAAE;AAAA,MAC7C,CAAC;AACD,iBAAW,UAAU,OAAO,SAAS,CAAC,GAAG;AACvC,cAAM,WAAW,eAAgB,OAAmC,EAAE;AACtE,YAAI,CAAC,SAAU;AACf,cAAM,QAAQ,WAAW,QAAmC,UAAU,UAAU,WAAW;AAC3F,cAAM,OAAO,UAAU,YAAY,MAAiC,KAAK;AACzE,YAAI,SAAS,MAAM;AACjB,cAAI,IAAI,GAAG,QAAQ,IAAI,QAAQ,IAAI;AAAA,YACjC,OAAO,SAAS;AAAA,YAChB,MAAM,QAAQ;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,KAAK,0DAA0D,UAAU,KAAK;AAAA,IACxF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,2BACd,aACA,aACwB;AACxB,MAAI,CAAC,YAAY,KAAM,QAAO;AAC9B,SAAO,YAAY,IAAI,CAAC,eAAe;AACrC,QAAI,CAAC,cAAc,CAAC,WAAW,QAAQ,CAAC,WAAW,GAAI,QAAO;AAC9D,UAAM,MAAM,GAAG,WAAW,IAAI,IAAI,WAAW,EAAE;AAC/C,UAAM,SAAS,YAAY,IAAI,GAAG;AAClC,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,OAA6B,EAAE,GAAG,WAAW;AACnD,QAAI,CAAC,KAAK,SAAS,OAAO,MAAO,MAAK,QAAQ,OAAO;AACrD,QAAI,CAAC,KAAK,QAAQ,OAAO,KAAM,MAAK,OAAO,OAAO;AAClD,WAAO;AAAA,EACT,CAAC;AACH;",
6
6
  "names": []
7
7
  }
@@ -16,9 +16,9 @@ const DEFAULT_ATTACHMENT_PARTITIONS = [
16
16
  isPublic: false
17
17
  }
18
18
  ];
19
- const PRODUCT_MEDIA_ENTITY_IDS = /* @__PURE__ */ new Set([
20
- E.catalog.catalog_product
21
- ]);
19
+ const PRODUCT_MEDIA_ENTITY_IDS = new Set(
20
+ [E.catalog?.catalog_product].filter(Boolean)
21
+ );
22
22
  const FALLBACK_PARTITION = "privateAttachments";
23
23
  function resolveDefaultPartitionCode(entityId) {
24
24
  if (!entityId) return FALLBACK_PARTITION;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/attachments/lib/partitions.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { AttachmentPartition } from '../data/entities'\nimport { resolveDefaultAttachmentOcrEnabled } from './ocrConfig'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { E } from '#generated/entities.ids.generated'\n\nexport type AttachmentPartitionSeed = {\n code: string\n title: string\n description?: string | null\n isPublic?: boolean\n}\n\nexport const DEFAULT_ATTACHMENT_PARTITIONS: AttachmentPartitionSeed[] = [\n {\n code: 'productsMedia',\n title: 'Products media',\n description: 'Public media uploaded for catalog products.',\n isPublic: true,\n },\n {\n code: 'privateAttachments',\n title: 'Private attachments',\n description: 'Internal attachments scoped to tenants and organizations.',\n isPublic: false,\n },\n]\n\nconst PRODUCT_MEDIA_ENTITY_IDS = new Set<string>([\n E.catalog.catalog_product,\n])\n\nconst FALLBACK_PARTITION = 'privateAttachments'\n\nexport function resolveDefaultPartitionCode(entityId: string | null | undefined): string {\n if (!entityId) return FALLBACK_PARTITION\n if (PRODUCT_MEDIA_ENTITY_IDS.has(entityId)) return 'productsMedia'\n return FALLBACK_PARTITION\n}\n\nexport async function ensureDefaultPartitions(em: EntityManager): Promise<void> {\n const repo = em.getRepository(AttachmentPartition)\n const existing = await repo.findAll({ fields: ['code'] })\n const existingCodes = new Set(existing.map((entry) => entry.code))\n const pending = DEFAULT_ATTACHMENT_PARTITIONS.filter((seed) => !existingCodes.has(seed.code))\n if (!pending.length) return\n for (const seed of pending) {\n const record = repo.create({\n code: seed.code,\n title: seed.title,\n description: seed.description ?? null,\n storageDriver: 'local',\n isPublic: seed.isPublic ?? false,\n requiresOcr: resolveDefaultAttachmentOcrEnabled(),\n })\n em.persist(record)\n }\n await em.flush()\n}\n\nexport function sanitizePartitionCode(input: string): string {\n const trimmed = input.trim()\n const normalized = trimmed.replace(/[^a-zA-Z0-9_-]/g, '')\n return normalized\n}\n\nexport function isPartitionSettingsLocked(): boolean {\n const demoModeParsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n const demoModeEnabled = demoModeParsed === false ? false : true\n const onboardingEnabled = parseBooleanToken(process.env.SELF_SERVICE_ONBOARDING_ENABLED ?? '') === true\n return demoModeEnabled || onboardingEnabled\n}\n"],
5
- "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AACnD,SAAS,yBAAyB;AAClC,SAAS,SAAS;AASX,MAAM,gCAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AACF;AAEA,MAAM,2BAA2B,oBAAI,IAAY;AAAA,EAC/C,EAAE,QAAQ;AACZ,CAAC;AAED,MAAM,qBAAqB;AAEpB,SAAS,4BAA4B,UAA6C;AACvF,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,yBAAyB,IAAI,QAAQ,EAAG,QAAO;AACnD,SAAO;AACT;AAEA,eAAsB,wBAAwB,IAAkC;AAC9E,QAAM,OAAO,GAAG,cAAc,mBAAmB;AACjD,QAAM,WAAW,MAAM,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACxD,QAAM,gBAAgB,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACjE,QAAM,UAAU,8BAA8B,OAAO,CAAC,SAAS,CAAC,cAAc,IAAI,KAAK,IAAI,CAAC;AAC5F,MAAI,CAAC,QAAQ,OAAQ;AACrB,aAAW,QAAQ,SAAS;AAC1B,UAAM,SAAS,KAAK,OAAO;AAAA,MACzB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,aAAa,mCAAmC;AAAA,IAClD,CAAC;AACD,OAAG,QAAQ,MAAM;AAAA,EACnB;AACA,QAAM,GAAG,MAAM;AACjB;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,aAAa,QAAQ,QAAQ,mBAAmB,EAAE;AACxD,SAAO;AACT;AAEO,SAAS,4BAAqC;AACnD,QAAM,iBAAiB,kBAAkB,QAAQ,IAAI,aAAa,EAAE;AACpE,QAAM,kBAAkB,mBAAmB,QAAQ,QAAQ;AAC3D,QAAM,oBAAoB,kBAAkB,QAAQ,IAAI,mCAAmC,EAAE,MAAM;AACnG,SAAO,mBAAmB;AAC5B;",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { AttachmentPartition } from '../data/entities'\nimport { resolveDefaultAttachmentOcrEnabled } from './ocrConfig'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { E } from '#generated/entities.ids.generated'\n\nexport type AttachmentPartitionSeed = {\n code: string\n title: string\n description?: string | null\n isPublic?: boolean\n}\n\nexport const DEFAULT_ATTACHMENT_PARTITIONS: AttachmentPartitionSeed[] = [\n {\n code: 'productsMedia',\n title: 'Products media',\n description: 'Public media uploaded for catalog products.',\n isPublic: true,\n },\n {\n code: 'privateAttachments',\n title: 'Private attachments',\n description: 'Internal attachments scoped to tenants and organizations.',\n isPublic: false,\n },\n]\n\nconst PRODUCT_MEDIA_ENTITY_IDS = new Set<string>(\n [(E as any).catalog?.catalog_product].filter(Boolean) as string[]\n)\n\nconst FALLBACK_PARTITION = 'privateAttachments'\n\nexport function resolveDefaultPartitionCode(entityId: string | null | undefined): string {\n if (!entityId) return FALLBACK_PARTITION\n if (PRODUCT_MEDIA_ENTITY_IDS.has(entityId)) return 'productsMedia'\n return FALLBACK_PARTITION\n}\n\nexport async function ensureDefaultPartitions(em: EntityManager): Promise<void> {\n const repo = em.getRepository(AttachmentPartition)\n const existing = await repo.findAll({ fields: ['code'] })\n const existingCodes = new Set(existing.map((entry) => entry.code))\n const pending = DEFAULT_ATTACHMENT_PARTITIONS.filter((seed) => !existingCodes.has(seed.code))\n if (!pending.length) return\n for (const seed of pending) {\n const record = repo.create({\n code: seed.code,\n title: seed.title,\n description: seed.description ?? null,\n storageDriver: 'local',\n isPublic: seed.isPublic ?? false,\n requiresOcr: resolveDefaultAttachmentOcrEnabled(),\n })\n em.persist(record)\n }\n await em.flush()\n}\n\nexport function sanitizePartitionCode(input: string): string {\n const trimmed = input.trim()\n const normalized = trimmed.replace(/[^a-zA-Z0-9_-]/g, '')\n return normalized\n}\n\nexport function isPartitionSettingsLocked(): boolean {\n const demoModeParsed = parseBooleanToken(process.env.DEMO_MODE ?? '')\n const demoModeEnabled = demoModeParsed === false ? false : true\n const onboardingEnabled = parseBooleanToken(process.env.SELF_SERVICE_ONBOARDING_ENABLED ?? '') === true\n return demoModeEnabled || onboardingEnabled\n}\n"],
5
+ "mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AACnD,SAAS,yBAAyB;AAClC,SAAS,SAAS;AASX,MAAM,gCAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AACF;AAEA,MAAM,2BAA2B,IAAI;AAAA,EACnC,CAAE,EAAU,SAAS,eAAe,EAAE,OAAO,OAAO;AACtD;AAEA,MAAM,qBAAqB;AAEpB,SAAS,4BAA4B,UAA6C;AACvF,MAAI,CAAC,SAAU,QAAO;AACtB,MAAI,yBAAyB,IAAI,QAAQ,EAAG,QAAO;AACnD,SAAO;AACT;AAEA,eAAsB,wBAAwB,IAAkC;AAC9E,QAAM,OAAO,GAAG,cAAc,mBAAmB;AACjD,QAAM,WAAW,MAAM,KAAK,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;AACxD,QAAM,gBAAgB,IAAI,IAAI,SAAS,IAAI,CAAC,UAAU,MAAM,IAAI,CAAC;AACjE,QAAM,UAAU,8BAA8B,OAAO,CAAC,SAAS,CAAC,cAAc,IAAI,KAAK,IAAI,CAAC;AAC5F,MAAI,CAAC,QAAQ,OAAQ;AACrB,aAAW,QAAQ,SAAS;AAC1B,UAAM,SAAS,KAAK,OAAO;AAAA,MACzB,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,aAAa,mCAAmC;AAAA,IAClD,CAAC;AACD,OAAG,QAAQ,MAAM;AAAA,EACnB;AACA,QAAM,GAAG,MAAM;AACjB;AAEO,SAAS,sBAAsB,OAAuB;AAC3D,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,aAAa,QAAQ,QAAQ,mBAAmB,EAAE;AACxD,SAAO;AACT;AAEO,SAAS,4BAAqC;AACnD,QAAM,iBAAiB,kBAAkB,QAAQ,IAAI,aAAa,EAAE;AACpE,QAAM,kBAAkB,mBAAmB,QAAQ,QAAQ;AAC3D,QAAM,oBAAoB,kBAAkB,QAAQ,IAAI,mCAAmC,EAAE,MAAM;AACnG,SAAO,mBAAmB;AAC5B;",
6
6
  "names": []
7
7
  }