@open-mercato/core 0.6.6-develop.6330.1.a261878aa8 → 0.6.6-develop.6331.1.a33b8e99b7

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 (244) hide show
  1. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
  2. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  3. package/dist/modules/auth/api/roles/acl/route.js +2 -2
  4. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  5. package/dist/modules/auth/api/users/acl/route.js +2 -2
  6. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  7. package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
  8. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  9. package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
  10. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  11. package/dist/modules/auth/data/entities.js +2 -2
  12. package/dist/modules/auth/data/entities.js.map +2 -2
  13. package/dist/modules/business_rules/api/rules/route.js +3 -3
  14. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  15. package/dist/modules/business_rules/api/sets/route.js +3 -3
  16. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  17. package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
  18. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
  19. package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
  20. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  21. package/dist/modules/catalog/api/product-media/route.js.map +2 -2
  22. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -0
  23. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  24. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  25. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  26. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +12 -1
  27. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  28. package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
  29. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  30. package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
  31. package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
  32. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  33. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  34. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  35. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
  36. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  37. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
  38. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  39. package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
  40. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  41. package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
  42. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  43. package/dist/modules/customers/api/addresses/route.js +4 -2
  44. package/dist/modules/customers/api/addresses/route.js.map +2 -2
  45. package/dist/modules/customers/api/tags/route.js +8 -3
  46. package/dist/modules/customers/api/tags/route.js.map +2 -2
  47. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
  48. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  49. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
  50. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  51. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
  52. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
  53. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
  54. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
  55. package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
  56. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  57. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
  58. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  59. package/dist/modules/customers/commands/interactions.js +5 -5
  60. package/dist/modules/customers/commands/interactions.js.map +2 -2
  61. package/dist/modules/customers/commands/pipeline-stages.js +24 -2
  62. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  63. package/dist/modules/customers/commands/pipelines.js +24 -2
  64. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  65. package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
  66. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  67. package/dist/modules/customers/components/detail/DealForm.js +5 -1
  68. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  69. package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
  70. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  71. package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
  72. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  73. package/dist/modules/data_sync/api/schedules/route.js +1 -1
  74. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  75. package/dist/modules/data_sync/backend/data-sync/page.js +32 -15
  76. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  77. package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
  78. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  79. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
  80. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  81. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
  82. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  83. package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
  84. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  85. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  86. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
  87. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  88. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
  89. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  90. package/dist/modules/entities/api/entities.js +2 -2
  91. package/dist/modules/entities/api/entities.js.map +2 -2
  92. package/dist/modules/entities/api/records.js +7 -5
  93. package/dist/modules/entities/api/records.js.map +2 -2
  94. package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
  95. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  96. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  97. package/dist/modules/feature_toggles/data/entities.js +1 -1
  98. package/dist/modules/feature_toggles/data/entities.js.map +2 -2
  99. package/dist/modules/feature_toggles/data/validators.js +2 -1
  100. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  101. package/dist/modules/feature_toggles/lib/queries.js +2 -1
  102. package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
  103. package/dist/modules/inbox_ops/api/settings/route.js +2 -2
  104. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  105. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
  106. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  107. package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
  108. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  109. package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
  110. package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
  111. package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
  112. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  113. package/dist/modules/sales/commands/documents.js +11 -10
  114. package/dist/modules/sales/commands/documents.js.map +2 -2
  115. package/dist/modules/sales/commands/payments.js +6 -1
  116. package/dist/modules/sales/commands/payments.js.map +2 -2
  117. package/dist/modules/sales/commands/returns.js +3 -3
  118. package/dist/modules/sales/commands/returns.js.map +2 -2
  119. package/dist/modules/sales/commands/shared.js +3 -3
  120. package/dist/modules/sales/commands/shared.js.map +2 -2
  121. package/dist/modules/sales/commands/shipments.js +6 -1
  122. package/dist/modules/sales/commands/shipments.js.map +2 -2
  123. package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
  124. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  125. package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
  126. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  127. package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
  128. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  129. package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
  130. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  131. package/dist/modules/sales/di.js +39 -3
  132. package/dist/modules/sales/di.js.map +2 -2
  133. package/dist/modules/sales/setup.js +2 -0
  134. package/dist/modules/sales/setup.js.map +2 -2
  135. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
  136. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  137. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
  138. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  139. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
  140. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  141. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
  142. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  143. package/dist/modules/staff/commands/job-histories.js +3 -3
  144. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  145. package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
  146. package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
  147. package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
  148. package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
  149. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
  150. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  151. package/dist/modules/translations/components/TranslationManager.js +7 -1
  152. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  153. package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
  154. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  155. package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
  156. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  157. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
  158. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  159. package/package.json +7 -7
  160. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
  161. package/src/modules/auth/api/roles/acl/route.ts +2 -2
  162. package/src/modules/auth/api/users/acl/route.ts +2 -2
  163. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
  164. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
  165. package/src/modules/auth/data/entities.ts +2 -2
  166. package/src/modules/business_rules/api/rules/route.ts +3 -3
  167. package/src/modules/business_rules/api/sets/route.ts +3 -3
  168. package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
  169. package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
  170. package/src/modules/catalog/api/product-media/route.ts +4 -0
  171. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
  172. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
  173. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
  174. package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
  175. package/src/modules/catalog/lib/bulkDelete.ts +6 -0
  176. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
  177. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  178. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
  179. package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
  180. package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
  181. package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
  182. package/src/modules/customers/api/addresses/route.ts +2 -0
  183. package/src/modules/customers/api/tags/route.ts +6 -1
  184. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
  185. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
  186. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
  187. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
  188. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
  189. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
  190. package/src/modules/customers/commands/interactions.ts +5 -5
  191. package/src/modules/customers/commands/pipeline-stages.ts +26 -2
  192. package/src/modules/customers/commands/pipelines.ts +26 -2
  193. package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
  194. package/src/modules/customers/components/detail/DealForm.tsx +12 -0
  195. package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
  196. package/src/modules/customers/i18n/de.json +2 -0
  197. package/src/modules/customers/i18n/en.json +2 -0
  198. package/src/modules/customers/i18n/es.json +2 -0
  199. package/src/modules/customers/i18n/pl.json +2 -0
  200. package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
  201. package/src/modules/data_sync/api/schedules/route.ts +1 -1
  202. package/src/modules/data_sync/backend/data-sync/page.tsx +32 -15
  203. package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
  204. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
  205. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
  206. package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
  207. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
  208. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
  209. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
  210. package/src/modules/entities/api/entities.ts +2 -2
  211. package/src/modules/entities/api/records.ts +7 -5
  212. package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
  213. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
  214. package/src/modules/feature_toggles/data/entities.ts +1 -1
  215. package/src/modules/feature_toggles/data/validators.ts +1 -0
  216. package/src/modules/feature_toggles/lib/queries.ts +1 -0
  217. package/src/modules/inbox_ops/api/settings/route.ts +2 -2
  218. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
  219. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
  220. package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
  221. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
  222. package/src/modules/sales/commands/documents.ts +11 -10
  223. package/src/modules/sales/commands/payments.ts +11 -0
  224. package/src/modules/sales/commands/returns.ts +3 -3
  225. package/src/modules/sales/commands/shared.ts +10 -4
  226. package/src/modules/sales/commands/shipments.ts +14 -0
  227. package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
  228. package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
  229. package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
  230. package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
  231. package/src/modules/sales/di.ts +68 -9
  232. package/src/modules/sales/setup.ts +2 -0
  233. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
  234. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
  235. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
  236. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
  237. package/src/modules/staff/commands/job-histories.ts +3 -3
  238. package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
  239. package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
  240. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
  241. package/src/modules/translations/components/TranslationManager.tsx +14 -1
  242. package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
  243. package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
  244. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/dictionaries/components/DictionaryEntriesEditor.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus, Pencil, Trash2, RefreshCw, Languages } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@open-mercato/ui/primitives/table'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { AppearanceSelector, useAppearanceState } from './AppearanceSelector'\nimport { DictionaryValue } from './dictionaryAppearance'\nimport {\n invalidateDictionaryEntries,\n useDictionaryEntries,\n} from './hooks/useDictionaryEntries'\nimport type { DictionaryEntryRecord } from './hooks/useDictionaryEntries'\nimport {\n DialogDescription,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Entry = DictionaryEntryRecord\n\ntype DictionaryEntriesEditorProps = {\n dictionaryId: string\n dictionaryName: string\n readOnly?: boolean\n}\n\ntype FormState = {\n id?: string | null\n value: string\n label: string\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\nexport function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = false }: DictionaryEntriesEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const readOnlyMessage = t('dictionaries.config.entries.readOnly', 'Inherited dictionaries are managed at the parent organization.')\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useDictionaryEntries(dictionaryId, scopeVersion)\n const entries = React.useMemo<Entry[]>(() => dictionaryQuery.data?.fullEntries ?? [], [dictionaryQuery.data?.fullEntries])\n const dictionaryMap = dictionaryQuery.data?.map ?? {}\n const isInitialLoading = dictionaryQuery.isLoading\n const loadError = dictionaryQuery.isError\n ? t('dictionaries.config.entries.error.load', 'Failed to load dictionary entries.')\n : null\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const [formState, setFormState] = React.useState<FormState>(() => ({\n value: '',\n label: '',\n color: null,\n icon: null,\n }))\n const [errors, setErrors] = React.useState<{ value?: string; label?: string }>({})\n const [translateEntry, setTranslateEntry] = React.useState<Entry | null>(null)\n const appearance = useAppearanceState(formState.icon, formState.color)\n const mutationContextId = React.useMemo(\n () => `dictionaries:dictionary_entry:${dictionaryId}`,\n [dictionaryId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId?: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const resetForm = React.useCallback(() => {\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n }, [appearance])\n\n const openDialog = React.useCallback(\n (entry?: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (entry) {\n setFormState({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n updatedAt: entry.updatedAt ?? null,\n })\n appearance.setColor(entry.color ?? null)\n appearance.setIcon(entry.icon ?? null)\n } else {\n resetForm()\n }\n setErrors({})\n setDialogOpen(true)\n },\n [appearance, readOnly, readOnlyMessage, resetForm],\n )\n\n const closeDialog = React.useCallback(() => {\n setDialogOpen(false)\n resetForm()\n setErrors({})\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n const trimmedValue = formState.value.trim()\n const trimmedLabel = formState.label.trim()\n const nextErrors: { value?: string } = {}\n if (!trimmedValue) {\n nextErrors.value = t('dictionaries.config.entries.error.required', 'Value is required.')\n }\n if (nextErrors.value) {\n setErrors(nextErrors)\n return\n }\n setErrors({})\n setIsSaving(true)\n try {\n const payload = {\n value: trimmedValue,\n label: trimmedLabel || trimmedValue,\n color: appearance.color,\n icon: appearance.icon,\n }\n if (formState.id) {\n const entryId = formState.id\n const expectedUpdatedAt = formState.updatedAt\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(expectedUpdatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entryId}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to save dictionary entry'),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entryId,\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.update', 'Dictionary entry updated.'), 'success')\n } else {\n await runMutation({\n operation: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary entry',\n )\n }\n return call\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.create', 'Dictionary entry created.'), 'success')\n }\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n setDialogOpen(false)\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to save dictionary entry', err)\n flash(t('dictionaries.config.entries.error.save', 'Failed to save dictionary entry.'), 'error')\n } finally {\n setIsSaving(false)\n }\n }, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t])\n\n const handleDelete = React.useCallback(\n async (entry: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (!entry.id) return\n const confirmDelete = await confirm({\n title: t('dictionaries.config.entries.delete.confirm', 'Delete \"{{value}}\"?', { value: entry.label || entry.value }),\n variant: 'destructive',\n })\n if (!confirmDelete) return\n setIsDeleting(true)\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entry.id}`,\n { method: 'DELETE' },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary entry',\n ),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entry.id,\n retryLastMutation,\n },\n mutationPayload: { id: entry.id },\n })\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n flash(t('dictionaries.config.entries.success.delete', 'Dictionary entry deleted.'), 'success')\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to delete dictionary entry', err)\n flash(t('dictionaries.config.entries.error.delete', 'Failed to delete dictionary entry.'), 'error')\n } finally {\n setIsDeleting(false)\n }\n },\n [confirm, dictionaryId, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t],\n )\n\n const tableContent = React.useMemo(() => {\n if (isInitialLoading) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-8 text-center text-sm text-muted-foreground\">\n <Spinner className=\"mx-auto mb-2 h-5 w-5\" />\n {t('dictionaries.config.entries.loading', 'Loading entries\u2026')}\n </TableCell>\n </TableRow>\n )\n }\n if (loadError) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-destructive\">\n {loadError}\n </TableCell>\n </TableRow>\n )\n }\n if (!entries.length) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('dictionaries.config.entries.empty', 'No entries yet.')}\n </TableCell>\n </TableRow>\n )\n }\n return entries.map((entry) => (\n <TableRow key={entry.id}>\n <TableCell className=\"font-medium\">{entry.value}</TableCell>\n <TableCell>{entry.label}</TableCell>\n <TableCell>\n <DictionaryValue\n value={entry.value}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{t('dictionaries.config.entries.appearance.none', 'None')}</span>}\n />\n </TableCell>\n <TableCell className=\"flex items-center gap-2\">\n {readOnly ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('dictionaries.config.entries.readOnlyActions', 'Managed in parent organization')}\n </span>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openDialog(entry)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTranslateEntry(entry)}\n title={t('dictionaries.config.entries.actions.translate', 'Translate')}\n >\n <Languages className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(entry)}\n disabled={isDeleting}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </>\n )}\n </TableCell>\n </TableRow>\n ))\n }, [dictionaryMap, entries, handleDelete, isDeleting, isInitialLoading, loadError, openDialog, readOnly, t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">{dictionaryName}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {readOnly\n ? readOnlyMessage\n : t('dictionaries.config.entries.subtitle', 'Manage reusable values and appearance for this dictionary.')}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n dictionaryQuery.refetch().catch(() => {})\n }}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.refresh', 'Refresh')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => openDialog()}\n disabled={readOnly}\n title={readOnly ? readOnlyMessage : undefined}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.add', 'Add entry')}\n </Button>\n </div>\n </div>\n\n <div className=\"overflow-hidden rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.value', 'Value')}</TableHead>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.label', 'Label')}</TableHead>\n <TableHead>{t('dictionaries.config.entries.columns.appearance', 'Appearance')}</TableHead>\n <TableHead className=\"w-32 text-right\">{t('dictionaries.config.entries.columns.actions', 'Actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>{tableContent}</TableBody>\n </Table>\n </div>\n\n <Dialog open={dialogOpen} onOpenChange={(open) => (!open ? closeDialog() : undefined)}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {formState.id\n ? t('dictionaries.config.entries.dialog.editTitle', 'Edit dictionary entry')\n : t('dictionaries.config.entries.dialog.addTitle', 'Add dictionary entry')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.valueLabel', 'Value')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <Input\n type=\"text\"\n value={formState.value}\n onChange={(event) => {\n const nextValue = event.target.value\n setFormState((prev) => ({ ...prev, value: nextValue }))\n if (errors.value) {\n setErrors((prev) => ({ ...prev, value: undefined }))\n }\n }}\n aria-invalid={errors.value ? 'true' : 'false'}\n aria-describedby=\"dictionary-entry-value-error\"\n />\n {errors.value ? (\n <p id=\"dictionary-entry-value-error\" className=\"text-xs text-destructive\">\n {errors.value}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.labelLabel', 'Label')}\n </label>\n <Input\n type=\"text\"\n value={formState.label}\n onChange={(event) => setFormState((prev) => ({ ...prev, label: event.target.value }))}\n placeholder={t('dictionaries.config.entries.dialog.labelPlaceholder', 'Display name shown in UI')}\n />\n </div>\n <AppearanceSelector\n icon={appearance.icon}\n color={appearance.color}\n onIconChange={(next) => {\n appearance.setIcon(next)\n setFormState((prev) => ({ ...prev, icon: next }))\n }}\n onColorChange={(next) => {\n appearance.setColor(next)\n setFormState((prev) => ({ ...prev, color: next }))\n }}\n labels={{\n colorLabel: t('dictionaries.config.entries.dialog.colorLabel', 'Color'),\n colorHelp: t('dictionaries.config.entries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('dictionaries.config.entries.dialog.colorClear', 'Remove color'),\n iconLabel: t('dictionaries.config.entries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('dictionaries.config.entries.dialog.iconPlaceholder', 'Type an emoji or icon token.'),\n iconPickerTriggerLabel: t('dictionaries.config.entries.dialog.iconBrowse', 'Browse icons and emoji'),\n iconSearchPlaceholder: t('dictionaries.config.entries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('dictionaries.config.entries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('dictionaries.config.entries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('dictionaries.config.entries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('dictionaries.config.entries.dialog.previewEmpty', 'No appearance selected'),\n }}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={closeDialog}\n disabled={isSaving}\n >\n {t('dictionaries.config.entries.dialog.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.entries.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <Dialog open={!!translateEntry} onOpenChange={(open) => { if (!open) setTranslateEntry(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateEntry', 'Translate: {{label}}', { label: translateEntry?.label ?? '' })}</DialogTitle>\n <DialogDescription>\n {t('translations.manager.translateEntryDescription', 'Manage translations for this dictionary entry.')}\n </DialogDescription>\n </DialogHeader>\n {translateEntry?.id && (\n <TranslationManager\n mode=\"embedded\"\n entityType=\"dictionaries:dictionary_entry\"\n recordId={translateEntry.id}\n baseValues={{ label: translateEntry.label }}\n translatableFields={['label']}\n />\n )}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus, Pencil, Trash2, RefreshCw, Languages } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@open-mercato/ui/primitives/table'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { AppearanceSelector, useAppearanceState } from './AppearanceSelector'\nimport { DictionaryValue } from './dictionaryAppearance'\nimport {\n invalidateDictionaryEntries,\n useDictionaryEntries,\n} from './hooks/useDictionaryEntries'\nimport type { DictionaryEntryRecord } from './hooks/useDictionaryEntries'\nimport {\n DialogDescription,\n} from '@open-mercato/ui/primitives/dialog'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Entry = DictionaryEntryRecord\n\ntype DictionaryEntriesEditorProps = {\n dictionaryId: string\n dictionaryName: string\n readOnly?: boolean\n}\n\ntype FormState = {\n id?: string | null\n value: string\n label: string\n color: string | null\n icon: string | null\n updatedAt?: string | null\n}\n\nexport function DictionaryEntriesEditor({ dictionaryId, dictionaryName, readOnly = false }: DictionaryEntriesEditorProps) {\n const t = useT()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const readOnlyMessage = t('dictionaries.config.entries.readOnly', 'Inherited dictionaries are managed at the parent organization.')\n const queryClient = useQueryClient()\n const scopeVersion = useOrganizationScopeVersion()\n const dictionaryQuery = useDictionaryEntries(dictionaryId, scopeVersion)\n const entries = React.useMemo<Entry[]>(() => dictionaryQuery.data?.fullEntries ?? [], [dictionaryQuery.data?.fullEntries])\n const dictionaryMap = dictionaryQuery.data?.map ?? {}\n const isInitialLoading = dictionaryQuery.isLoading\n const loadError = dictionaryQuery.isError\n ? t('dictionaries.config.entries.error.load', 'Failed to load dictionary entries.')\n : null\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [isDeleting, setIsDeleting] = React.useState(false)\n const [isSaving, setIsSaving] = React.useState(false)\n const [formState, setFormState] = React.useState<FormState>(() => ({\n value: '',\n label: '',\n color: null,\n icon: null,\n }))\n const [errors, setErrors] = React.useState<{ value?: string; label?: string }>({})\n const [translateEntry, setTranslateEntry] = React.useState<Entry | null>(null)\n const appearance = useAppearanceState(formState.icon, formState.color)\n const mutationContextId = React.useMemo(\n () => `dictionaries:dictionary_entry:${dictionaryId}`,\n [dictionaryId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n resourceId?: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: mutationContextId,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const resetForm = React.useCallback(() => {\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n }, [appearance])\n\n const openDialog = React.useCallback(\n (entry?: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (entry) {\n setFormState({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n updatedAt: entry.updatedAt ?? null,\n })\n appearance.setColor(entry.color ?? null)\n appearance.setIcon(entry.icon ?? null)\n } else {\n resetForm()\n }\n setErrors({})\n setDialogOpen(true)\n },\n [appearance, readOnly, readOnlyMessage, resetForm],\n )\n\n const closeDialog = React.useCallback(() => {\n setDialogOpen(false)\n resetForm()\n setErrors({})\n }, [resetForm])\n\n const handleSave = React.useCallback(async () => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n const trimmedValue = formState.value.trim()\n const trimmedLabel = formState.label.trim()\n const nextErrors: { value?: string } = {}\n if (!trimmedValue) {\n nextErrors.value = t('dictionaries.config.entries.error.required', 'Value is required.')\n }\n if (nextErrors.value) {\n setErrors(nextErrors)\n return\n }\n setErrors({})\n setIsSaving(true)\n try {\n const payload = {\n value: trimmedValue,\n label: trimmedLabel || trimmedValue,\n color: appearance.color,\n icon: appearance.icon,\n }\n if (formState.id) {\n const entryId = formState.id\n const expectedUpdatedAt = formState.updatedAt\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(expectedUpdatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entryId}`,\n {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(typeof call.result?.error === 'string' ? call.result.error : 'Failed to save dictionary entry'),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entryId,\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.update', 'Dictionary entry updated.'), 'success')\n } else {\n await runMutation({\n operation: async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries`,\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n )\n if (!call.ok) {\n throw new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to create dictionary entry',\n )\n }\n return call\n },\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n retryLastMutation,\n },\n mutationPayload: payload,\n })\n flash(t('dictionaries.config.entries.success.create', 'Dictionary entry created.'), 'success')\n }\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n setDialogOpen(false)\n setFormState({ value: '', label: '', color: null, icon: null })\n appearance.setColor(null)\n appearance.setIcon(null)\n setErrors({})\n } catch (err) {\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to save dictionary entry', err)\n flash(t('dictionaries.config.entries.error.save', 'Failed to save dictionary entry.'), 'error')\n } finally {\n setIsSaving(false)\n }\n }, [appearance, dictionaryId, formState.id, formState.label, formState.updatedAt, formState.value, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t])\n\n const handleDelete = React.useCallback(\n async (entry: Entry) => {\n if (readOnly) {\n flash(readOnlyMessage, 'info')\n return\n }\n if (!entry.id) return\n const confirmDelete = await confirm({\n title: t('dictionaries.config.entries.delete.confirm', 'Delete \"{{value}}\"?', { value: entry.label || entry.value }),\n variant: 'destructive',\n })\n if (!confirmDelete) return\n setIsDeleting(true)\n try {\n await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n async () => {\n const call = await apiCall<Record<string, unknown>>(\n `/api/dictionaries/${dictionaryId}/entries/${entry.id}`,\n { method: 'DELETE' },\n )\n if (!call.ok) {\n throw Object.assign(\n new Error(\n typeof call.result?.error === 'string' ? call.result.error : 'Failed to delete dictionary entry',\n ),\n { status: call.status, ...(call.result && typeof call.result === 'object' ? call.result : {}) },\n )\n }\n return call\n },\n ),\n context: {\n formId: mutationContextId,\n resourceKind: 'dictionaries.dictionary_entry',\n resourceId: entry.id,\n retryLastMutation,\n },\n mutationPayload: { id: entry.id },\n })\n await invalidateDictionaryEntries(queryClient, dictionaryId)\n flash(t('dictionaries.config.entries.success.delete', 'Dictionary entry deleted.'), 'success')\n } catch (err) {\n // Route a concurrent-edit 409 through the single conflict surface (matching\n // the entry save path); fall back to a flash for any other delete failure.\n if (surfaceRecordConflict(err, t)) {\n return\n }\n console.error('Failed to delete dictionary entry', err)\n flash(t('dictionaries.config.entries.error.delete', 'Failed to delete dictionary entry.'), 'error')\n } finally {\n setIsDeleting(false)\n }\n },\n [confirm, dictionaryId, mutationContextId, queryClient, readOnly, readOnlyMessage, runMutation, retryLastMutation, t],\n )\n\n const tableContent = React.useMemo(() => {\n if (isInitialLoading) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-8 text-center text-sm text-muted-foreground\">\n <Spinner className=\"mx-auto mb-2 h-5 w-5\" />\n {t('dictionaries.config.entries.loading', 'Loading entries\u2026')}\n </TableCell>\n </TableRow>\n )\n }\n if (loadError) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-destructive\">\n {loadError}\n </TableCell>\n </TableRow>\n )\n }\n if (!entries.length) {\n return (\n <TableRow>\n <TableCell colSpan={4} className=\"py-6 text-center text-sm text-muted-foreground\">\n {t('dictionaries.config.entries.empty', 'No entries yet.')}\n </TableCell>\n </TableRow>\n )\n }\n return entries.map((entry) => (\n <TableRow key={entry.id}>\n <TableCell className=\"font-medium\">{entry.value}</TableCell>\n <TableCell>{entry.label}</TableCell>\n <TableCell>\n <DictionaryValue\n value={entry.value}\n map={dictionaryMap}\n fallback={<span className=\"text-sm text-muted-foreground\">{t('dictionaries.config.entries.appearance.none', 'None')}</span>}\n />\n </TableCell>\n <TableCell className=\"flex items-center gap-2\">\n {readOnly ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('dictionaries.config.entries.readOnlyActions', 'Managed in parent organization')}\n </span>\n ) : (\n <>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => openDialog(entry)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setTranslateEntry(entry)}\n title={t('dictionaries.config.entries.actions.translate', 'Translate')}\n >\n <Languages className=\"h-4 w-4\" />\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => handleDelete(entry)}\n disabled={isDeleting}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </>\n )}\n </TableCell>\n </TableRow>\n ))\n }, [dictionaryMap, entries, handleDelete, isDeleting, isInitialLoading, loadError, openDialog, readOnly, t])\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold\">{dictionaryName}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {readOnly\n ? readOnlyMessage\n : t('dictionaries.config.entries.subtitle', 'Manage reusable values and appearance for this dictionary.')}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => {\n dictionaryQuery.refetch().catch(() => {})\n }}\n >\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.refresh', 'Refresh')}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={() => openDialog()}\n disabled={readOnly}\n title={readOnly ? readOnlyMessage : undefined}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('dictionaries.config.entries.actions.add', 'Add entry')}\n </Button>\n </div>\n </div>\n\n <div className=\"overflow-hidden rounded-md border\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.value', 'Value')}</TableHead>\n <TableHead className=\"w-48\">{t('dictionaries.config.entries.columns.label', 'Label')}</TableHead>\n <TableHead>{t('dictionaries.config.entries.columns.appearance', 'Appearance')}</TableHead>\n <TableHead className=\"w-32 text-right\">{t('dictionaries.config.entries.columns.actions', 'Actions')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>{tableContent}</TableBody>\n </Table>\n </div>\n\n <Dialog open={dialogOpen} onOpenChange={(open) => (!open ? closeDialog() : undefined)}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>\n {formState.id\n ? t('dictionaries.config.entries.dialog.editTitle', 'Edit dictionary entry')\n : t('dictionaries.config.entries.dialog.addTitle', 'Add dictionary entry')}\n </DialogTitle>\n </DialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.valueLabel', 'Value')}\n <span className=\"ml-1 text-destructive\">*</span>\n </label>\n <Input\n type=\"text\"\n value={formState.value}\n onChange={(event) => {\n const nextValue = event.target.value\n setFormState((prev) => ({ ...prev, value: nextValue }))\n if (errors.value) {\n setErrors((prev) => ({ ...prev, value: undefined }))\n }\n }}\n aria-invalid={errors.value ? 'true' : 'false'}\n aria-describedby=\"dictionary-entry-value-error\"\n />\n {errors.value ? (\n <p id=\"dictionary-entry-value-error\" className=\"text-xs text-destructive\">\n {errors.value}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">\n {t('dictionaries.config.entries.dialog.labelLabel', 'Label')}\n </label>\n <Input\n type=\"text\"\n value={formState.label}\n onChange={(event) => setFormState((prev) => ({ ...prev, label: event.target.value }))}\n placeholder={t('dictionaries.config.entries.dialog.labelPlaceholder', 'Display name shown in UI')}\n />\n </div>\n <AppearanceSelector\n icon={appearance.icon}\n color={appearance.color}\n onIconChange={(next) => {\n appearance.setIcon(next)\n setFormState((prev) => ({ ...prev, icon: next }))\n }}\n onColorChange={(next) => {\n appearance.setColor(next)\n setFormState((prev) => ({ ...prev, color: next }))\n }}\n labels={{\n colorLabel: t('dictionaries.config.entries.dialog.colorLabel', 'Color'),\n colorHelp: t('dictionaries.config.entries.dialog.colorHelp', 'Pick a highlight color for this entry.'),\n colorClearLabel: t('dictionaries.config.entries.dialog.colorClear', 'Remove color'),\n iconLabel: t('dictionaries.config.entries.dialog.iconLabel', 'Icon or emoji'),\n iconPlaceholder: t('dictionaries.config.entries.dialog.iconPlaceholder', 'Type an emoji or icon token.'),\n iconPickerTriggerLabel: t('dictionaries.config.entries.dialog.iconBrowse', 'Browse icons and emoji'),\n iconSearchPlaceholder: t('dictionaries.config.entries.dialog.iconSearchPlaceholder', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('dictionaries.config.entries.dialog.iconSearchEmpty', 'No icons match your search.'),\n iconSuggestionsLabel: t('dictionaries.config.entries.dialog.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('dictionaries.config.entries.dialog.iconClear', 'Remove icon'),\n previewEmptyLabel: t('dictionaries.config.entries.dialog.previewEmpty', 'No appearance selected'),\n }}\n />\n </div>\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={closeDialog}\n disabled={isSaving}\n >\n {t('dictionaries.config.entries.dialog.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n onClick={handleSave}\n disabled={isSaving}\n >\n {isSaving ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\n {t('dictionaries.config.entries.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n <Dialog open={!!translateEntry} onOpenChange={(open) => { if (!open) setTranslateEntry(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateEntry', 'Translate: {{label}}', { label: translateEntry?.label ?? '' })}</DialogTitle>\n <DialogDescription>\n {t('translations.manager.translateEntryDescription', 'Manage translations for this dictionary entry.')}\n </DialogDescription>\n </DialogHeader>\n {translateEntry?.id && (\n <TranslationManager\n mode=\"embedded\"\n entityType=\"dictionaries:dictionary_entry\"\n recordId={translateEntry.id}\n baseValues={{ label: translateEntry.label }}\n translatableFields={['label']}\n />\n )}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { usePathname } from "next/navigation";
4
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
5
6
  import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
6
7
  import { E } from "../../../../../../../generated/entities.ids.generated.js";
@@ -16,11 +17,13 @@ import { deleteCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
16
17
  import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
17
18
  import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
18
19
  import { ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
20
+ import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from "@open-mercato/ui/backend/injection/recordContext";
19
21
  const TREE_STEP = 16;
20
22
  const TREE_PADDING = 12;
21
23
  function EditOrganizationPage({ params }) {
22
24
  const orgId = params?.id;
23
25
  const t = useT();
26
+ const pathname = usePathname();
24
27
  const [initialValues, setInitialValues] = React.useState(null);
25
28
  const [pathLabel, setPathLabel] = React.useState("");
26
29
  const [tenantId, setTenantId] = React.useState(null);
@@ -218,6 +221,15 @@ function EditOrganizationPage({ params }) {
218
221
  { id: "details", title: t("directory.organizations.form.group.details", "Details"), column: 1, fields: detailFields },
219
222
  { id: "custom", title: t("directory.organizations.form.group.customFields", "Custom Data"), column: 2, kind: "customFields" }
220
223
  ], [detailFields, t]);
224
+ useSetCurrentRecordInjectionContext(
225
+ buildRecordInjectionContext({
226
+ resourceKind: "directory.organization",
227
+ resourceId: orgId || null,
228
+ updatedAt: typeof initialValues?.updatedAt === "string" ? initialValues.updatedAt : null,
229
+ data: initialValues,
230
+ path: pathname
231
+ })
232
+ );
221
233
  if (!orgId) {
222
234
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx("div", { className: "rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive", children: t("directory.organizations.form.errors.missingId", "Organization identifier is missing.") }) }) });
223
235
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/directory/backend/directory/organizations/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport {\n buildOrganizationTreeOptions,\n type OrganizationTreeNode,\n type OrganizationTreeOption,\n} from '@open-mercato/core/modules/directory/lib/tree'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\n\ntype TreeResponse = {\n items: OrganizationTreeNode[]\n}\n\ntype OrganizationResponse = {\n items: Array<{\n id: string\n name: string\n slug?: string | null\n tenantId: string\n tenantName?: string | null\n parentId: string | null\n childIds: string[]\n ancestorIds: string[]\n descendantIds: string[]\n isActive: boolean\n pathLabel: string\n updatedAt?: string | null\n updated_at?: string | null\n } & Record<string, unknown>>\n}\n\nconst TREE_STEP = 16\nconst TREE_PADDING = 12\n\nexport default function EditOrganizationPage({ params }: { params?: { id?: string } }) {\n const orgId = params?.id\n const t = useT()\n const [initialValues, setInitialValues] = React.useState<Record<string, unknown> | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [tenantId, setTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [parentTree, setParentTree] = React.useState<OrganizationTreeNode[]>([])\n const [childSummary, setChildSummary] = React.useState<OrganizationTreeOption[]>([])\n const [originalChildIds, setOriginalChildIds] = React.useState<string[]>([])\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const skipTenantEffectRef = React.useRef(true)\n\n React.useEffect(() => {\n let cancelled = false\n async function loadActor() {\n try {\n const { ok, result } = await apiCall<{ isSuperAdmin?: boolean }>('/api/auth/roles?page=1&pageSize=1')\n if (!cancelled && ok) setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n } catch {\n if (!cancelled) setActorIsSuperAdmin(false)\n }\n }\n loadActor()\n return () => { cancelled = true }\n }, [])\n\n const markSelectable = React.useCallback((nodes: OrganizationTreeNode[], excluded: Set<string>): OrganizationTreeNode[] => (\n nodes.map((node) => ({\n ...node,\n selectable: !excluded.has(node.id),\n children: Array.isArray(node.children) ? markSelectable(node.children, excluded) : [],\n }))\n ), [])\n\n const loadParentTree = React.useCallback(async (\n targetTenantId: string | null,\n excludedIds: Iterable<string>,\n ): Promise<OrganizationTreeNode[]> => {\n const treeParams = new URLSearchParams({ view: 'tree', includeInactive: 'true' })\n if (targetTenantId) treeParams.set('tenantId', targetTenantId)\n if (orgId) treeParams.set('ids', orgId)\n try {\n const { ok, result } = await apiCall<TreeResponse>(`/api/directory/organizations?${treeParams.toString()}`)\n if (!ok) {\n setParentTree([])\n return []\n }\n const baseTree = Array.isArray(result?.items) ? result.items ?? [] : []\n const excludedSet = new Set<string>(excludedIds)\n if (orgId) excludedSet.add(orgId)\n setParentTree(markSelectable(baseTree, excludedSet))\n return baseTree\n } catch {\n setParentTree([])\n return []\n }\n }, [markSelectable, orgId])\n\n React.useEffect(() => {\n if (!orgId) return\n const currentOrgId = orgId\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const { ok, status, result } = await apiCall<OrganizationResponse>(\n `/api/directory/organizations?view=manage&ids=${currentOrgId}&status=all&includeInactive=true&page=1&pageSize=1`,\n )\n if (!ok) {\n if (status === 404) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n throw new Error(t('directory.organizations.form.errors.load', 'Failed to load organization'))\n }\n const record = Array.isArray(result?.items) ? result.items?.[0] : undefined\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const resolvedTenantId = record.tenantId || null\n setTenantId(resolvedTenantId)\n const baseTree = await loadParentTree(resolvedTenantId, record.descendantIds ?? [])\n const fullTree = buildOrganizationTreeOptions(baseTree)\n const nodeMap = new Map(fullTree.map((opt) => [opt.value, opt]))\n const childrenDetails = record.childIds\n .map((id) => nodeMap.get(id))\n .filter((node): node is OrganizationTreeOption => !!node)\n setChildSummary(childrenDetails)\n setOriginalChildIds(Array.isArray(record.childIds) ? record.childIds : [])\n\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n parentId: record.parentId || '',\n isActive: record.isActive,\n tenantId: resolvedTenantId,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customValues,\n })\n setPathLabel(record.pathLabel)\n } catch (err: unknown) {\n if (!cancelled) {\n const fallback = t('directory.organizations.form.errors.load', 'Failed to load organization')\n const message = err instanceof Error && err.message ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) {\n skipTenantEffectRef.current = false\n setLoading(false)\n }\n }\n }\n load()\n return () => { cancelled = true }\n }, [loadParentTree, orgId, t])\n\n React.useEffect(() => {\n if (!actorIsSuperAdmin) return\n if (skipTenantEffectRef.current) {\n skipTenantEffectRef.current = false\n return\n }\n if (!orgId) return\n if (!tenantId) {\n setParentTree([])\n setChildSummary([])\n setOriginalChildIds([])\n return\n }\n void loadParentTree(tenantId, [])\n setChildSummary([])\n setOriginalChildIds([])\n }, [actorIsSuperAdmin, loadParentTree, orgId, tenantId])\n\n const fields = React.useMemo<CrudField[]>(() => [\n ...(actorIsSuperAdmin ? [\n {\n id: 'tenantId',\n label: t('directory.organizations.form.field.tenant', 'Tenant'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <TenantSelect\n id=\"tenantId\"\n value={typeof value === 'string' ? value : tenantId}\n onChange={(next) => {\n const normalized = next ?? null\n setTenantId(normalized)\n setValue(normalized)\n }}\n includeEmptyOption={false}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n } as CrudField,\n ] : []),\n { id: 'name', label: t('directory.organizations.form.field.name', 'Name'), type: 'text', required: true },\n {\n id: 'slug',\n label: t('directory.organizations.form.field.slug', 'Slug'),\n type: 'text',\n description: t('directory.organizations.form.field.slug.description', 'URL-safe identifier used for the customer portal (lowercase letters, numbers, hyphens, underscores).'),\n },\n {\n id: 'parentId',\n label: t('directory.organizations.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <OrganizationSelect\n id={id}\n value={value ? String(value) : null}\n onChange={(next) => setValue(next ?? '')}\n nodes={parentTree}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.rootOption', '\u2014 Root level \u2014')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'childrenInfo',\n label: t('directory.organizations.form.field.children', 'Children'),\n type: 'custom',\n component: () => {\n if (!childSummary.length) {\n return <p className=\"text-xs text-muted-foreground\">{t('directory.organizations.form.children.empty', 'No direct children assigned.')}</p>\n }\n return (\n <ul className=\"space-y-1 text-sm\">\n {childSummary.map((child) => (\n <li key={child.value} className=\"leading-none\">\n <span style={{ paddingLeft: child.depth > 0 ? TREE_PADDING + (child.depth - 1) * TREE_STEP : 0 }}>\n {child.depth > 0 ? <span className=\"text-muted-foreground\">\u21B3 </span> : null}\n {child.name}\n </span>\n </li>\n ))}\n </ul>\n )\n },\n },\n { id: 'isActive', label: t('directory.organizations.form.field.isActive', 'Active'), type: 'checkbox' },\n ], [actorIsSuperAdmin, childSummary, parentTree, t, tenantId])\n\n const detailFields = React.useMemo(() => (\n actorIsSuperAdmin\n ? ['tenantId', 'name', 'slug', 'parentId', 'childrenInfo', 'isActive']\n : ['name', 'slug', 'parentId', 'childrenInfo', 'isActive']\n ), [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('directory.organizations.form.group.details', 'Details'), column: 1, fields: detailFields },\n { id: 'custom', title: t('directory.organizations.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n ]), [detailFields, t])\n\n if (!orgId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('directory.organizations.form.errors.missingId', 'Organization identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('directory.organizations.form.errors.notFound', 'Organization not found')}\n backHref=\"/backend/directory/organizations\"\n backLabel={t('directory.organizations.form.actions.backToList', 'Back to organizations')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('directory.organizations.form.title.edit', 'Edit Organization')}\n backHref=\"/backend/directory/organizations\"\n versionHistory={{ resourceKind: 'directory.organization', resourceId: orgId ? String(orgId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.directory.organization}\n initialValues={initialValues ?? { id: orgId, tenantId: tenantId ?? null, name: '', slug: '', parentId: '', isActive: true, childIds: [] }}\n optimisticLockUpdatedAt={typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null}\n isLoading={loading}\n loadingMessage={t('directory.organizations.form.loading', 'Loading organization...')}\n submitLabel={t('directory.organizations.form.action.save', 'Save')}\n cancelHref=\"/backend/directory/organizations\"\n successRedirect={`/backend/directory/organizations?flash=${encodeURIComponent(t('directory.organizations.flash.updated', 'Organization updated'))}&type=success`}\n extraActions={pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('directory.organizations.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n onSubmit={async (values) => {\n await submitUpdateOrganization({\n values: values as Record<string, unknown>,\n orgId: orgId ?? '',\n tenantId,\n originalChildIds,\n messages: {\n orgIdRequired: t('directory.organizations.errors.orgIdRequired', 'Organization identifier is required'),\n },\n })\n }}\n onDelete={async () => {\n await deleteCrud('directory/organizations', orgId ?? '', {\n errorMessage: t('directory.organizations.errors.deleteFailed', 'Failed to delete organization'),\n })\n }}\n deleteRedirect={`/backend/directory/organizations?flash=${encodeURIComponent(t('directory.organizations.flash.deleted', 'Organization deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype UpdateOrganizationPayload = {\n id: string\n name: string\n slug?: string | null\n isActive: boolean\n parentId: string | null\n childIds: string[]\n tenantId?: string | null\n customFields?: Record<string, unknown>\n}\n\ntype UpdateOrganizationRequest = (payload: UpdateOrganizationPayload) => Promise<void>\n\nconst defaultUpdateOrganizationRequest: UpdateOrganizationRequest = async (payload) => {\n await updateCrud('directory/organizations', payload)\n}\n\nexport async function submitUpdateOrganization(options: {\n values: Record<string, unknown>\n orgId: string\n tenantId: string | null\n originalChildIds: string[]\n updateOrganization?: UpdateOrganizationRequest\n messages?: {\n orgIdRequired?: string\n }\n}): Promise<void> {\n const {\n values,\n orgId,\n tenantId,\n originalChildIds,\n updateOrganization = defaultUpdateOrganizationRequest,\n messages,\n } = options\n\n const payloadId = typeof values.id === 'string' && values.id.length ? values.id : orgId\n if (!payloadId) {\n const message = messages?.orgIdRequired ?? 'Organization identifier is required'\n throw createCrudFormError(message, { id: message })\n }\n\n const customFields = collectCustomFieldValues(values)\n\n const submittedTenantId =\n typeof values.tenantId === 'string' && values.tenantId.trim().length\n ? values.tenantId.trim()\n : tenantId\n\n const payload: UpdateOrganizationPayload = {\n id: payloadId,\n name: typeof values.name === 'string' ? values.name : '',\n isActive: values.isActive !== false,\n parentId:\n typeof values.parentId === 'string' && values.parentId.length\n ? values.parentId\n : null,\n childIds: originalChildIds,\n }\n\n if (typeof values.slug === 'string') {\n const trimmedSlug = values.slug.trim()\n payload.slug = trimmedSlug.length ? trimmedSlug : null\n }\n\n if (submittedTenantId !== undefined && submittedTenantId !== null) {\n payload.tenantId = submittedTenantId\n }\n if (Object.keys(customFields).length > 0) {\n payload.customFields = customFields\n }\n\n await updateOrganization(payload)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { E } from '#generated/entities.ids.generated'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport {\n buildOrganizationTreeOptions,\n type OrganizationTreeNode,\n type OrganizationTreeOption,\n} from '@open-mercato/core/modules/directory/lib/tree'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\n\ntype TreeResponse = {\n items: OrganizationTreeNode[]\n}\n\ntype OrganizationResponse = {\n items: Array<{\n id: string\n name: string\n slug?: string | null\n tenantId: string\n tenantName?: string | null\n parentId: string | null\n childIds: string[]\n ancestorIds: string[]\n descendantIds: string[]\n isActive: boolean\n pathLabel: string\n updatedAt?: string | null\n updated_at?: string | null\n } & Record<string, unknown>>\n}\n\nconst TREE_STEP = 16\nconst TREE_PADDING = 12\n\nexport default function EditOrganizationPage({ params }: { params?: { id?: string } }) {\n const orgId = params?.id\n const t = useT()\n const pathname = usePathname()\n const [initialValues, setInitialValues] = React.useState<Record<string, unknown> | null>(null)\n const [pathLabel, setPathLabel] = React.useState<string>('')\n const [tenantId, setTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [parentTree, setParentTree] = React.useState<OrganizationTreeNode[]>([])\n const [childSummary, setChildSummary] = React.useState<OrganizationTreeOption[]>([])\n const [originalChildIds, setOriginalChildIds] = React.useState<string[]>([])\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const skipTenantEffectRef = React.useRef(true)\n\n React.useEffect(() => {\n let cancelled = false\n async function loadActor() {\n try {\n const { ok, result } = await apiCall<{ isSuperAdmin?: boolean }>('/api/auth/roles?page=1&pageSize=1')\n if (!cancelled && ok) setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n } catch {\n if (!cancelled) setActorIsSuperAdmin(false)\n }\n }\n loadActor()\n return () => { cancelled = true }\n }, [])\n\n const markSelectable = React.useCallback((nodes: OrganizationTreeNode[], excluded: Set<string>): OrganizationTreeNode[] => (\n nodes.map((node) => ({\n ...node,\n selectable: !excluded.has(node.id),\n children: Array.isArray(node.children) ? markSelectable(node.children, excluded) : [],\n }))\n ), [])\n\n const loadParentTree = React.useCallback(async (\n targetTenantId: string | null,\n excludedIds: Iterable<string>,\n ): Promise<OrganizationTreeNode[]> => {\n const treeParams = new URLSearchParams({ view: 'tree', includeInactive: 'true' })\n if (targetTenantId) treeParams.set('tenantId', targetTenantId)\n if (orgId) treeParams.set('ids', orgId)\n try {\n const { ok, result } = await apiCall<TreeResponse>(`/api/directory/organizations?${treeParams.toString()}`)\n if (!ok) {\n setParentTree([])\n return []\n }\n const baseTree = Array.isArray(result?.items) ? result.items ?? [] : []\n const excludedSet = new Set<string>(excludedIds)\n if (orgId) excludedSet.add(orgId)\n setParentTree(markSelectable(baseTree, excludedSet))\n return baseTree\n } catch {\n setParentTree([])\n return []\n }\n }, [markSelectable, orgId])\n\n React.useEffect(() => {\n if (!orgId) return\n const currentOrgId = orgId\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const { ok, status, result } = await apiCall<OrganizationResponse>(\n `/api/directory/organizations?view=manage&ids=${currentOrgId}&status=all&includeInactive=true&page=1&pageSize=1`,\n )\n if (!ok) {\n if (status === 404) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n throw new Error(t('directory.organizations.form.errors.load', 'Failed to load organization'))\n }\n const record = Array.isArray(result?.items) ? result.items?.[0] : undefined\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const resolvedTenantId = record.tenantId || null\n setTenantId(resolvedTenantId)\n const baseTree = await loadParentTree(resolvedTenantId, record.descendantIds ?? [])\n const fullTree = buildOrganizationTreeOptions(baseTree)\n const nodeMap = new Map(fullTree.map((opt) => [opt.value, opt]))\n const childrenDetails = record.childIds\n .map((id) => nodeMap.get(id))\n .filter((node): node is OrganizationTreeOption => !!node)\n setChildSummary(childrenDetails)\n setOriginalChildIds(Array.isArray(record.childIds) ? record.childIds : [])\n\n const customValues = extractCustomFieldEntries(record as Record<string, unknown>)\n setInitialValues({\n id: record.id,\n name: record.name,\n slug: record.slug ?? '',\n parentId: record.parentId || '',\n isActive: record.isActive,\n tenantId: resolvedTenantId,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customValues,\n })\n setPathLabel(record.pathLabel)\n } catch (err: unknown) {\n if (!cancelled) {\n const fallback = t('directory.organizations.form.errors.load', 'Failed to load organization')\n const message = err instanceof Error && err.message ? err.message : fallback\n setError(message)\n }\n } finally {\n if (!cancelled) {\n skipTenantEffectRef.current = false\n setLoading(false)\n }\n }\n }\n load()\n return () => { cancelled = true }\n }, [loadParentTree, orgId, t])\n\n React.useEffect(() => {\n if (!actorIsSuperAdmin) return\n if (skipTenantEffectRef.current) {\n skipTenantEffectRef.current = false\n return\n }\n if (!orgId) return\n if (!tenantId) {\n setParentTree([])\n setChildSummary([])\n setOriginalChildIds([])\n return\n }\n void loadParentTree(tenantId, [])\n setChildSummary([])\n setOriginalChildIds([])\n }, [actorIsSuperAdmin, loadParentTree, orgId, tenantId])\n\n const fields = React.useMemo<CrudField[]>(() => [\n ...(actorIsSuperAdmin ? [\n {\n id: 'tenantId',\n label: t('directory.organizations.form.field.tenant', 'Tenant'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <TenantSelect\n id=\"tenantId\"\n value={typeof value === 'string' ? value : tenantId}\n onChange={(next) => {\n const normalized = next ?? null\n setTenantId(normalized)\n setValue(normalized)\n }}\n includeEmptyOption={false}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n } as CrudField,\n ] : []),\n { id: 'name', label: t('directory.organizations.form.field.name', 'Name'), type: 'text', required: true },\n {\n id: 'slug',\n label: t('directory.organizations.form.field.slug', 'Slug'),\n type: 'text',\n description: t('directory.organizations.form.field.slug.description', 'URL-safe identifier used for the customer portal (lowercase letters, numbers, hyphens, underscores).'),\n },\n {\n id: 'parentId',\n label: t('directory.organizations.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <OrganizationSelect\n id={id}\n value={value ? String(value) : null}\n onChange={(next) => setValue(next ?? '')}\n nodes={parentTree}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.rootOption', '\u2014 Root level \u2014')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'childrenInfo',\n label: t('directory.organizations.form.field.children', 'Children'),\n type: 'custom',\n component: () => {\n if (!childSummary.length) {\n return <p className=\"text-xs text-muted-foreground\">{t('directory.organizations.form.children.empty', 'No direct children assigned.')}</p>\n }\n return (\n <ul className=\"space-y-1 text-sm\">\n {childSummary.map((child) => (\n <li key={child.value} className=\"leading-none\">\n <span style={{ paddingLeft: child.depth > 0 ? TREE_PADDING + (child.depth - 1) * TREE_STEP : 0 }}>\n {child.depth > 0 ? <span className=\"text-muted-foreground\">\u21B3 </span> : null}\n {child.name}\n </span>\n </li>\n ))}\n </ul>\n )\n },\n },\n { id: 'isActive', label: t('directory.organizations.form.field.isActive', 'Active'), type: 'checkbox' },\n ], [actorIsSuperAdmin, childSummary, parentTree, t, tenantId])\n\n const detailFields = React.useMemo(() => (\n actorIsSuperAdmin\n ? ['tenantId', 'name', 'slug', 'parentId', 'childrenInfo', 'isActive']\n : ['name', 'slug', 'parentId', 'childrenInfo', 'isActive']\n ), [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('directory.organizations.form.group.details', 'Details'), column: 1, fields: detailFields },\n { id: 'custom', title: t('directory.organizations.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n ]), [detailFields, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `directory.organization` + id\n // explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held\n // lock matches the save-time conflict surface for the same organization.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'directory.organization',\n resourceId: orgId || null,\n updatedAt: typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null,\n data: initialValues,\n path: pathname,\n }),\n )\n\n if (!orgId) {\n return (\n <Page>\n <PageBody>\n <div className=\"rounded border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive\">\n {t('directory.organizations.form.errors.missingId', 'Organization identifier is missing.')}\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('directory.organizations.form.errors.notFound', 'Organization not found')}\n backHref=\"/backend/directory/organizations\"\n backLabel={t('directory.organizations.form.actions.backToList', 'Back to organizations')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('directory.organizations.form.title.edit', 'Edit Organization')}\n backHref=\"/backend/directory/organizations\"\n versionHistory={{ resourceKind: 'directory.organization', resourceId: orgId ? String(orgId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.directory.organization}\n initialValues={initialValues ?? { id: orgId, tenantId: tenantId ?? null, name: '', slug: '', parentId: '', isActive: true, childIds: [] }}\n optimisticLockUpdatedAt={typeof initialValues?.updatedAt === 'string' ? initialValues.updatedAt : null}\n isLoading={loading}\n loadingMessage={t('directory.organizations.form.loading', 'Loading organization...')}\n submitLabel={t('directory.organizations.form.action.save', 'Save')}\n cancelHref=\"/backend/directory/organizations\"\n successRedirect={`/backend/directory/organizations?flash=${encodeURIComponent(t('directory.organizations.flash.updated', 'Organization updated'))}&type=success`}\n extraActions={pathLabel ? (\n <span className=\"text-xs text-muted-foreground\">\n {t('directory.organizations.form.pathLabel', { path: pathLabel })}\n </span>\n ) : null}\n onSubmit={async (values) => {\n await submitUpdateOrganization({\n values: values as Record<string, unknown>,\n orgId: orgId ?? '',\n tenantId,\n originalChildIds,\n messages: {\n orgIdRequired: t('directory.organizations.errors.orgIdRequired', 'Organization identifier is required'),\n },\n })\n }}\n onDelete={async () => {\n await deleteCrud('directory/organizations', orgId ?? '', {\n errorMessage: t('directory.organizations.errors.deleteFailed', 'Failed to delete organization'),\n })\n }}\n deleteRedirect={`/backend/directory/organizations?flash=${encodeURIComponent(t('directory.organizations.flash.deleted', 'Organization deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype UpdateOrganizationPayload = {\n id: string\n name: string\n slug?: string | null\n isActive: boolean\n parentId: string | null\n childIds: string[]\n tenantId?: string | null\n customFields?: Record<string, unknown>\n}\n\ntype UpdateOrganizationRequest = (payload: UpdateOrganizationPayload) => Promise<void>\n\nconst defaultUpdateOrganizationRequest: UpdateOrganizationRequest = async (payload) => {\n await updateCrud('directory/organizations', payload)\n}\n\nexport async function submitUpdateOrganization(options: {\n values: Record<string, unknown>\n orgId: string\n tenantId: string | null\n originalChildIds: string[]\n updateOrganization?: UpdateOrganizationRequest\n messages?: {\n orgIdRequired?: string\n }\n}): Promise<void> {\n const {\n values,\n orgId,\n tenantId,\n originalChildIds,\n updateOrganization = defaultUpdateOrganizationRequest,\n messages,\n } = options\n\n const payloadId = typeof values.id === 'string' && values.id.length ? values.id : orgId\n if (!payloadId) {\n const message = messages?.orgIdRequired ?? 'Organization identifier is required'\n throw createCrudFormError(message, { id: message })\n }\n\n const customFields = collectCustomFieldValues(values)\n\n const submittedTenantId =\n typeof values.tenantId === 'string' && values.tenantId.trim().length\n ? values.tenantId.trim()\n : tenantId\n\n const payload: UpdateOrganizationPayload = {\n id: payloadId,\n name: typeof values.name === 'string' ? values.name : '',\n isActive: values.isActive !== false,\n parentId:\n typeof values.parentId === 'string' && values.parentId.length\n ? values.parentId\n : null,\n childIds: originalChildIds,\n }\n\n if (typeof values.slug === 'string') {\n const trimmedSlug = values.slug.trim()\n payload.slug = trimmedSlug.length ? trimmedSlug : null\n }\n\n if (submittedTenantId !== undefined && submittedTenantId !== null) {\n payload.tenantId = submittedTenantId\n }\n if (Object.keys(customFields).length > 0) {\n payload.customFields = customFields\n }\n\n await updateOrganization(payload)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
+ import { usePathname } from "next/navigation";
4
5
  import { E } from "../../../../../../../generated/entities.ids.generated.js";
5
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
6
7
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
@@ -10,10 +11,12 @@ import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
10
11
  import { readApiResultOrThrow, apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
11
12
  import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
12
13
  import { ErrorMessage, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
14
+ import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from "@open-mercato/ui/backend/injection/recordContext";
13
15
  import { useT } from "@open-mercato/shared/lib/i18n/context";
14
16
  import { extractCustomFieldEntries } from "@open-mercato/shared/lib/crud/custom-fields-client";
15
17
  function EditTenantPage({ params }) {
16
18
  const tenantId = params?.id;
19
+ const pathname = usePathname();
17
20
  const [initial, setInitial] = React.useState(null);
18
21
  const [loading, setLoading] = React.useState(true);
19
22
  const [error, setError] = React.useState(null);
@@ -73,6 +76,15 @@ function EditTenantPage({ params }) {
73
76
  cancelled = true;
74
77
  };
75
78
  }, [tenantId, t]);
79
+ useSetCurrentRecordInjectionContext(
80
+ buildRecordInjectionContext({
81
+ resourceKind: "directory.tenant",
82
+ resourceId: tenantId || null,
83
+ updatedAt: initial?.updatedAt ?? null,
84
+ data: initial,
85
+ path: pathname
86
+ })
87
+ );
76
88
  if (!tenantId) return null;
77
89
  if (isNotFound) {
78
90
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/directory/backend/directory/tenants/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { readApiResultOrThrow, apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\n\ntype TenantFormValues = {\n id: string\n name: string\n isActive: boolean\n updatedAt?: string | null\n} & Record<string, unknown>\n\nexport default function EditTenantPage({ params }: { params?: { id?: string } }) {\n const tenantId = params?.id\n const [initial, setInitial] = React.useState<TenantFormValues | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const t = useT()\n const fields = React.useMemo<CrudField[]>(() => [\n { id: 'name', label: t('directory.tenants.form.fields.name', 'Name'), type: 'text', required: true },\n { id: 'isActive', label: t('directory.tenants.form.fields.active', 'Active'), type: 'checkbox' },\n ], [t])\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n { id: 'details', title: t('directory.tenants.form.groups.details', 'Details'), column: 1, fields: ['name', 'isActive'] },\n { id: 'custom', title: t('directory.tenants.form.groups.custom', 'Custom Data'), column: 2, kind: 'customFields' },\n ], [t])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n if (!tenantId) return\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const data = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/directory/tenants?id=${encodeURIComponent(tenantId)}`,\n undefined,\n { errorMessage: t('directory.tenants.form.errors.load', 'Failed to load tenant'), fallback: { items: [] } },\n )\n const rows = Array.isArray(data?.items) ? data.items : []\n const row = rows[0]\n if (!row) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const cfValues = extractCustomFieldEntries(row as Record<string, unknown>)\n const values: TenantFormValues = {\n id: String(row.id),\n name: String(row.name),\n isActive: !!row.isActive,\n updatedAt: typeof row.updatedAt === 'string'\n ? row.updatedAt\n : typeof row.updated_at === 'string'\n ? row.updated_at\n : null,\n ...cfValues,\n }\n if (!cancelled) setInitial(values)\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('directory.tenants.form.errors.load', 'Failed to load tenant')\n setError(message)\n }\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [tenantId, t])\n\n if (!tenantId) return null\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('directory.tenants.form.errors.notFound', 'Tenant not found')}\n backHref=\"/backend/directory/tenants\"\n backLabel={t('directory.tenants.form.actions.backToList', 'Back to tenants')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading && !initial) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<TenantFormValues>\n title={t('directory.tenants.form.title.edit', 'Edit Tenant')}\n backHref=\"/backend/directory/tenants\"\n versionHistory={{ resourceKind: 'directory.tenant', resourceId: tenantId ? String(tenantId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.directory.tenant}\n initialValues={(initial || { id: tenantId, name: '', isActive: true }) as Partial<TenantFormValues>}\n optimisticLockUpdatedAt={initial?.updatedAt}\n isLoading={loading}\n loadingMessage={t('directory.tenants.form.loading', 'Loading tenant\u2026')}\n submitLabel={t('common.save', 'Save')}\n cancelHref=\"/backend/directory/tenants\"\n successRedirect=\"/backend/directory/tenants?flash=Tenant%20updated&type=success\"\n onSubmit={async (values) => {\n const customFields = collectCustomFieldValues(values)\n const payload: {\n id: string\n name: string\n isActive: boolean\n customFields?: Record<string, unknown>\n } = {\n id: values.id || tenantId,\n name: values.name,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) {\n payload.customFields = customFields\n }\n await updateCrud('directory/tenants', payload)\n }}\n onDelete={async () => {\n const headers = buildOptimisticLockHeader(initial?.updatedAt)\n const call = await withScopedApiRequestHeaders(headers, () => (\n apiCall(\n `/api/directory/tenants?id=${encodeURIComponent(tenantId)}`,\n { method: 'DELETE' },\n )\n ))\n if (!call.ok) {\n await raiseCrudError(call.response, t('directory.tenants.form.errors.delete', 'Failed to delete tenant'))\n }\n }}\n deleteRedirect=\"/backend/directory/tenants?flash=Tenant%20deleted&type=success\"\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { readApiResultOrThrow, apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\n\ntype TenantFormValues = {\n id: string\n name: string\n isActive: boolean\n updatedAt?: string | null\n} & Record<string, unknown>\n\nexport default function EditTenantPage({ params }: { params?: { id?: string } }) {\n const tenantId = params?.id\n const pathname = usePathname()\n const [initial, setInitial] = React.useState<TenantFormValues | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const t = useT()\n const fields = React.useMemo<CrudField[]>(() => [\n { id: 'name', label: t('directory.tenants.form.fields.name', 'Name'), type: 'text', required: true },\n { id: 'isActive', label: t('directory.tenants.form.fields.active', 'Active'), type: 'checkbox' },\n ], [t])\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n { id: 'details', title: t('directory.tenants.form.groups.details', 'Details'), column: 1, fields: ['name', 'isActive'] },\n { id: 'custom', title: t('directory.tenants.form.groups.custom', 'Custom Data'), column: 2, kind: 'customFields' },\n ], [t])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n if (!tenantId) return\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n try {\n const data = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/directory/tenants?id=${encodeURIComponent(tenantId)}`,\n undefined,\n { errorMessage: t('directory.tenants.form.errors.load', 'Failed to load tenant'), fallback: { items: [] } },\n )\n const rows = Array.isArray(data?.items) ? data.items : []\n const row = rows[0]\n if (!row) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const cfValues = extractCustomFieldEntries(row as Record<string, unknown>)\n const values: TenantFormValues = {\n id: String(row.id),\n name: String(row.name),\n isActive: !!row.isActive,\n updatedAt: typeof row.updatedAt === 'string'\n ? row.updatedAt\n : typeof row.updated_at === 'string'\n ? row.updated_at\n : null,\n ...cfValues,\n }\n if (!cancelled) setInitial(values)\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('directory.tenants.form.errors.load', 'Failed to load tenant')\n setError(message)\n }\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [tenantId, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `directory.tenant` + id\n // explicitly. The resourceKind mirrors the CrudForm `versionHistory` so the held\n // lock matches the save-time conflict surface for the same tenant.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'directory.tenant',\n resourceId: tenantId || null,\n updatedAt: initial?.updatedAt ?? null,\n data: initial as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (!tenantId) return null\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('directory.tenants.form.errors.notFound', 'Tenant not found')}\n backHref=\"/backend/directory/tenants\"\n backLabel={t('directory.tenants.form.actions.backToList', 'Back to tenants')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading && !initial) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<TenantFormValues>\n title={t('directory.tenants.form.title.edit', 'Edit Tenant')}\n backHref=\"/backend/directory/tenants\"\n versionHistory={{ resourceKind: 'directory.tenant', resourceId: tenantId ? String(tenantId) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.directory.tenant}\n initialValues={(initial || { id: tenantId, name: '', isActive: true }) as Partial<TenantFormValues>}\n optimisticLockUpdatedAt={initial?.updatedAt}\n isLoading={loading}\n loadingMessage={t('directory.tenants.form.loading', 'Loading tenant\u2026')}\n submitLabel={t('common.save', 'Save')}\n cancelHref=\"/backend/directory/tenants\"\n successRedirect=\"/backend/directory/tenants?flash=Tenant%20updated&type=success\"\n onSubmit={async (values) => {\n const customFields = collectCustomFieldValues(values)\n const payload: {\n id: string\n name: string\n isActive: boolean\n customFields?: Record<string, unknown>\n } = {\n id: values.id || tenantId,\n name: values.name,\n isActive: values.isActive !== false,\n }\n if (Object.keys(customFields).length > 0) {\n payload.customFields = customFields\n }\n await updateCrud('directory/tenants', payload)\n }}\n onDelete={async () => {\n const headers = buildOptimisticLockHeader(initial?.updatedAt)\n const call = await withScopedApiRequestHeaders(headers, () => (\n apiCall(\n `/api/directory/tenants?id=${encodeURIComponent(tenantId)}`,\n { method: 'DELETE' },\n )\n ))\n if (!call.ok) {\n await raiseCrudError(call.response, t('directory.tenants.form.errors.delete', 'Failed to delete tenant'))\n }\n }}\n deleteRedirect=\"/backend/directory/tenants?flash=Tenant%20deleted&type=success\"\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,7 +7,7 @@ import { getEntityIds } from "@open-mercato/shared/lib/encryption/entityIds";
7
7
  import { upsertCustomEntitySchema } from "@open-mercato/core/modules/entities/data/validators";
8
8
  import { isSystemEntitySelectable } from "@open-mercato/shared/lib/entities/system-entities";
9
9
  import { SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, isOrmBackedSystemEntityId } from "@open-mercato/shared/lib/data/engine";
10
- import { enforceCommandOptimisticLock } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
10
+ import { enforceCommandOptimisticLockWithGuards } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
11
11
  import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
12
12
  import {
13
13
  beginEntitiesMutationGuard,
@@ -110,7 +110,7 @@ async function POST(req) {
110
110
  let ent = await em.findOne(CustomEntity, where);
111
111
  if (ent) {
112
112
  try {
113
- enforceCommandOptimisticLock({
113
+ await enforceCommandOptimisticLockWithGuards(container, {
114
114
  resourceKind: CUSTOM_ENTITY_DEFINITION_RESOURCE_KIND,
115
115
  resourceId: ent.id,
116
116
  current: ent.updatedAt ?? null,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/entities/api/entities.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { CustomEntity, CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { upsertCustomEntitySchema } from '@open-mercato/core/modules/entities/data/validators'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { isSystemEntitySelectable } from '@open-mercato/shared/lib/entities/system-entities'\nimport { SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, isOrmBackedSystemEntityId } from '@open-mercato/shared/lib/data/engine'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n beginEntitiesMutationGuard,\n ENTITY_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\n\nconst CUSTOM_ENTITY_DEFINITION_RESOURCE_KIND = ENTITY_DEFINITION_RESOURCE_KIND\n\nexport const metadata = {\n GET: { requireAuth: true },\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId || (!auth.orgId && !auth.isSuperAdmin)) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n\n // Generated entities from code\n const AllEntities = getEntityIds()\n const generated: { entityId: string; source: 'code'; label: string }[] = []\n for (const modId of Object.keys(AllEntities)) {\n const entities = (AllEntities as any)[modId] as Record<string, string>\n for (const k of Object.keys(entities)) {\n const id = entities[k]\n if (!isSystemEntitySelectable(id)) continue\n generated.push({ entityId: id, source: 'code', label: id })\n }\n }\n\n // Custom user-defined entities (global/org/tenant scoped)\n const where: any = { isActive: true }\n where.$and = [\n { $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] },\n { $or: [ { tenantId: auth.tenantId ?? undefined as any }, { tenantId: null } ] },\n ]\n const customs = await em.find(CustomEntity as any, where as any, { orderBy: { entityId: 'asc' } as any })\n // Resolve overlay precedence: prefer organization/tenant-specific over global\n const customByEntityId = new Map<string, any>()\n for (const c of customs as any[]) {\n const specificity = (c.organizationId ? 2 : 0) + (c.tenantId ? 1 : 0)\n const prev = customByEntityId.get(c.entityId)\n const prevSpec = prev ? ((prev.organizationId ? 2 : 0) + (prev.tenantId ? 1 : 0)) : -1\n if (!prev || specificity > prevSpec) customByEntityId.set(c.entityId, c)\n }\n\n const custom = Array.from(customByEntityId.values())\n .filter((c) => isSystemEntitySelectable(c.entityId))\n .map((c) => ({\n entityId: c.entityId,\n source: 'custom' as const,\n label: c.label,\n description: c.description ?? undefined,\n labelField: (c as any).labelField ?? undefined,\n defaultEditor: (c as any).defaultEditor ?? undefined,\n showInSidebar: (c as any).showInSidebar ?? false,\n updatedAt: c.updatedAt instanceof Date ? c.updatedAt.toISOString() : (c.updatedAt ?? undefined),\n }))\n\n const byId = new Map<string, any>()\n for (const g of generated) byId.set(g.entityId, g)\n for (const cu of custom) {\n const existing = byId.get(cu.entityId)\n byId.set(cu.entityId, { ...existing, ...cu, source: existing?.source ?? cu.source })\n }\n\n // Count field definitions scoped to current tenant/org (same scoping as custom entities)\n const defsWhere: any = { isActive: true }\n defsWhere.$and = [\n //{ $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] }, // the entities and custom fields are defined per tenant\n { tenantId: auth.tenantId ?? undefined as any },\n ]\n const defs = await em.find(CustomFieldDef as any, defsWhere as any)\n // Count distinct field names (keys) per entityId\n const keySets = new Map<string, Set<string>>()\n for (const d of defs as any[]) {\n const eid = String(d.entityId)\n const k = String(d.key)\n if (!isSystemEntitySelectable(eid)) continue\n const set = keySets.get(eid) || new Set<string>()\n set.add(k)\n keySets.set(eid, set)\n }\n const counts: Record<string, number> = {}\n for (const [eid, set] of keySets.entries()) counts[eid] = set.size\n\n const items = Array.from(byId.values()).map((it: any) => ({ ...it, count: counts[it.entityId] || 0 }))\n return NextResponse.json({ items })\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = upsertCustomEntitySchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n }\n const input = parsed.data\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n\n // A registration for a module-declared, table-backed system entity would flip\n // query-engine classification to doc storage for the whole entity type (#2939's\n // failure mode via another door) \u2014 refuse to create one.\n if (isOrmBackedSystemEntityId(em, input.entityId)) {\n return NextResponse.json(\n { error: 'System entities cannot be registered as custom entities', code: SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, entityId: input.entityId },\n { status: 400 },\n )\n }\n\n const where: any = { entityId: input.entityId, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n let ent = await em.findOne(CustomEntity, where)\n if (ent) {\n try {\n enforceCommandOptimisticLock({\n resourceKind: CUSTOM_ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent.id,\n current: ent.updatedAt ?? null,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n }\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent ? ent.id : input.entityId,\n operation: ent ? 'update' : 'create',\n mutationPayload: input as unknown as Record<string, unknown>,\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n if (!ent) ent = em.create(CustomEntity, { ...where, createdAt: new Date() })\n ent.label = input.label\n ent.description = input.description ?? null\n ent.isActive = input.isActive ?? true\n ent.labelField = input.labelField ?? ent.labelField ?? null\n ent.defaultEditor = input.defaultEditor ?? ent.defaultEditor ?? null\n ent.showInSidebar = input.showInSidebar ?? ent.showInSidebar ?? false\n ent.updatedAt = new Date()\n em.persist(ent)\n await em.flush()\n await guard.runAfterSuccess()\n // Invalidate sidebar/nav cache for tenant scope (also when tenantId is null)\n try {\n const cache = (await createRequestContainer()).resolve('cache') as any\n if (cache) {\n await cache.deleteByTags([`nav:entities:${auth.tenantId || 'null'}`])\n }\n } catch {}\n return NextResponse.json({ ok: true, item: { id: ent.id, entityId: ent.entityId, label: ent.label, description: ent.description ?? undefined } })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const entityId = body?.entityId\n if (!entityId) return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n\n const where: any = { entityId, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n const ent = await em.findOne(CustomEntity, where)\n if (!ent) return NextResponse.json({ error: 'Not found' }, { status: 404 })\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent.id,\n operation: 'delete',\n mutationPayload: { entityId },\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n ent.isActive = false\n ent.updatedAt = new Date()\n ent.deletedAt = ent.deletedAt ?? new Date()\n em.persist(ent)\n await em.flush()\n await guard.runAfterSuccess()\n // Invalidate sidebar/nav cache for tenant scope (also when tenantId is null)\n try {\n const cache = (await createRequestContainer()).resolve('cache') as any\n if (cache) {\n await cache.deleteByTags([`nav:entities:${auth.tenantId || 'null'}`])\n }\n } catch {}\n return NextResponse.json({ ok: true })\n}\n\nconst entitySummarySchema = z.object({\n entityId: z.string(),\n source: z.enum(['code', 'custom']),\n label: z.string(),\n description: z.string().optional(),\n labelField: z.string().optional(),\n defaultEditor: z.string().optional(),\n showInSidebar: z.boolean().optional(),\n updatedAt: z.string().optional(),\n count: z.number(),\n})\n\nconst entityListResponseSchema = z.object({\n items: z.array(entitySummarySchema),\n})\n\nconst deleteEntityRequestSchema = z.object({\n entityId: z.string(),\n})\n\nconst upsertCustomEntityResponseSchema = z.object({\n ok: z.literal(true),\n item: z.object({\n id: z.string().uuid(),\n entityId: z.string(),\n label: z.string(),\n description: z.string().optional(),\n }),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'Manage custom entities',\n methods: {\n GET: {\n summary: 'List available entities',\n description: 'Returns generated and custom entities scoped to the caller with field counts per entity.',\n responses: [\n {\n status: 200,\n description: 'List of entities',\n schema: entityListResponseSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Upsert custom entity',\n description: 'Creates or updates a tenant/org scoped custom entity definition.',\n requestBody: {\n contentType: 'application/json',\n schema: upsertCustomEntitySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Entity saved',\n schema: upsertCustomEntityResponseSchema,\n },\n {\n status: 400,\n description: 'Validation error',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n DELETE: {\n summary: 'Soft delete custom entity',\n description: 'Marks the specified custom entity inactive within the current scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteEntityRequestSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Entity deleted',\n schema: z.object({ ok: z.boolean() }),\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Entity not found in scope',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { CustomEntity, CustomFieldDef } from '@open-mercato/core/modules/entities/data/entities'\nimport { getEntityIds } from '@open-mercato/shared/lib/encryption/entityIds'\nimport { upsertCustomEntitySchema } from '@open-mercato/core/modules/entities/data/validators'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { isSystemEntitySelectable } from '@open-mercato/shared/lib/entities/system-entities'\nimport { SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, isOrmBackedSystemEntityId } from '@open-mercato/shared/lib/data/engine'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n beginEntitiesMutationGuard,\n ENTITY_DEFINITION_RESOURCE_KIND,\n} from './definitions.mutation-guard'\n\nconst CUSTOM_ENTITY_DEFINITION_RESOURCE_KIND = ENTITY_DEFINITION_RESOURCE_KIND\n\nexport const metadata = {\n GET: { requireAuth: true },\n POST: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.definitions.manage'] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId || (!auth.orgId && !auth.isSuperAdmin)) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as any\n\n // Generated entities from code\n const AllEntities = getEntityIds()\n const generated: { entityId: string; source: 'code'; label: string }[] = []\n for (const modId of Object.keys(AllEntities)) {\n const entities = (AllEntities as any)[modId] as Record<string, string>\n for (const k of Object.keys(entities)) {\n const id = entities[k]\n if (!isSystemEntitySelectable(id)) continue\n generated.push({ entityId: id, source: 'code', label: id })\n }\n }\n\n // Custom user-defined entities (global/org/tenant scoped)\n const where: any = { isActive: true }\n where.$and = [\n { $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] },\n { $or: [ { tenantId: auth.tenantId ?? undefined as any }, { tenantId: null } ] },\n ]\n const customs = await em.find(CustomEntity as any, where as any, { orderBy: { entityId: 'asc' } as any })\n // Resolve overlay precedence: prefer organization/tenant-specific over global\n const customByEntityId = new Map<string, any>()\n for (const c of customs as any[]) {\n const specificity = (c.organizationId ? 2 : 0) + (c.tenantId ? 1 : 0)\n const prev = customByEntityId.get(c.entityId)\n const prevSpec = prev ? ((prev.organizationId ? 2 : 0) + (prev.tenantId ? 1 : 0)) : -1\n if (!prev || specificity > prevSpec) customByEntityId.set(c.entityId, c)\n }\n\n const custom = Array.from(customByEntityId.values())\n .filter((c) => isSystemEntitySelectable(c.entityId))\n .map((c) => ({\n entityId: c.entityId,\n source: 'custom' as const,\n label: c.label,\n description: c.description ?? undefined,\n labelField: (c as any).labelField ?? undefined,\n defaultEditor: (c as any).defaultEditor ?? undefined,\n showInSidebar: (c as any).showInSidebar ?? false,\n updatedAt: c.updatedAt instanceof Date ? c.updatedAt.toISOString() : (c.updatedAt ?? undefined),\n }))\n\n const byId = new Map<string, any>()\n for (const g of generated) byId.set(g.entityId, g)\n for (const cu of custom) {\n const existing = byId.get(cu.entityId)\n byId.set(cu.entityId, { ...existing, ...cu, source: existing?.source ?? cu.source })\n }\n\n // Count field definitions scoped to current tenant/org (same scoping as custom entities)\n const defsWhere: any = { isActive: true }\n defsWhere.$and = [\n //{ $or: [ { organizationId: auth.orgId ?? undefined as any }, { organizationId: null } ] }, // the entities and custom fields are defined per tenant\n { tenantId: auth.tenantId ?? undefined as any },\n ]\n const defs = await em.find(CustomFieldDef as any, defsWhere as any)\n // Count distinct field names (keys) per entityId\n const keySets = new Map<string, Set<string>>()\n for (const d of defs as any[]) {\n const eid = String(d.entityId)\n const k = String(d.key)\n if (!isSystemEntitySelectable(eid)) continue\n const set = keySets.get(eid) || new Set<string>()\n set.add(k)\n keySets.set(eid, set)\n }\n const counts: Record<string, number> = {}\n for (const [eid, set] of keySets.entries()) counts[eid] = set.size\n\n const items = Array.from(byId.values()).map((it: any) => ({ ...it, count: counts[it.entityId] || 0 }))\n return NextResponse.json({ items })\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = upsertCustomEntitySchema.safeParse(body)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n }\n const input = parsed.data\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n\n // A registration for a module-declared, table-backed system entity would flip\n // query-engine classification to doc storage for the whole entity type (#2939's\n // failure mode via another door) \u2014 refuse to create one.\n if (isOrmBackedSystemEntityId(em, input.entityId)) {\n return NextResponse.json(\n { error: 'System entities cannot be registered as custom entities', code: SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, entityId: input.entityId },\n { status: 400 },\n )\n }\n\n const where: any = { entityId: input.entityId, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n let ent = await em.findOne(CustomEntity, where)\n if (ent) {\n try {\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: CUSTOM_ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent.id,\n current: ent.updatedAt ?? null,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n }\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent ? ent.id : input.entityId,\n operation: ent ? 'update' : 'create',\n mutationPayload: input as unknown as Record<string, unknown>,\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n if (!ent) ent = em.create(CustomEntity, { ...where, createdAt: new Date() })\n ent.label = input.label\n ent.description = input.description ?? null\n ent.isActive = input.isActive ?? true\n ent.labelField = input.labelField ?? ent.labelField ?? null\n ent.defaultEditor = input.defaultEditor ?? ent.defaultEditor ?? null\n ent.showInSidebar = input.showInSidebar ?? ent.showInSidebar ?? false\n ent.updatedAt = new Date()\n em.persist(ent)\n await em.flush()\n await guard.runAfterSuccess()\n // Invalidate sidebar/nav cache for tenant scope (also when tenantId is null)\n try {\n const cache = (await createRequestContainer()).resolve('cache') as any\n if (cache) {\n await cache.deleteByTags([`nav:entities:${auth.tenantId || 'null'}`])\n }\n } catch {}\n return NextResponse.json({ ok: true, item: { id: ent.id, entityId: ent.entityId, label: ent.label, description: ent.description ?? undefined } })\n}\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.orgId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n let body: any\n try { body = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const entityId = body?.entityId\n if (!entityId) return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n\n const container = await createRequestContainer()\n const { resolve } = container\n const em = resolve('em') as any\n\n const where: any = { entityId, organizationId: auth.orgId ?? null, tenantId: auth.tenantId ?? null }\n const ent = await em.findOne(CustomEntity, where)\n if (!ent) return NextResponse.json({ error: 'Not found' }, { status: 404 })\n\n const guard = await beginEntitiesMutationGuard({\n container,\n auth,\n req,\n resourceKind: ENTITY_DEFINITION_RESOURCE_KIND,\n resourceId: ent.id,\n operation: 'delete',\n mutationPayload: { entityId },\n })\n if (guard.blockedResponse) return guard.blockedResponse\n\n ent.isActive = false\n ent.updatedAt = new Date()\n ent.deletedAt = ent.deletedAt ?? new Date()\n em.persist(ent)\n await em.flush()\n await guard.runAfterSuccess()\n // Invalidate sidebar/nav cache for tenant scope (also when tenantId is null)\n try {\n const cache = (await createRequestContainer()).resolve('cache') as any\n if (cache) {\n await cache.deleteByTags([`nav:entities:${auth.tenantId || 'null'}`])\n }\n } catch {}\n return NextResponse.json({ ok: true })\n}\n\nconst entitySummarySchema = z.object({\n entityId: z.string(),\n source: z.enum(['code', 'custom']),\n label: z.string(),\n description: z.string().optional(),\n labelField: z.string().optional(),\n defaultEditor: z.string().optional(),\n showInSidebar: z.boolean().optional(),\n updatedAt: z.string().optional(),\n count: z.number(),\n})\n\nconst entityListResponseSchema = z.object({\n items: z.array(entitySummarySchema),\n})\n\nconst deleteEntityRequestSchema = z.object({\n entityId: z.string(),\n})\n\nconst upsertCustomEntityResponseSchema = z.object({\n ok: z.literal(true),\n item: z.object({\n id: z.string().uuid(),\n entityId: z.string(),\n label: z.string(),\n description: z.string().optional(),\n }),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'Manage custom entities',\n methods: {\n GET: {\n summary: 'List available entities',\n description: 'Returns generated and custom entities scoped to the caller with field counts per entity.',\n responses: [\n {\n status: 200,\n description: 'List of entities',\n schema: entityListResponseSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n POST: {\n summary: 'Upsert custom entity',\n description: 'Creates or updates a tenant/org scoped custom entity definition.',\n requestBody: {\n contentType: 'application/json',\n schema: upsertCustomEntitySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Entity saved',\n schema: upsertCustomEntityResponseSchema,\n },\n {\n status: 400,\n description: 'Validation error',\n schema: z.object({\n error: z.string(),\n details: z.any().optional(),\n }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n DELETE: {\n summary: 'Soft delete custom entity',\n description: 'Marks the specified custom entity inactive within the current scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteEntityRequestSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Entity deleted',\n schema: z.object({ ok: z.boolean() }),\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: z.object({ error: z.string() }),\n },\n {\n status: 404,\n description: 'Entity not found in scope',\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }