@open-mercato/ui 0.6.7-develop.6860.1.f796b22e80 → 0.6.7

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 (167) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +2 -4
  3. package/agentic/standalone-guide.md +1 -1
  4. package/build.mjs +54 -2
  5. package/dist/ai/AiChat.js +2 -21
  6. package/dist/ai/AiChat.js.map +2 -2
  7. package/dist/backend/AppShell.js +4 -43
  8. package/dist/backend/AppShell.js.map +2 -2
  9. package/dist/backend/AuthSessionGuard.js +0 -14
  10. package/dist/backend/AuthSessionGuard.js.map +2 -2
  11. package/dist/backend/BackendChromeProvider.js +1 -6
  12. package/dist/backend/BackendChromeProvider.js.map +2 -2
  13. package/dist/backend/CrudForm.js +4 -6
  14. package/dist/backend/CrudForm.js.map +2 -2
  15. package/dist/backend/DataTable.js +18 -20
  16. package/dist/backend/DataTable.js.map +2 -2
  17. package/dist/backend/JsonBuilder.js +3 -3
  18. package/dist/backend/JsonBuilder.js.map +2 -2
  19. package/dist/backend/NextStepCallout.js +4 -4
  20. package/dist/backend/NextStepCallout.js.map +1 -1
  21. package/dist/backend/ProfileDropdown.js +1 -2
  22. package/dist/backend/ProfileDropdown.js.map +2 -2
  23. package/dist/backend/RowActions.js +2 -2
  24. package/dist/backend/RowActions.js.map +2 -2
  25. package/dist/backend/confirm-dialog/ConfirmDialog.js +1 -13
  26. package/dist/backend/confirm-dialog/ConfirmDialog.js.map +2 -2
  27. package/dist/backend/crud/useGroupOrder.js +21 -14
  28. package/dist/backend/crud/useGroupOrder.js.map +2 -2
  29. package/dist/backend/detail/AddressTiles.js +5 -4
  30. package/dist/backend/detail/AddressTiles.js.map +2 -2
  31. package/dist/backend/detail/AttachmentDeleteDialog.js +1 -1
  32. package/dist/backend/detail/AttachmentDeleteDialog.js.map +2 -2
  33. package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
  34. package/dist/backend/detail/AttachmentsSection.js +1 -1
  35. package/dist/backend/detail/AttachmentsSection.js.map +2 -2
  36. package/dist/backend/detail/NotesSection.js +1 -1
  37. package/dist/backend/detail/NotesSection.js.map +2 -2
  38. package/dist/backend/detail/TagsSection.js +1 -1
  39. package/dist/backend/detail/TagsSection.js.map +2 -2
  40. package/dist/backend/forms/FormHeader.js +2 -1
  41. package/dist/backend/forms/FormHeader.js.map +2 -2
  42. package/dist/backend/icons/lucideRegistry.generated.js +25 -1
  43. package/dist/backend/icons/lucideRegistry.generated.js.map +2 -2
  44. package/dist/backend/icons/lucideRegistry.js +3 -3
  45. package/dist/backend/icons/lucideRegistry.js.map +2 -2
  46. package/dist/backend/injection/spotIds.js +18 -23
  47. package/dist/backend/injection/spotIds.js.map +2 -2
  48. package/dist/backend/schedule/ScheduleAgenda.js +3 -3
  49. package/dist/backend/schedule/ScheduleAgenda.js.map +1 -1
  50. package/dist/backend/schedule/ScheduleGrid.js +3 -3
  51. package/dist/backend/schedule/ScheduleGrid.js.map +1 -1
  52. package/dist/backend/schedule/ScheduleToolbar.js +70 -87
  53. package/dist/backend/schedule/ScheduleToolbar.js.map +2 -2
  54. package/dist/backend/sidebar/SidebarCustomizationEditor.js +2 -30
  55. package/dist/backend/sidebar/SidebarCustomizationEditor.js.map +2 -2
  56. package/dist/backend/sidebar/customization-helpers.js +0 -30
  57. package/dist/backend/sidebar/customization-helpers.js.map +2 -2
  58. package/dist/backend/utils/api.js +13 -3
  59. package/dist/backend/utils/api.js.map +2 -2
  60. package/dist/backend/utils/apiCall.js +1 -21
  61. package/dist/backend/utils/apiCall.js.map +2 -2
  62. package/dist/backend/utils/customFieldDefs.js.map +2 -2
  63. package/dist/backend/utils/customFieldForms.js +9 -10
  64. package/dist/backend/utils/customFieldForms.js.map +2 -2
  65. package/dist/backend/utils/nav.js +2 -5
  66. package/dist/backend/utils/nav.js.map +2 -2
  67. package/dist/frontend/LanguageSwitcher.js +1 -2
  68. package/dist/frontend/LanguageSwitcher.js.map +2 -2
  69. package/dist/portal/PortalContext.js +1 -1
  70. package/dist/portal/PortalContext.js.map +2 -2
  71. package/dist/portal/hooks/usePortalEventBridge.js +0 -6
  72. package/dist/portal/hooks/usePortalEventBridge.js.map +2 -2
  73. package/dist/portal/hooks/usePortalNotifications.js +4 -42
  74. package/dist/portal/hooks/usePortalNotifications.js.map +2 -2
  75. package/dist/portal/utils/nav.js +3 -2
  76. package/dist/portal/utils/nav.js.map +2 -2
  77. package/dist/primitives/button.js +4 -9
  78. package/dist/primitives/button.js.map +2 -2
  79. package/jest.config.cjs +1 -2
  80. package/package.json +18 -21
  81. package/src/ai/AiChat.tsx +1 -30
  82. package/src/ai/__tests__/AiChat.test.tsx +0 -31
  83. package/src/backend/AppShell.tsx +4 -55
  84. package/src/backend/AuthSessionGuard.tsx +0 -29
  85. package/src/backend/BackendChromeProvider.tsx +1 -19
  86. package/src/backend/CrudForm.tsx +4 -18
  87. package/src/backend/DataTable.tsx +19 -36
  88. package/src/backend/JsonBuilder.tsx +3 -3
  89. package/src/backend/NextStepCallout.tsx +4 -4
  90. package/src/backend/ProfileDropdown.tsx +0 -1
  91. package/src/backend/RowActions.tsx +2 -2
  92. package/src/backend/__tests__/AppShell.test.tsx +7 -65
  93. package/src/backend/__tests__/AuthSessionGuard.test.tsx +0 -52
  94. package/src/backend/__tests__/BackendChromeProvider.test.tsx +2 -98
  95. package/src/backend/__tests__/DataTable.perspectiveStorage.test.ts +1 -62
  96. package/src/backend/__tests__/nav-utils.test.ts +0 -139
  97. package/src/backend/confirm-dialog/ConfirmDialog.tsx +1 -16
  98. package/src/backend/confirm-dialog/__tests__/ConfirmDialog.test.tsx +1 -68
  99. package/src/backend/crud/__tests__/useGroupOrder.test.ts +1 -39
  100. package/src/backend/crud/useGroupOrder.ts +25 -30
  101. package/src/backend/detail/AddressTiles.tsx +6 -3
  102. package/src/backend/detail/AttachmentDeleteDialog.tsx +1 -1
  103. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  104. package/src/backend/detail/AttachmentsSection.tsx +1 -1
  105. package/src/backend/detail/NotesSection.tsx +1 -1
  106. package/src/backend/detail/TagsSection.tsx +1 -1
  107. package/src/backend/detail/__tests__/AttachmentAssignmentsEditor.test.tsx +0 -21
  108. package/src/backend/forms/FormHeader.tsx +2 -1
  109. package/src/backend/icons/lucideRegistry.generated.tsx +37 -3
  110. package/src/backend/icons/lucideRegistry.ts +2 -2
  111. package/src/backend/injection/spotIds.ts +18 -23
  112. package/src/backend/schedule/ScheduleAgenda.tsx +3 -3
  113. package/src/backend/schedule/ScheduleGrid.tsx +3 -3
  114. package/src/backend/schedule/ScheduleToolbar.tsx +68 -89
  115. package/src/backend/sidebar/SidebarCustomizationEditor.tsx +3 -42
  116. package/src/backend/sidebar/customization-helpers.ts +0 -47
  117. package/src/backend/utils/__tests__/api.test.ts +27 -0
  118. package/src/backend/utils/__tests__/apiCall.test.ts +0 -61
  119. package/src/backend/utils/api.ts +20 -3
  120. package/src/backend/utils/apiCall.ts +1 -29
  121. package/src/backend/utils/customFieldDefs.ts +0 -1
  122. package/src/backend/utils/customFieldForms.ts +11 -15
  123. package/src/backend/utils/nav.ts +2 -22
  124. package/src/frontend/LanguageSwitcher.tsx +0 -1
  125. package/src/portal/PortalContext.tsx +1 -1
  126. package/src/portal/hooks/usePortalEventBridge.ts +0 -6
  127. package/src/portal/hooks/usePortalNotifications.ts +12 -55
  128. package/src/portal/utils/__tests__/nav.test.ts +2 -2
  129. package/src/portal/utils/nav.ts +4 -3
  130. package/src/primitives/button.tsx +4 -10
  131. package/dist/backend/icons/lucideRegistryRuntime.js +0 -28
  132. package/dist/backend/icons/lucideRegistryRuntime.js.map +0 -7
  133. package/dist/backend/perspectiveState.js +0 -34
  134. package/dist/backend/perspectiveState.js.map +0 -7
  135. package/dist/backend/utils/fetchAllPages.js +0 -57
  136. package/dist/backend/utils/fetchAllPages.js.map +0 -7
  137. package/dist/portal/hooks/portalBridgeStatus.js +0 -25
  138. package/dist/portal/hooks/portalBridgeStatus.js.map +0 -7
  139. package/figma/alert.figma.tsx +0 -35
  140. package/figma/badge.figma.tsx +0 -33
  141. package/figma/button.figma.tsx +0 -33
  142. package/figma/checkbox.figma.tsx +0 -28
  143. package/figma/drawer.figma.tsx +0 -40
  144. package/figma/input-variants.figma.tsx +0 -58
  145. package/figma/radio.figma.tsx +0 -16
  146. package/figma/select.figma.tsx +0 -24
  147. package/figma/status-badge.figma.tsx +0 -24
  148. package/figma/switch.figma.tsx +0 -28
  149. package/figma/tabs.figma.tsx +0 -22
  150. package/figma/tag.figma.tsx +0 -27
  151. package/figma.config.json +0 -6
  152. package/scripts/lucideRegistrySource.cjs +0 -133
  153. package/src/backend/__tests__/CrudForm.fieldsetBinding.test.tsx +0 -158
  154. package/src/backend/__tests__/CrudForm.groupInjectionColumn.test.tsx +0 -98
  155. package/src/backend/__tests__/DataTable.metaHiddenLateColumns.test.tsx +0 -105
  156. package/src/backend/icons/__tests__/lucideRegistryGenerator.test.ts +0 -177
  157. package/src/backend/icons/lucideRegistryRuntime.tsx +0 -36
  158. package/src/backend/injection/__tests__/spotIds.extension-points.test.ts +0 -38
  159. package/src/backend/perspectiveState.ts +0 -44
  160. package/src/backend/sidebar/__tests__/group-visibility.test.ts +0 -131
  161. package/src/backend/utils/__tests__/customFieldForms.optionsPaging.test.ts +0 -95
  162. package/src/backend/utils/__tests__/fetchAllPages.test.ts +0 -103
  163. package/src/backend/utils/fetchAllPages.ts +0 -93
  164. package/src/portal/hooks/__tests__/usePortalEventBridge.test.tsx +0 -66
  165. package/src/portal/hooks/__tests__/usePortalNotifications.test.tsx +0 -155
  166. package/src/portal/hooks/portalBridgeStatus.ts +0 -29
  167. package/src/primitives/__tests__/button.test.tsx +0 -70
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/AuthSessionGuard.tsx"],
4
- "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\nimport { clearAllPerspectiveState } from './perspectiveState'\n\nexport const AUTH_IDENTITY_STORAGE_KEY = 'om:auth:identity'\nexport const AUTH_IDENTITY_BROADCAST_CHANNEL = 'om-auth-identity'\nexport const AUTH_IDENTITY_USER_STORAGE_KEY = 'om:auth:identity:user'\n\n/**\n * Purge browser-local DataTable perspective state whenever the backend renders for a\n * different user than the one it last rendered for (#4185).\n *\n * The login form also purges on submit, but that only fires when its client handler\n * runs: a form submitted before hydration, an SSO/magic-link return, or any other\n * entry point into the backend bypasses it entirely and the previous account's unsaved\n * column widths carry over. Anchoring the purge to the observed server identity covers\n * every route into the backend instead of one form.\n *\n * Missing identity metadata is treated as a legacy browser state and purged once:\n * snapshots may predate this marker and belong to a different account. After the\n * marker is recorded, an account's own unsaved widths survive a plain reload.\n */\nfunction purgePerspectiveStateOnIdentityChange(serverUserId: string | null): void {\n if (typeof window === 'undefined' || !serverUserId) return\n try {\n const lastSeenUserId = window.localStorage.getItem(AUTH_IDENTITY_USER_STORAGE_KEY)\n if (lastSeenUserId === serverUserId) return\n clearAllPerspectiveState()\n window.localStorage.setItem(AUTH_IDENTITY_USER_STORAGE_KEY, serverUserId)\n } catch {\n // private mode / quota errors are non-fatal\n }\n}\n\ntype FeatureCheckResponse = {\n ok: boolean\n granted?: string[]\n userId?: string\n}\n\nexport type AuthSessionGuardProps = {\n serverUserId: string | null\n}\n\nexport const __reload = {\n fn: (): void => {\n if (typeof window !== 'undefined') window.location.reload()\n },\n}\n\nexport function AuthSessionGuard({ serverUserId }: AuthSessionGuardProps) {\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n purgePerspectiveStateOnIdentityChange(serverUserId)\n let cancelled = false\n let reloadScheduled = false\n\n const triggerReload = () => {\n if (reloadScheduled) return\n reloadScheduled = true\n __reload.fn()\n }\n\n const checkIdentity = async () => {\n if (cancelled || reloadScheduled) return\n try {\n const res = await apiCall<FeatureCheckResponse>('/api/auth/feature-check', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: [] }),\n cache: 'no-store',\n })\n if (cancelled || reloadScheduled) return\n if (res.status === 401) {\n if (serverUserId) triggerReload()\n return\n }\n if (!res.ok) return\n const currentUserId = typeof res.result?.userId === 'string' ? res.result.userId : null\n if (!currentUserId) return\n if (currentUserId !== serverUserId) triggerReload()\n } catch {\n // network errors are ignored \u2014 next focus/storage event retries\n }\n }\n\n const onVisibilityOrFocus = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n void checkIdentity()\n }\n\n const onStorage = (event: StorageEvent) => {\n if (event.key !== AUTH_IDENTITY_STORAGE_KEY) return\n void checkIdentity()\n }\n\n let broadcastChannel: BroadcastChannel | null = null\n if (typeof BroadcastChannel !== 'undefined') {\n try {\n broadcastChannel = new BroadcastChannel(AUTH_IDENTITY_BROADCAST_CHANNEL)\n broadcastChannel.onmessage = () => { void checkIdentity() }\n } catch {\n broadcastChannel = null\n }\n }\n\n window.addEventListener('focus', onVisibilityOrFocus)\n document.addEventListener('visibilitychange', onVisibilityOrFocus)\n window.addEventListener('storage', onStorage)\n\n return () => {\n cancelled = true\n window.removeEventListener('focus', onVisibilityOrFocus)\n document.removeEventListener('visibilitychange', onVisibilityOrFocus)\n window.removeEventListener('storage', onStorage)\n if (broadcastChannel) {\n broadcastChannel.onmessage = null\n broadcastChannel.close()\n }\n }\n }, [serverUserId])\n\n return null\n}\n\nexport function notifyAuthIdentityChange(): void {\n if (typeof window === 'undefined') return\n try {\n if (typeof BroadcastChannel !== 'undefined') {\n const channel = new BroadcastChannel(AUTH_IDENTITY_BROADCAST_CHANNEL)\n channel.postMessage('changed')\n channel.close()\n }\n } catch {\n // ignore \u2014 fall back to storage event below\n }\n try {\n window.localStorage.setItem(AUTH_IDENTITY_STORAGE_KEY, String(Date.now()))\n } catch {\n // private mode / quota errors are non-fatal\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\n\nexport const AUTH_IDENTITY_STORAGE_KEY = 'om:auth:identity'\nexport const AUTH_IDENTITY_BROADCAST_CHANNEL = 'om-auth-identity'\n\ntype FeatureCheckResponse = {\n ok: boolean\n granted?: string[]\n userId?: string\n}\n\nexport type AuthSessionGuardProps = {\n serverUserId: string | null\n}\n\nexport const __reload = {\n fn: (): void => {\n if (typeof window !== 'undefined') window.location.reload()\n },\n}\n\nexport function AuthSessionGuard({ serverUserId }: AuthSessionGuardProps) {\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n let cancelled = false\n let reloadScheduled = false\n\n const triggerReload = () => {\n if (reloadScheduled) return\n reloadScheduled = true\n __reload.fn()\n }\n\n const checkIdentity = async () => {\n if (cancelled || reloadScheduled) return\n try {\n const res = await apiCall<FeatureCheckResponse>('/api/auth/feature-check', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: [] }),\n cache: 'no-store',\n })\n if (cancelled || reloadScheduled) return\n if (res.status === 401) {\n if (serverUserId) triggerReload()\n return\n }\n if (!res.ok) return\n const currentUserId = typeof res.result?.userId === 'string' ? res.result.userId : null\n if (!currentUserId) return\n if (currentUserId !== serverUserId) triggerReload()\n } catch {\n // network errors are ignored \u2014 next focus/storage event retries\n }\n }\n\n const onVisibilityOrFocus = () => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return\n void checkIdentity()\n }\n\n const onStorage = (event: StorageEvent) => {\n if (event.key !== AUTH_IDENTITY_STORAGE_KEY) return\n void checkIdentity()\n }\n\n let broadcastChannel: BroadcastChannel | null = null\n if (typeof BroadcastChannel !== 'undefined') {\n try {\n broadcastChannel = new BroadcastChannel(AUTH_IDENTITY_BROADCAST_CHANNEL)\n broadcastChannel.onmessage = () => { void checkIdentity() }\n } catch {\n broadcastChannel = null\n }\n }\n\n window.addEventListener('focus', onVisibilityOrFocus)\n document.addEventListener('visibilitychange', onVisibilityOrFocus)\n window.addEventListener('storage', onStorage)\n\n return () => {\n cancelled = true\n window.removeEventListener('focus', onVisibilityOrFocus)\n document.removeEventListener('visibilitychange', onVisibilityOrFocus)\n window.removeEventListener('storage', onStorage)\n if (broadcastChannel) {\n broadcastChannel.onmessage = null\n broadcastChannel.close()\n }\n }\n }, [serverUserId])\n\n return null\n}\n\nexport function notifyAuthIdentityChange(): void {\n if (typeof window === 'undefined') return\n try {\n if (typeof BroadcastChannel !== 'undefined') {\n const channel = new BroadcastChannel(AUTH_IDENTITY_BROADCAST_CHANNEL)\n channel.postMessage('changed')\n channel.close()\n }\n } catch {\n // ignore \u2014 fall back to storage event below\n }\n try {\n window.localStorage.setItem(AUTH_IDENTITY_STORAGE_KEY, String(Date.now()))\n } catch {\n // private mode / quota errors are non-fatal\n }\n}\n"],
5
+ "mappings": ";AACA,YAAY,WAAW;AACvB,SAAS,eAAe;AAEjB,MAAM,4BAA4B;AAClC,MAAM,kCAAkC;AAYxC,MAAM,WAAW;AAAA,EACtB,IAAI,MAAY;AACd,QAAI,OAAO,WAAW,YAAa,QAAO,SAAS,OAAO;AAAA,EAC5D;AACF;AAEO,SAAS,iBAAiB,EAAE,aAAa,GAA0B;AACxE,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,WAAW,YAAa;AACnC,QAAI,YAAY;AAChB,QAAI,kBAAkB;AAEtB,UAAM,gBAAgB,MAAM;AAC1B,UAAI,gBAAiB;AACrB,wBAAkB;AAClB,eAAS,GAAG;AAAA,IACd;AAEA,UAAM,gBAAgB,YAAY;AAChC,UAAI,aAAa,gBAAiB;AAClC,UAAI;AACF,cAAM,MAAM,MAAM,QAA8B,2BAA2B;AAAA,UACzE,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;AAAA,UACrC,OAAO;AAAA,QACT,CAAC;AACD,YAAI,aAAa,gBAAiB;AAClC,YAAI,IAAI,WAAW,KAAK;AACtB,cAAI,aAAc,eAAc;AAChC;AAAA,QACF;AACA,YAAI,CAAC,IAAI,GAAI;AACb,cAAM,gBAAgB,OAAO,IAAI,QAAQ,WAAW,WAAW,IAAI,OAAO,SAAS;AACnF,YAAI,CAAC,cAAe;AACpB,YAAI,kBAAkB,aAAc,eAAc;AAAA,MACpD,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,sBAAsB,MAAM;AAChC,UAAI,OAAO,aAAa,eAAe,SAAS,oBAAoB,SAAU;AAC9E,WAAK,cAAc;AAAA,IACrB;AAEA,UAAM,YAAY,CAAC,UAAwB;AACzC,UAAI,MAAM,QAAQ,0BAA2B;AAC7C,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,mBAA4C;AAChD,QAAI,OAAO,qBAAqB,aAAa;AAC3C,UAAI;AACF,2BAAmB,IAAI,iBAAiB,+BAA+B;AACvE,yBAAiB,YAAY,MAAM;AAAE,eAAK,cAAc;AAAA,QAAE;AAAA,MAC5D,QAAQ;AACN,2BAAmB;AAAA,MACrB;AAAA,IACF;AAEA,WAAO,iBAAiB,SAAS,mBAAmB;AACpD,aAAS,iBAAiB,oBAAoB,mBAAmB;AACjE,WAAO,iBAAiB,WAAW,SAAS;AAE5C,WAAO,MAAM;AACX,kBAAY;AACZ,aAAO,oBAAoB,SAAS,mBAAmB;AACvD,eAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,aAAO,oBAAoB,WAAW,SAAS;AAC/C,UAAI,kBAAkB;AACpB,yBAAiB,YAAY;AAC7B,yBAAiB,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,SAAO;AACT;AAEO,SAAS,2BAAiC;AAC/C,MAAI,OAAO,WAAW,YAAa;AACnC,MAAI;AACF,QAAI,OAAO,qBAAqB,aAAa;AAC3C,YAAM,UAAU,IAAI,iBAAiB,+BAA+B;AACpE,cAAQ,YAAY,SAAS;AAC7B,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,WAAO,aAAa,QAAQ,2BAA2B,OAAO,KAAK,IAAI,CAAC,CAAC;AAAA,EAC3E,QAAQ;AAAA,EAER;AACF;",
6
6
  "names": []
7
7
  }
@@ -78,13 +78,8 @@ function useBackendChrome() {
78
78
  }
79
79
  };
80
80
  }
81
- function useCurrentOrganization() {
82
- const { payload } = useBackendChrome();
83
- return payload?.currentOrganization ?? null;
84
- }
85
81
  export {
86
82
  BackendChromeProvider,
87
- useBackendChrome,
88
- useCurrentOrganization
83
+ useBackendChrome
89
84
  };
90
85
  //# sourceMappingURL=BackendChromeProvider.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/backend/BackendChromeProvider.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\nimport { subscribeOrganizationScopeChanged, getCurrentOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/organizationEvents'\nimport type {\n BackendChromeCurrentOrganization,\n BackendChromePayload,\n} from '@open-mercato/shared/modules/navigation/backendChrome'\n\ntype BackendChromeContextValue = {\n payload: BackendChromePayload | null\n isLoading: boolean\n isReady: boolean\n refresh: () => Promise<void>\n}\n\ntype BackendChromeProviderProps = {\n adminNavApi?: string\n children: React.ReactNode\n}\n\nconst chromeCache = new Map<string, BackendChromePayload>()\nconst BackendChromeContext = React.createContext<BackendChromeContextValue | null>(null)\n\nfunction buildCacheKey(api: string): string {\n return `${api}::scope:${getCurrentOrganizationScopeVersion()}`\n}\n\nexport function BackendChromeProvider({ adminNavApi, children }: BackendChromeProviderProps) {\n const cachedPayload = React.useMemo(() => {\n if (!adminNavApi) return null\n return chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n }, [adminNavApi])\n const [payload, setPayload] = React.useState<BackendChromePayload | null>(cachedPayload)\n const [isLoading, setIsLoading] = React.useState(Boolean(adminNavApi && !cachedPayload))\n\n const refresh = React.useCallback(async () => {\n if (!adminNavApi) return\n setIsLoading(true)\n try {\n const call = await apiCall<BackendChromePayload>(adminNavApi, { credentials: 'include' as never })\n if (!call.ok || !call.result) return\n const nextPayload = call.result\n chromeCache.set(buildCacheKey(adminNavApi), nextPayload)\n setPayload(nextPayload)\n } catch {\n return\n } finally {\n setIsLoading(false)\n }\n }, [adminNavApi])\n\n React.useEffect(() => {\n if (!adminNavApi) {\n setPayload(null)\n setIsLoading(false)\n return\n }\n const cached = chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n setPayload(cached)\n if (!cached) {\n void refresh()\n }\n }, [adminNavApi, refresh])\n\n React.useEffect(() => {\n if (!adminNavApi) return\n const onFocus = () => { void refresh() }\n const onManualRefresh = () => { void refresh() }\n const unsubscribeScope = subscribeOrganizationScopeChanged(() => {\n void refresh()\n })\n window.addEventListener('focus', onFocus)\n window.addEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n return () => {\n unsubscribeScope()\n window.removeEventListener('focus', onFocus)\n window.removeEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n }\n }, [adminNavApi, refresh])\n\n const value = React.useMemo<BackendChromeContextValue>(() => ({\n payload,\n isLoading,\n isReady: !adminNavApi || payload !== null,\n refresh,\n }), [adminNavApi, isLoading, payload, refresh])\n\n return (\n <BackendChromeContext.Provider value={value}>\n {children}\n </BackendChromeContext.Provider>\n )\n}\n\nexport function useBackendChrome(): BackendChromeContextValue {\n return React.useContext(BackendChromeContext) ?? {\n payload: null,\n isLoading: false,\n isReady: true,\n refresh: async () => {},\n }\n}\n\n/**\n * The organization the backend chrome is currently scoped to, for UI that needs to label\n * \"you are viewing: <name>\".\n *\n * Reads the payload this provider already holds, so it costs no additional request. Returns `null`\n * under an all-organizations selection, outside a provider, or before the payload has arrived \u2014 treat\n * it as \"unknown\", not as \"no organization\".\n *\n * Prefer this over `payload.brand`, which only populates when the organization has a logo configured.\n */\nexport function useCurrentOrganization(): BackendChromeCurrentOrganization | null {\n const { payload } = useBackendChrome()\n return payload?.currentOrganization ?? null\n}\n"],
5
- "mappings": ";AA0FI;AAxFJ,YAAY,WAAW;AACvB,SAAS,eAAe;AACxB,SAAS,mCAAmC,0CAA0C;AAkBtF,MAAM,cAAc,oBAAI,IAAkC;AAC1D,MAAM,uBAAuB,MAAM,cAAgD,IAAI;AAEvF,SAAS,cAAc,KAAqB;AAC1C,SAAO,GAAG,GAAG,WAAW,mCAAmC,CAAC;AAC9D;AAEO,SAAS,sBAAsB,EAAE,aAAa,SAAS,GAA+B;AAC3F,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,QAAI,CAAC,YAAa,QAAO;AACzB,WAAO,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAAA,EACxD,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAsC,aAAa;AACvF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,QAAQ,eAAe,CAAC,aAAa,CAAC;AAEvF,QAAM,UAAU,MAAM,YAAY,YAAY;AAC5C,QAAI,CAAC,YAAa;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,OAAO,MAAM,QAA8B,aAAa,EAAE,aAAa,UAAmB,CAAC;AACjG,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,OAAQ;AAC9B,YAAM,cAAc,KAAK;AACzB,kBAAY,IAAI,cAAc,WAAW,GAAG,WAAW;AACvD,iBAAW,WAAW;AAAA,IACxB,QAAQ;AACN;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa;AAChB,iBAAW,IAAI;AACf,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAM,SAAS,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAC9D,eAAW,MAAM;AACjB,QAAI,CAAC,QAAQ;AACX,WAAK,QAAQ;AAAA,IACf;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,YAAa;AAClB,UAAM,UAAU,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AACvC,UAAM,kBAAkB,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AAC/C,UAAM,mBAAmB,kCAAkC,MAAM;AAC/D,WAAK,QAAQ;AAAA,IACf,CAAC;AACD,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,sBAAsB,eAAgC;AAC9E,WAAO,MAAM;AACX,uBAAiB;AACjB,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,sBAAsB,eAAgC;AAAA,IACnF;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,QAAQ,MAAM,QAAmC,OAAO;AAAA,IAC5D;AAAA,IACA;AAAA,IACA,SAAS,CAAC,eAAe,YAAY;AAAA,IACrC;AAAA,EACF,IAAI,CAAC,aAAa,WAAW,SAAS,OAAO,CAAC;AAE9C,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAC5B,UACH;AAEJ;AAEO,SAAS,mBAA8C;AAC5D,SAAO,MAAM,WAAW,oBAAoB,KAAK;AAAA,IAC/C,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,IACT,SAAS,YAAY;AAAA,IAAC;AAAA,EACxB;AACF;AAYO,SAAS,yBAAkE;AAChF,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AACrC,SAAO,SAAS,uBAAuB;AACzC;",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { apiCall } from './utils/apiCall'\nimport { subscribeOrganizationScopeChanged, getCurrentOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/organizationEvents'\nimport type { BackendChromePayload } from '@open-mercato/shared/modules/navigation/backendChrome'\n\ntype BackendChromeContextValue = {\n payload: BackendChromePayload | null\n isLoading: boolean\n isReady: boolean\n refresh: () => Promise<void>\n}\n\ntype BackendChromeProviderProps = {\n adminNavApi?: string\n children: React.ReactNode\n}\n\nconst chromeCache = new Map<string, BackendChromePayload>()\nconst BackendChromeContext = React.createContext<BackendChromeContextValue | null>(null)\n\nfunction buildCacheKey(api: string): string {\n return `${api}::scope:${getCurrentOrganizationScopeVersion()}`\n}\n\nexport function BackendChromeProvider({ adminNavApi, children }: BackendChromeProviderProps) {\n const cachedPayload = React.useMemo(() => {\n if (!adminNavApi) return null\n return chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n }, [adminNavApi])\n const [payload, setPayload] = React.useState<BackendChromePayload | null>(cachedPayload)\n const [isLoading, setIsLoading] = React.useState(Boolean(adminNavApi && !cachedPayload))\n\n const refresh = React.useCallback(async () => {\n if (!adminNavApi) return\n setIsLoading(true)\n try {\n const call = await apiCall<BackendChromePayload>(adminNavApi, { credentials: 'include' as never })\n if (!call.ok || !call.result) return\n const nextPayload = call.result\n chromeCache.set(buildCacheKey(adminNavApi), nextPayload)\n setPayload(nextPayload)\n } catch {\n return\n } finally {\n setIsLoading(false)\n }\n }, [adminNavApi])\n\n React.useEffect(() => {\n if (!adminNavApi) {\n setPayload(null)\n setIsLoading(false)\n return\n }\n const cached = chromeCache.get(buildCacheKey(adminNavApi)) ?? null\n setPayload(cached)\n if (!cached) {\n void refresh()\n }\n }, [adminNavApi, refresh])\n\n React.useEffect(() => {\n if (!adminNavApi) return\n const onFocus = () => { void refresh() }\n const onManualRefresh = () => { void refresh() }\n const unsubscribeScope = subscribeOrganizationScopeChanged(() => {\n void refresh()\n })\n window.addEventListener('focus', onFocus)\n window.addEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n return () => {\n unsubscribeScope()\n window.removeEventListener('focus', onFocus)\n window.removeEventListener('om:refresh-sidebar', onManualRefresh as EventListener)\n }\n }, [adminNavApi, refresh])\n\n const value = React.useMemo<BackendChromeContextValue>(() => ({\n payload,\n isLoading,\n isReady: !adminNavApi || payload !== null,\n refresh,\n }), [adminNavApi, isLoading, payload, refresh])\n\n return (\n <BackendChromeContext.Provider value={value}>\n {children}\n </BackendChromeContext.Provider>\n )\n}\n\nexport function useBackendChrome(): BackendChromeContextValue {\n return React.useContext(BackendChromeContext) ?? {\n payload: null,\n isLoading: false,\n isReady: true,\n refresh: async () => {},\n }\n}\n"],
5
+ "mappings": ";AAuFI;AArFJ,YAAY,WAAW;AACvB,SAAS,eAAe;AACxB,SAAS,mCAAmC,0CAA0C;AAetF,MAAM,cAAc,oBAAI,IAAkC;AAC1D,MAAM,uBAAuB,MAAM,cAAgD,IAAI;AAEvF,SAAS,cAAc,KAAqB;AAC1C,SAAO,GAAG,GAAG,WAAW,mCAAmC,CAAC;AAC9D;AAEO,SAAS,sBAAsB,EAAE,aAAa,SAAS,GAA+B;AAC3F,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,QAAI,CAAC,YAAa,QAAO;AACzB,WAAO,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAAA,EACxD,GAAG,CAAC,WAAW,CAAC;AAChB,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAsC,aAAa;AACvF,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,QAAQ,eAAe,CAAC,aAAa,CAAC;AAEvF,QAAM,UAAU,MAAM,YAAY,YAAY;AAC5C,QAAI,CAAC,YAAa;AAClB,iBAAa,IAAI;AACjB,QAAI;AACF,YAAM,OAAO,MAAM,QAA8B,aAAa,EAAE,aAAa,UAAmB,CAAC;AACjG,UAAI,CAAC,KAAK,MAAM,CAAC,KAAK,OAAQ;AAC9B,YAAM,cAAc,KAAK;AACzB,kBAAY,IAAI,cAAc,WAAW,GAAG,WAAW;AACvD,iBAAW,WAAW;AAAA,IACxB,QAAQ;AACN;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa;AAChB,iBAAW,IAAI;AACf,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,UAAM,SAAS,YAAY,IAAI,cAAc,WAAW,CAAC,KAAK;AAC9D,eAAW,MAAM;AACjB,QAAI,CAAC,QAAQ;AACX,WAAK,QAAQ;AAAA,IACf;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,YAAa;AAClB,UAAM,UAAU,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AACvC,UAAM,kBAAkB,MAAM;AAAE,WAAK,QAAQ;AAAA,IAAE;AAC/C,UAAM,mBAAmB,kCAAkC,MAAM;AAC/D,WAAK,QAAQ;AAAA,IACf,CAAC;AACD,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,sBAAsB,eAAgC;AAC9E,WAAO,MAAM;AACX,uBAAiB;AACjB,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,sBAAsB,eAAgC;AAAA,IACnF;AAAA,EACF,GAAG,CAAC,aAAa,OAAO,CAAC;AAEzB,QAAM,QAAQ,MAAM,QAAmC,OAAO;AAAA,IAC5D;AAAA,IACA;AAAA,IACA,SAAS,CAAC,eAAe,YAAY;AAAA,IACrC;AAAA,EACF,IAAI,CAAC,aAAa,WAAW,SAAS,OAAO,CAAC;AAE9C,SACE,oBAAC,qBAAqB,UAArB,EAA8B,OAC5B,UACH;AAEJ;AAEO,SAAS,mBAA8C;AAC5D,SAAO,MAAM,WAAW,oBAAoB,KAAK;AAAA,IAC/C,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,IACT,SAAS,YAAY;AAAA,IAAC;AAAA,EACxB;AACF;",
6
6
  "names": []
7
7
  }
@@ -100,7 +100,6 @@ import { InjectedField } from "./injection/InjectedField.js";
100
100
  import { insertByInjectionPlacement } from "@open-mercato/shared/modules/widgets/injection-position";
101
101
  import { evaluateInjectedVisibility } from "./injection/visibility-utils.js";
102
102
  import { ComponentReplacementHandles } from "@open-mercato/shared/modules/widgets/component-registry";
103
- import { crudFormExtensionSpotId, extensionSpotChildId } from "@open-mercato/shared/modules/widgets/extension-points";
104
103
  import { RichEditor } from "../primitives/rich-editor.js";
105
104
  import MarkdownField from "./inputs/MarkdownField.js";
106
105
  const logger = createLogger("ui").child({ component: "CrudForm" });
@@ -454,7 +453,7 @@ function CrudForm({
454
453
  if (injectionSpotId) return injectionSpotId;
455
454
  if (resolvedEntityIds.length) {
456
455
  const normalized = resolvedEntityIds[0].replace(/[:]+/g, ".");
457
- return crudFormExtensionSpotId(normalized);
456
+ return `crud-form:${normalized}`;
458
457
  }
459
458
  return void 0;
460
459
  }, [injectionSpotId, resolvedEntityIds]);
@@ -463,7 +462,7 @@ function CrudForm({
463
462
  if (resolvedEntityIds.length) return ComponentReplacementHandles.crudForm(resolvedEntityIds[0].replace(/[:]+/g, "."));
464
463
  return ComponentReplacementHandles.crudForm("unknown");
465
464
  }, [replacementHandle, resolvedEntityIds]);
466
- const headerInjectionSpotId = resolvedInjectionSpotId ? extensionSpotChildId(resolvedInjectionSpotId, "header") : void 0;
465
+ const headerInjectionSpotId = resolvedInjectionSpotId ? `${resolvedInjectionSpotId}:header` : void 0;
467
466
  const recordId = React.useMemo(() => {
468
467
  const raw = values.id;
469
468
  if (typeof raw === "string") return raw;
@@ -680,7 +679,7 @@ function CrudForm({
680
679
  triggerOnLoad: true
681
680
  });
682
681
  const { widgets: injectedFieldWidgets } = useInjectionDataWidgets(
683
- resolvedInjectionSpotId ? extensionSpotChildId(resolvedInjectionSpotId, "fields") : "__disabled__:fields"
682
+ resolvedInjectionSpotId ? `${resolvedInjectionSpotId}:fields` : "__disabled__:fields"
684
683
  );
685
684
  const { triggerEvent: triggerInjectionEvent } = useInjectionSpotEvents(resolvedInjectionSpotId ?? "", injectionWidgets);
686
685
  const extendedInjectionEventsEnabled = CRUDFORM_EXTENDED_EVENTS_ENABLED && Boolean(resolvedInjectionSpotId);
@@ -1799,11 +1798,10 @@ function CrudForm({
1799
1798
  }, [validateFieldOnBlur]);
1800
1799
  const handleFieldsetSelectionChange = React.useCallback(
1801
1800
  (entityId2, nextCode) => {
1802
- if (!nextCode) return;
1803
1801
  setCfFieldsetSelections((prev) => ({ ...prev, [entityId2]: nextCode }));
1804
1802
  const bindingKey = customFieldsetBindings?.[entityId2]?.valueKey;
1805
1803
  if (bindingKey) {
1806
- setValue(bindingKey, nextCode);
1804
+ setValue(bindingKey, nextCode ?? void 0);
1807
1805
  }
1808
1806
  },
1809
1807
  [customFieldsetBindings, setValue]