@rebasepro/plugin-insights 0.5.0 → 0.6.1

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 (303) hide show
  1. package/dist/{plugin-insights/src/components → components}/CollectionInsightsInline.d.ts +2 -1
  2. package/dist/{plugin-insights/src/components → components}/HomeCardInsightSlot.d.ts +3 -2
  3. package/dist/{plugin-insights/src/components → components}/HomeInsightsSlot.d.ts +3 -2
  4. package/dist/{plugin-insights/src/components → components}/InsightWidget.d.ts +3 -2
  5. package/dist/{plugin-insights/src/components → components}/InsightWidgetSkeleton.d.ts +3 -2
  6. package/dist/{plugin-insights/src/components → components}/InsightsScorecardView.d.ts +3 -2
  7. package/dist/{plugin-insights/src/engine → engine}/InsightsProvider.d.ts +2 -2
  8. package/dist/{plugin-insights/src/index.d.ts → index.d.ts} +1 -1
  9. package/dist/index.es.js +583 -1072
  10. package/dist/index.es.js.map +1 -1
  11. package/dist/index.umd.js +645 -1096
  12. package/dist/index.umd.js.map +1 -1
  13. package/package.json +19 -14
  14. package/src/components/CollectionInsightsInline.tsx +3 -3
  15. package/src/components/HomeCardInsightSlot.tsx +1 -1
  16. package/src/components/HomeInsightsSlot.tsx +1 -1
  17. package/src/components/InsightWidget.tsx +4 -2
  18. package/src/components/InsightWidgetSkeleton.tsx +21 -13
  19. package/src/components/InsightsScorecardView.tsx +2 -2
  20. package/src/engine/InsightsCache.test.ts +5 -3
  21. package/src/engine/InsightsCache.ts +3 -2
  22. package/src/engine/useInsightsData.ts +3 -1
  23. package/src/index.ts +1 -1
  24. package/src/useInsightsPlugin.tsx +68 -65
  25. package/dist/common/src/collections/CollectionRegistry.d.ts +0 -56
  26. package/dist/common/src/collections/default-collections.d.ts +0 -9
  27. package/dist/common/src/collections/index.d.ts +0 -2
  28. package/dist/common/src/data/buildRebaseData.d.ts +0 -14
  29. package/dist/common/src/data/query_builder.d.ts +0 -55
  30. package/dist/common/src/index.d.ts +0 -4
  31. package/dist/common/src/util/builders.d.ts +0 -57
  32. package/dist/common/src/util/callbacks.d.ts +0 -6
  33. package/dist/common/src/util/collections.d.ts +0 -11
  34. package/dist/common/src/util/common.d.ts +0 -2
  35. package/dist/common/src/util/conditions.d.ts +0 -26
  36. package/dist/common/src/util/entities.d.ts +0 -58
  37. package/dist/common/src/util/enums.d.ts +0 -3
  38. package/dist/common/src/util/index.d.ts +0 -16
  39. package/dist/common/src/util/navigation_from_path.d.ts +0 -34
  40. package/dist/common/src/util/navigation_utils.d.ts +0 -20
  41. package/dist/common/src/util/parent_references_from_path.d.ts +0 -6
  42. package/dist/common/src/util/paths.d.ts +0 -14
  43. package/dist/common/src/util/permissions.d.ts +0 -14
  44. package/dist/common/src/util/references.d.ts +0 -2
  45. package/dist/common/src/util/relations.d.ts +0 -22
  46. package/dist/common/src/util/resolutions.d.ts +0 -72
  47. package/dist/common/src/util/storage.d.ts +0 -24
  48. package/dist/core/src/components/AIIcon.d.ts +0 -16
  49. package/dist/core/src/components/BootstrapAdminBanner.d.ts +0 -4
  50. package/dist/core/src/components/ConfirmationDialog.d.ts +0 -9
  51. package/dist/core/src/components/Debug/UIReferenceView.d.ts +0 -1
  52. package/dist/core/src/components/Debug/UIStyleGuide.d.ts +0 -1
  53. package/dist/core/src/components/ErrorTooltip.d.ts +0 -2
  54. package/dist/core/src/components/ErrorView.d.ts +0 -21
  55. package/dist/core/src/components/LanguageToggle.d.ts +0 -1
  56. package/dist/core/src/components/LoginView/LoginView.d.ts +0 -109
  57. package/dist/core/src/components/LoginView/index.d.ts +0 -2
  58. package/dist/core/src/components/NotFoundPage.d.ts +0 -1
  59. package/dist/core/src/components/RebaseAuth.d.ts +0 -10
  60. package/dist/core/src/components/RebaseLogo.d.ts +0 -7
  61. package/dist/core/src/components/UnsavedChangesDialog.d.ts +0 -9
  62. package/dist/core/src/components/UserDisplay.d.ts +0 -7
  63. package/dist/core/src/components/UserSelectPopover.d.ts +0 -62
  64. package/dist/core/src/components/UserSettingsView.d.ts +0 -1
  65. package/dist/core/src/components/common/index.d.ts +0 -6
  66. package/dist/core/src/components/common/table_height.d.ts +0 -5
  67. package/dist/core/src/components/common/types.d.ts +0 -66
  68. package/dist/core/src/components/common/useColumnsIds.d.ts +0 -9
  69. package/dist/core/src/components/common/useDataTableController.d.ts +0 -45
  70. package/dist/core/src/components/common/useDebouncedData.d.ts +0 -9
  71. package/dist/core/src/components/common/useScrollRestoration.d.ts +0 -14
  72. package/dist/core/src/components/index.d.ts +0 -17
  73. package/dist/core/src/contexts/AdminModeController.d.ts +0 -4
  74. package/dist/core/src/contexts/AnalyticsContext.d.ts +0 -3
  75. package/dist/core/src/contexts/AuthControllerContext.d.ts +0 -3
  76. package/dist/core/src/contexts/CustomizationControllerContext.d.ts +0 -3
  77. package/dist/core/src/contexts/DataDriverContext.d.ts +0 -3
  78. package/dist/core/src/contexts/DatabaseAdminContext.d.ts +0 -3
  79. package/dist/core/src/contexts/DialogsProvider.d.ts +0 -4
  80. package/dist/core/src/contexts/EffectiveRoleController.d.ts +0 -4
  81. package/dist/core/src/contexts/InternalUserManagementContext.d.ts +0 -3
  82. package/dist/core/src/contexts/ModeController.d.ts +0 -4
  83. package/dist/core/src/contexts/RebaseClientInstanceContext.d.ts +0 -6
  84. package/dist/core/src/contexts/RebaseDataContext.d.ts +0 -3
  85. package/dist/core/src/contexts/SnackbarProvider.d.ts +0 -2
  86. package/dist/core/src/contexts/StorageSourceContext.d.ts +0 -3
  87. package/dist/core/src/contexts/UserConfigurationPersistenceContext.d.ts +0 -3
  88. package/dist/core/src/contexts/index.d.ts +0 -13
  89. package/dist/core/src/core/PluginLifecycleManager.d.ts +0 -17
  90. package/dist/core/src/core/PluginProviderStack.d.ts +0 -21
  91. package/dist/core/src/core/Rebase.d.ts +0 -14
  92. package/dist/core/src/core/RebaseProps.d.ts +0 -147
  93. package/dist/core/src/core/RebaseRouter.d.ts +0 -4
  94. package/dist/core/src/core/RebaseRoutes.d.ts +0 -17
  95. package/dist/core/src/core/index.d.ts +0 -4
  96. package/dist/core/src/hooks/ApiConfigContext.d.ts +0 -24
  97. package/dist/core/src/hooks/data/delete.d.ts +0 -31
  98. package/dist/core/src/hooks/data/save.d.ts +0 -34
  99. package/dist/core/src/hooks/data/useCollectionFetch.d.ts +0 -62
  100. package/dist/core/src/hooks/data/useData.d.ts +0 -13
  101. package/dist/core/src/hooks/data/useDataOrder.d.ts +0 -12
  102. package/dist/core/src/hooks/data/useEntityFetch.d.ts +0 -43
  103. package/dist/core/src/hooks/data/useRelationSelector.d.ts +0 -52
  104. package/dist/core/src/hooks/data/useUserSelector.d.ts +0 -31
  105. package/dist/core/src/hooks/index.d.ts +0 -37
  106. package/dist/core/src/hooks/useAdminModeController.d.ts +0 -19
  107. package/dist/core/src/hooks/useAnalyticsController.d.ts +0 -5
  108. package/dist/core/src/hooks/useAuthController.d.ts +0 -11
  109. package/dist/core/src/hooks/useAuthSubscription.d.ts +0 -2
  110. package/dist/core/src/hooks/useBackendStorageSource.d.ts +0 -30
  111. package/dist/core/src/hooks/useBridgeRegistration.d.ts +0 -18
  112. package/dist/core/src/hooks/useBrowserTitleAndIcon.d.ts +0 -6
  113. package/dist/core/src/hooks/useBuildAdminModeController.d.ts +0 -6
  114. package/dist/core/src/hooks/useBuildEffectiveRoleController.d.ts +0 -8
  115. package/dist/core/src/hooks/useBuildLocalConfigurationPersistence.d.ts +0 -2
  116. package/dist/core/src/hooks/useBuildModeController.d.ts +0 -6
  117. package/dist/core/src/hooks/useClipboard.d.ts +0 -57
  118. package/dist/core/src/hooks/useCollapsedGroups.d.ts +0 -27
  119. package/dist/core/src/hooks/useCustomizationController.d.ts +0 -11
  120. package/dist/core/src/hooks/useDialogsController.d.ts +0 -11
  121. package/dist/core/src/hooks/useEffectiveRoleController.d.ts +0 -7
  122. package/dist/core/src/hooks/useInternalUserManagementController.d.ts +0 -12
  123. package/dist/core/src/hooks/useLargeLayout.d.ts +0 -1
  124. package/dist/core/src/hooks/useModeController.d.ts +0 -19
  125. package/dist/core/src/hooks/usePermissions.d.ts +0 -12
  126. package/dist/core/src/hooks/useRebaseClient.d.ts +0 -5
  127. package/dist/core/src/hooks/useRebaseContext.d.ts +0 -11
  128. package/dist/core/src/hooks/useRebaseRegistry.d.ts +0 -34
  129. package/dist/core/src/hooks/useResolvedComponent.d.ts +0 -47
  130. package/dist/core/src/hooks/useSlot.d.ts +0 -18
  131. package/dist/core/src/hooks/useSnackbarController.d.ts +0 -20
  132. package/dist/core/src/hooks/useStorageSource.d.ts +0 -7
  133. package/dist/core/src/hooks/useStudioBridge.d.ts +0 -91
  134. package/dist/core/src/hooks/useTranslation.d.ts +0 -17
  135. package/dist/core/src/hooks/useUnsavedChangesDialog.d.ts +0 -12
  136. package/dist/core/src/hooks/useUserConfigurationPersistence.d.ts +0 -8
  137. package/dist/core/src/i18n/RebaseI18nProvider.d.ts +0 -33
  138. package/dist/core/src/index.d.ts +0 -15
  139. package/dist/core/src/internal/common.d.ts +0 -3
  140. package/dist/core/src/internal/useRestoreScroll.d.ts +0 -6
  141. package/dist/core/src/locales/de.d.ts +0 -2
  142. package/dist/core/src/locales/en.d.ts +0 -10
  143. package/dist/core/src/locales/es.d.ts +0 -10
  144. package/dist/core/src/locales/fr.d.ts +0 -2
  145. package/dist/core/src/locales/hi.d.ts +0 -2
  146. package/dist/core/src/locales/it.d.ts +0 -2
  147. package/dist/core/src/locales/pt.d.ts +0 -7
  148. package/dist/core/src/util/constants.d.ts +0 -1
  149. package/dist/core/src/util/createFormexStub.d.ts +0 -2
  150. package/dist/core/src/util/entity_cache.d.ts +0 -22
  151. package/dist/core/src/util/enums.d.ts +0 -5
  152. package/dist/core/src/util/icon_list.d.ts +0 -5
  153. package/dist/core/src/util/icons.d.ts +0 -20
  154. package/dist/core/src/util/index.d.ts +0 -8
  155. package/dist/core/src/util/previews.d.ts +0 -4
  156. package/dist/core/src/util/useStorageUploadController.d.ts +0 -38
  157. package/dist/formex/src/Field.d.ts +0 -52
  158. package/dist/formex/src/Formex.d.ts +0 -7
  159. package/dist/formex/src/index.d.ts +0 -5
  160. package/dist/formex/src/types.d.ts +0 -40
  161. package/dist/formex/src/useCreateFormex.d.ts +0 -14
  162. package/dist/formex/src/utils.d.ts +0 -16
  163. package/dist/types/src/controllers/analytics_controller.d.ts +0 -7
  164. package/dist/types/src/controllers/auth.d.ts +0 -104
  165. package/dist/types/src/controllers/client.d.ts +0 -168
  166. package/dist/types/src/controllers/collection_registry.d.ts +0 -46
  167. package/dist/types/src/controllers/customization_controller.d.ts +0 -60
  168. package/dist/types/src/controllers/data.d.ts +0 -207
  169. package/dist/types/src/controllers/data_driver.d.ts +0 -218
  170. package/dist/types/src/controllers/database_admin.d.ts +0 -11
  171. package/dist/types/src/controllers/dialogs_controller.d.ts +0 -36
  172. package/dist/types/src/controllers/effective_role.d.ts +0 -4
  173. package/dist/types/src/controllers/email.d.ts +0 -36
  174. package/dist/types/src/controllers/index.d.ts +0 -18
  175. package/dist/types/src/controllers/local_config_persistence.d.ts +0 -20
  176. package/dist/types/src/controllers/navigation.d.ts +0 -225
  177. package/dist/types/src/controllers/registry.d.ts +0 -63
  178. package/dist/types/src/controllers/side_dialogs_controller.d.ts +0 -67
  179. package/dist/types/src/controllers/side_entity_controller.d.ts +0 -97
  180. package/dist/types/src/controllers/snackbar.d.ts +0 -24
  181. package/dist/types/src/controllers/storage.d.ts +0 -171
  182. package/dist/types/src/index.d.ts +0 -4
  183. package/dist/types/src/rebase_context.d.ts +0 -122
  184. package/dist/types/src/types/auth_adapter.d.ts +0 -301
  185. package/dist/types/src/types/backend.d.ts +0 -571
  186. package/dist/types/src/types/backend_hooks.d.ts +0 -172
  187. package/dist/types/src/types/builders.d.ts +0 -15
  188. package/dist/types/src/types/chips.d.ts +0 -5
  189. package/dist/types/src/types/collections.d.ts +0 -961
  190. package/dist/types/src/types/component_ref.d.ts +0 -47
  191. package/dist/types/src/types/cron.d.ts +0 -102
  192. package/dist/types/src/types/data_source.d.ts +0 -64
  193. package/dist/types/src/types/database_adapter.d.ts +0 -94
  194. package/dist/types/src/types/entities.d.ts +0 -145
  195. package/dist/types/src/types/entity_actions.d.ts +0 -104
  196. package/dist/types/src/types/entity_callbacks.d.ts +0 -173
  197. package/dist/types/src/types/entity_link_builder.d.ts +0 -7
  198. package/dist/types/src/types/entity_overrides.d.ts +0 -10
  199. package/dist/types/src/types/entity_views.d.ts +0 -87
  200. package/dist/types/src/types/export_import.d.ts +0 -21
  201. package/dist/types/src/types/formex.d.ts +0 -40
  202. package/dist/types/src/types/index.d.ts +0 -28
  203. package/dist/types/src/types/locales.d.ts +0 -4
  204. package/dist/types/src/types/modify_collections.d.ts +0 -5
  205. package/dist/types/src/types/plugins.d.ts +0 -282
  206. package/dist/types/src/types/properties.d.ts +0 -1173
  207. package/dist/types/src/types/property_config.d.ts +0 -74
  208. package/dist/types/src/types/relations.d.ts +0 -336
  209. package/dist/types/src/types/slots.d.ts +0 -262
  210. package/dist/types/src/types/translations.d.ts +0 -900
  211. package/dist/types/src/types/user_management_delegate.d.ts +0 -86
  212. package/dist/types/src/types/websockets.d.ts +0 -78
  213. package/dist/types/src/users/index.d.ts +0 -1
  214. package/dist/types/src/users/user.d.ts +0 -50
  215. package/dist/ui/src/components/Alert.d.ts +0 -12
  216. package/dist/ui/src/components/Autocomplete.d.ts +0 -21
  217. package/dist/ui/src/components/Avatar.d.ts +0 -11
  218. package/dist/ui/src/components/Badge.d.ts +0 -8
  219. package/dist/ui/src/components/BooleanSwitch.d.ts +0 -14
  220. package/dist/ui/src/components/BooleanSwitchWithLabel.d.ts +0 -17
  221. package/dist/ui/src/components/Button.d.ts +0 -14
  222. package/dist/ui/src/components/Card.d.ts +0 -8
  223. package/dist/ui/src/components/CenteredView.d.ts +0 -9
  224. package/dist/ui/src/components/Checkbox.d.ts +0 -13
  225. package/dist/ui/src/components/Chip.d.ts +0 -26
  226. package/dist/ui/src/components/CircularProgress.d.ts +0 -5
  227. package/dist/ui/src/components/CircularProgressCenter.d.ts +0 -11
  228. package/dist/ui/src/components/Collapse.d.ts +0 -9
  229. package/dist/ui/src/components/ColorPicker.d.ts +0 -30
  230. package/dist/ui/src/components/Container.d.ts +0 -8
  231. package/dist/ui/src/components/DateTimeField.d.ts +0 -24
  232. package/dist/ui/src/components/DebouncedTextField.d.ts +0 -2
  233. package/dist/ui/src/components/Dialog.d.ts +0 -39
  234. package/dist/ui/src/components/DialogActions.d.ts +0 -7
  235. package/dist/ui/src/components/DialogContent.d.ts +0 -7
  236. package/dist/ui/src/components/DialogTitle.d.ts +0 -10
  237. package/dist/ui/src/components/ErrorBoundary.d.ts +0 -33
  238. package/dist/ui/src/components/ExpandablePanel.d.ts +0 -12
  239. package/dist/ui/src/components/FileUpload.d.ts +0 -23
  240. package/dist/ui/src/components/FilterChip.d.ts +0 -34
  241. package/dist/ui/src/components/IconButton.d.ts +0 -12
  242. package/dist/ui/src/components/InfoLabel.d.ts +0 -5
  243. package/dist/ui/src/components/InputLabel.d.ts +0 -11
  244. package/dist/ui/src/components/Label.d.ts +0 -7
  245. package/dist/ui/src/components/LoadingButton.d.ts +0 -7
  246. package/dist/ui/src/components/Markdown.d.ts +0 -10
  247. package/dist/ui/src/components/Menu.d.ts +0 -23
  248. package/dist/ui/src/components/Menubar.d.ts +0 -80
  249. package/dist/ui/src/components/MultiSelect.d.ts +0 -48
  250. package/dist/ui/src/components/Paper.d.ts +0 -6
  251. package/dist/ui/src/components/Popover.d.ts +0 -24
  252. package/dist/ui/src/components/RadioGroup.d.ts +0 -28
  253. package/dist/ui/src/components/ResizablePanels.d.ts +0 -18
  254. package/dist/ui/src/components/SearchBar.d.ts +0 -26
  255. package/dist/ui/src/components/Select.d.ts +0 -43
  256. package/dist/ui/src/components/Separator.d.ts +0 -5
  257. package/dist/ui/src/components/Sheet.d.ts +0 -22
  258. package/dist/ui/src/components/Skeleton.d.ts +0 -6
  259. package/dist/ui/src/components/Slider.d.ts +0 -21
  260. package/dist/ui/src/components/Table.d.ts +0 -34
  261. package/dist/ui/src/components/Tabs.d.ts +0 -19
  262. package/dist/ui/src/components/TextField.d.ts +0 -58
  263. package/dist/ui/src/components/TextareaAutosize.d.ts +0 -43
  264. package/dist/ui/src/components/ToggleButtonGroup.d.ts +0 -30
  265. package/dist/ui/src/components/Tooltip.d.ts +0 -19
  266. package/dist/ui/src/components/Typography.d.ts +0 -36
  267. package/dist/ui/src/components/VirtualTable/VirtualTable.d.ts +0 -11
  268. package/dist/ui/src/components/VirtualTable/VirtualTableCell.d.ts +0 -21
  269. package/dist/ui/src/components/VirtualTable/VirtualTableHeader.d.ts +0 -29
  270. package/dist/ui/src/components/VirtualTable/VirtualTableHeaderRow.d.ts +0 -2
  271. package/dist/ui/src/components/VirtualTable/VirtualTableProps.d.ts +0 -249
  272. package/dist/ui/src/components/VirtualTable/VirtualTableRow.d.ts +0 -3
  273. package/dist/ui/src/components/VirtualTable/index.d.ts +0 -3
  274. package/dist/ui/src/components/VirtualTable/types.d.ts +0 -38
  275. package/dist/ui/src/components/common/SelectInputLabel.d.ts +0 -5
  276. package/dist/ui/src/components/index.d.ts +0 -58
  277. package/dist/ui/src/hooks/PortalContainerContext.d.ts +0 -31
  278. package/dist/ui/src/hooks/index.d.ts +0 -6
  279. package/dist/ui/src/hooks/useDebounceCallback.d.ts +0 -1
  280. package/dist/ui/src/hooks/useDebounceValue.d.ts +0 -1
  281. package/dist/ui/src/hooks/useDebouncedCallback.d.ts +0 -1
  282. package/dist/ui/src/hooks/useInjectStyles.d.ts +0 -7
  283. package/dist/ui/src/hooks/useOutsideAlerter.d.ts +0 -5
  284. package/dist/ui/src/icons/GitHubIcon.d.ts +0 -2
  285. package/dist/ui/src/icons/HandleIcon.d.ts +0 -1
  286. package/dist/ui/src/icons/Icon.d.ts +0 -20
  287. package/dist/ui/src/icons/cool_icon_keys.d.ts +0 -1
  288. package/dist/ui/src/icons/icon_keys.d.ts +0 -1
  289. package/dist/ui/src/icons/index.d.ts +0 -8
  290. package/dist/ui/src/index.d.ts +0 -5
  291. package/dist/ui/src/styles.d.ts +0 -12
  292. package/dist/ui/src/util/chip_colors.d.ts +0 -4
  293. package/dist/ui/src/util/cls.d.ts +0 -2
  294. package/dist/ui/src/util/debounce.d.ts +0 -10
  295. package/dist/ui/src/util/hash.d.ts +0 -1
  296. package/dist/ui/src/util/index.d.ts +0 -4
  297. package/dist/ui/src/util/key_to_icon_component.d.ts +0 -1
  298. /package/dist/{plugin-insights/src/engine → engine}/InsightsCache.d.ts +0 -0
  299. /package/dist/{plugin-insights/src/engine → engine}/useInsightsData.d.ts +0 -0
  300. /package/dist/{plugin-insights/src/types → types}/engine.d.ts +0 -0
  301. /package/dist/{plugin-insights/src/types → types}/index.d.ts +0 -0
  302. /package/dist/{plugin-insights/src/types → types}/widgets.d.ts +0 -0
  303. /package/dist/{plugin-insights/src/useInsightsPlugin.d.ts → useInsightsPlugin.d.ts} +0 -0
package/dist/index.umd.js CHANGED
@@ -1,1097 +1,646 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react/jsx-runtime"), require("react-compiler-runtime"), require("react"), require("@rebasepro/core"), require("@rebasepro/ui")) : typeof define === "function" && define.amd ? define(["exports", "react/jsx-runtime", "react-compiler-runtime", "react", "@rebasepro/core", "@rebasepro/ui"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.Rebase = {}, global.jsxRuntime, global.reactCompilerRuntime, global.React, global.core, global.ui));
3
- })(this, (function(exports2, jsxRuntime, reactCompilerRuntime, React, core, ui) {
4
- "use strict";
5
- class InsightsCache {
6
- constructor(ttl = 6e4) {
7
- this.ttl = ttl;
8
- }
9
- ttl;
10
- cache = /* @__PURE__ */ new Map();
11
- inflight = /* @__PURE__ */ new Map();
12
- get(key) {
13
- const entry = this.cache.get(key);
14
- if (!entry) return null;
15
- if (Date.now() - entry.timestamp > this.ttl) {
16
- this.cache.delete(key);
17
- return null;
18
- }
19
- return entry.data;
20
- }
21
- set(key, data) {
22
- this.cache.set(key, {
23
- data,
24
- timestamp: Date.now()
25
- });
26
- this.inflight.delete(key);
27
- }
28
- getInflight(key) {
29
- return this.inflight.get(key) ?? null;
30
- }
31
- setInflight(key, promise) {
32
- this.inflight.set(key, promise);
33
- }
34
- invalidate(key) {
35
- if (key) {
36
- this.cache.delete(key);
37
- this.inflight.delete(key);
38
- } else {
39
- this.cache.clear();
40
- this.inflight.clear();
41
- }
42
- }
43
- }
44
- const InsightsContext = React.createContext(null);
45
- function InsightsProvider(t0) {
46
- const $ = reactCompilerRuntime.c(7);
47
- const {
48
- cacheTTL,
49
- children
50
- } = t0;
51
- let t1;
52
- let t2;
53
- if ($[0] !== cacheTTL) {
54
- t2 = new InsightsCache(cacheTTL);
55
- $[0] = cacheTTL;
56
- $[1] = t2;
57
- } else {
58
- t2 = $[1];
59
- }
60
- t1 = t2;
61
- const cache = t1;
62
- let t3;
63
- let t4;
64
- if ($[2] !== cache) {
65
- t4 = {
66
- cache
67
- };
68
- $[2] = cache;
69
- $[3] = t4;
70
- } else {
71
- t4 = $[3];
72
- }
73
- t3 = t4;
74
- const value = t3;
75
- let t5;
76
- if ($[4] !== children || $[5] !== value) {
77
- t5 = /* @__PURE__ */ jsxRuntime.jsx(InsightsContext.Provider, { value, children });
78
- $[4] = children;
79
- $[5] = value;
80
- $[6] = t5;
81
- } else {
82
- t5 = $[6];
83
- }
84
- return t5;
85
- }
86
- function useInsightsEngine() {
87
- return React.useContext(InsightsContext);
88
- }
89
- function useInsightsData(definition, context) {
90
- const $ = reactCompilerRuntime.c(18);
91
- const engine = useInsightsEngine();
92
- const cache = engine?.cache ?? null;
93
- const {
94
- initialLoading,
95
- authLoading,
96
- user,
97
- loginSkipped
98
- } = core.useAuthController();
99
- const authReady = !initialLoading && !authLoading && (Boolean(user) || loginSkipped);
100
- const [data, setData] = React.useState(null);
101
- const [loading, setLoading] = React.useState(true);
102
- const [error, setError] = React.useState(null);
103
- const cacheKey = `${definition.id}:${context.path ?? context.collectionSlug ?? "global"}`;
104
- let t0;
105
- if ($[0] !== authReady || $[1] !== cache || $[2] !== cacheKey || $[3] !== context || $[4] !== definition) {
106
- t0 = () => {
107
- if (!authReady || !cache) {
108
- return;
109
- }
110
- let cancelled;
111
- cancelled = false;
112
- const cached = cache.get(cacheKey);
113
- if (cached) {
114
- setData(cached);
115
- setLoading(false);
116
- return;
117
- }
118
- const inflight = cache.getInflight(cacheKey);
119
- if (inflight) {
120
- setLoading(true);
121
- inflight.then((result) => {
122
- if (!cancelled) {
123
- setData(result);
124
- }
125
- }).catch((err) => {
126
- if (!cancelled) {
127
- setError(err instanceof Error ? err : new Error(String(err)));
128
- }
129
- }).finally(() => {
130
- if (!cancelled) {
131
- setLoading(false);
132
- }
133
- });
134
- return;
135
- }
136
- setLoading(true);
137
- setError(null);
138
- const promise = definition.data(context);
139
- cache.setInflight(cacheKey, promise);
140
- promise.then((result_0) => {
141
- cache.set(cacheKey, result_0);
142
- if (!cancelled) {
143
- setData(result_0);
144
- }
145
- }).catch((err_0) => {
146
- cache.invalidate(cacheKey);
147
- if (!cancelled) {
148
- setError(err_0 instanceof Error ? err_0 : new Error(String(err_0)));
149
- }
150
- }).finally(() => {
151
- if (!cancelled) {
152
- setLoading(false);
153
- }
154
- });
155
- return () => {
156
- cancelled = true;
157
- };
158
- };
159
- $[0] = authReady;
160
- $[1] = cache;
161
- $[2] = cacheKey;
162
- $[3] = context;
163
- $[4] = definition;
164
- $[5] = t0;
165
- } else {
166
- t0 = $[5];
167
- }
168
- let t1;
169
- if ($[6] !== authReady || $[7] !== cache || $[8] !== cacheKey || $[9] !== context.collectionSlug || $[10] !== context.path || $[11] !== definition.data || $[12] !== definition.id) {
170
- t1 = [definition.id, definition.data, context.path, context.collectionSlug, cacheKey, cache, authReady];
171
- $[6] = authReady;
172
- $[7] = cache;
173
- $[8] = cacheKey;
174
- $[9] = context.collectionSlug;
175
- $[10] = context.path;
176
- $[11] = definition.data;
177
- $[12] = definition.id;
178
- $[13] = t1;
179
- } else {
180
- t1 = $[13];
181
- }
182
- React.useEffect(t0, t1);
183
- let t2;
184
- if ($[14] !== data || $[15] !== error || $[16] !== loading) {
185
- t2 = {
186
- data,
187
- loading,
188
- error
189
- };
190
- $[14] = data;
191
- $[15] = error;
192
- $[16] = loading;
193
- $[17] = t2;
194
- } else {
195
- t2 = $[17];
196
- }
197
- return t2;
198
- }
199
- function formatNumber(value, format) {
200
- if (value === null || value === void 0) return "N/A";
201
- const options = {
202
- style: format?.style ?? "decimal",
203
- notation: format?.notation ?? "standard",
204
- maximumFractionDigits: format?.decimals ?? 1,
205
- minimumFractionDigits: format?.decimals ?? 1
206
- };
207
- if (format?.style === "currency") {
208
- options.currency = format.currency ?? "USD";
209
- }
210
- let formatted = new Intl.NumberFormat("en-US", options).format(value);
211
- if (format?.showSign && value > 0) {
212
- formatted = "+" + formatted;
213
- }
214
- return formatted;
215
- }
216
- function InsightsScorecardView(t0) {
217
- const $ = reactCompilerRuntime.c(59);
218
- const {
219
- config,
220
- data,
221
- title,
222
- compact: t1,
223
- embedded: t2,
224
- fixedHeight
225
- } = t0;
226
- const compact = t1 === void 0 ? false : t1;
227
- const embedded = t2 === void 0 ? false : t2;
228
- const containerRef = React.useRef(null);
229
- const [containerWidth, setContainerWidth] = React.useState(null);
230
- let t3;
231
- let t4;
232
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
233
- t3 = () => {
234
- if (!containerRef.current) {
235
- return;
236
- }
237
- setContainerWidth(containerRef.current.offsetWidth);
238
- const observer = new ResizeObserver((entries) => {
239
- for (const entry of entries) {
240
- setContainerWidth(entry.contentRect.width);
241
- }
242
- });
243
- observer.observe(containerRef.current);
244
- return () => observer.disconnect();
245
- };
246
- t4 = [];
247
- $[0] = t3;
248
- $[1] = t4;
249
- } else {
250
- t3 = $[0];
251
- t4 = $[1];
252
- }
253
- React.useLayoutEffect(t3, t4);
254
- const mainValue = data[config.value.field];
255
- let t5;
256
- if ($[2] !== config.value.format || $[3] !== mainValue) {
257
- t5 = typeof mainValue === "number" ? formatNumber(mainValue, config.value.format) : String(mainValue ?? "N/A");
258
- $[2] = config.value.format;
259
- $[3] = mainValue;
260
- $[4] = t5;
261
- } else {
262
- t5 = $[4];
263
- }
264
- const formattedValue = t5;
265
- let comparisonElement = null;
266
- if (config.comparison) {
267
- const comparisonValue = data[config.comparison.field];
268
- if (typeof comparisonValue === "number") {
269
- let t62;
270
- if ($[5] !== comparisonValue || $[6] !== config.comparison.format) {
271
- t62 = formatNumber(comparisonValue, config.comparison.format);
272
- $[5] = comparisonValue;
273
- $[6] = config.comparison.format;
274
- $[7] = t62;
275
- } else {
276
- t62 = $[7];
277
- }
278
- const formattedComparison = t62;
279
- const isPositive = comparisonValue > 0;
280
- const isNegative = comparisonValue < 0;
281
- let colorClass = "text-surface-500 dark:text-surface-400";
282
- if (config.comparison.intent === "increase_is_good") {
283
- if (isPositive) {
284
- colorClass = "text-emerald-500";
285
- }
286
- if (isNegative) {
287
- colorClass = "text-red-500";
288
- }
289
- } else {
290
- if (config.comparison.intent === "decrease_is_good") {
291
- if (isPositive) {
292
- colorClass = "text-red-500";
293
- }
294
- if (isNegative) {
295
- colorClass = "text-emerald-500";
296
- }
297
- }
298
- }
299
- const t72 = `font-medium ${compact ? "text-[10px]" : "text-xs"} ${colorClass}`;
300
- let t82;
301
- if ($[8] !== formattedComparison || $[9] !== t72) {
302
- t82 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: t72, children: formattedComparison });
303
- $[8] = formattedComparison;
304
- $[9] = t72;
305
- $[10] = t82;
306
- } else {
307
- t82 = $[10];
308
- }
309
- comparisonElement = t82;
310
- }
311
- }
312
- const isSmall = compact || containerWidth !== null && containerWidth < 200;
313
- let t6;
314
- if ($[11] !== config.icon || $[12] !== isSmall) {
315
- t6 = config.icon ? core.getIcon(config.icon, "text-surface-400 dark:text-surface-500", void 0, isSmall ? 14 : 18) : null;
316
- $[11] = config.icon;
317
- $[12] = isSmall;
318
- $[13] = t6;
319
- } else {
320
- t6 = $[13];
321
- }
322
- const iconElement = t6;
323
- if (compact) {
324
- let t72;
325
- if ($[14] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
326
- t72 = ui.cls("flex flex-col gap-0.5 px-2.5 py-2 rounded-md bg-transparent border min-w-0", ui.defaultBorderMixin);
327
- $[14] = t72;
328
- } else {
329
- t72 = $[14];
330
- }
331
- let t82;
332
- if ($[15] !== title) {
333
- t82 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider text-surface-400 dark:text-surface-500 truncate", children: title });
334
- $[15] = title;
335
- $[16] = t82;
336
- } else {
337
- t82 = $[16];
338
- }
339
- let t92;
340
- if ($[17] !== formattedValue) {
341
- t92 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold tabular-nums text-surface-800 dark:text-surface-100", children: formattedValue });
342
- $[17] = formattedValue;
343
- $[18] = t92;
344
- } else {
345
- t92 = $[18];
346
- }
347
- let t102;
348
- if ($[19] !== comparisonElement || $[20] !== t92) {
349
- t102 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
350
- t92,
351
- comparisonElement
352
- ] });
353
- $[19] = comparisonElement;
354
- $[20] = t92;
355
- $[21] = t102;
356
- } else {
357
- t102 = $[21];
358
- }
359
- let t112;
360
- if ($[22] !== t102 || $[23] !== t82) {
361
- t112 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t72, children: [
362
- t82,
363
- t102
364
- ] });
365
- $[22] = t102;
366
- $[23] = t82;
367
- $[24] = t112;
368
- } else {
369
- t112 = $[24];
370
- }
371
- return t112;
372
- }
373
- let t7;
374
- if ($[25] !== embedded || $[26] !== isSmall) {
375
- t7 = embedded ? `flex flex-col min-w-0 h-full ${isSmall ? "px-3.5 py-3" : "px-5 py-4"}` : ui.cls("rounded-lg flex flex-col min-w-0 bg-transparent border", ui.defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4");
376
- $[25] = embedded;
377
- $[26] = isSmall;
378
- $[27] = t7;
379
- } else {
380
- t7 = $[27];
381
- }
382
- const baseClass = t7;
383
- let t8;
384
- if ($[28] !== embedded || $[29] !== fixedHeight || $[30] !== isSmall) {
385
- t8 = embedded ? void 0 : fixedHeight ? {
386
- height: fixedHeight
387
- } : {
388
- minHeight: isSmall ? 68 : 92
389
- };
390
- $[28] = embedded;
391
- $[29] = fixedHeight;
392
- $[30] = isSmall;
393
- $[31] = t8;
394
- } else {
395
- t8 = $[31];
396
- }
397
- const t9 = `flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`;
398
- const t10 = `font-medium leading-snug truncate text-surface-500 dark:text-surface-400 ${isSmall ? "text-[11px]" : "text-xs"}`;
399
- let t11;
400
- if ($[32] !== t10 || $[33] !== title) {
401
- t11 = /* @__PURE__ */ jsxRuntime.jsx("span", { className: t10, children: title });
402
- $[32] = t10;
403
- $[33] = title;
404
- $[34] = t11;
405
- } else {
406
- t11 = $[34];
407
- }
408
- let t12;
409
- if ($[35] !== config.dateRange || $[36] !== isSmall) {
410
- t12 = config.dateRange && !isSmall && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-surface-400 dark:text-surface-500 truncate mt-0.5", children: config.dateRange });
411
- $[35] = config.dateRange;
412
- $[36] = isSmall;
413
- $[37] = t12;
414
- } else {
415
- t12 = $[37];
416
- }
417
- let t13;
418
- if ($[38] !== t11 || $[39] !== t12) {
419
- t13 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0", children: [
420
- t11,
421
- t12
422
- ] });
423
- $[38] = t11;
424
- $[39] = t12;
425
- $[40] = t13;
426
- } else {
427
- t13 = $[40];
428
- }
429
- let t14;
430
- if ($[41] !== iconElement) {
431
- t14 = iconElement && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 shrink-0", children: iconElement });
432
- $[41] = iconElement;
433
- $[42] = t14;
434
- } else {
435
- t14 = $[42];
436
- }
437
- let t15;
438
- if ($[43] !== t13 || $[44] !== t14 || $[45] !== t9) {
439
- t15 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t9, children: [
440
- t13,
441
- t14
442
- ] });
443
- $[43] = t13;
444
- $[44] = t14;
445
- $[45] = t9;
446
- $[46] = t15;
447
- } else {
448
- t15 = $[46];
449
- }
450
- const t16 = `font-semibold leading-tight tracking-tight break-all text-surface-800 dark:text-surface-100 ${isSmall ? "text-lg" : containerWidth !== null && containerWidth < 300 ? "text-xl" : "text-2xl"}`;
451
- let t17;
452
- if ($[47] !== formattedValue || $[48] !== t16) {
453
- t17 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: t16, children: formattedValue });
454
- $[47] = formattedValue;
455
- $[48] = t16;
456
- $[49] = t17;
457
- } else {
458
- t17 = $[49];
459
- }
460
- let t18;
461
- if ($[50] !== comparisonElement || $[51] !== isSmall) {
462
- t18 = comparisonElement && /* @__PURE__ */ jsxRuntime.jsx("div", { className: isSmall ? "mt-0.5" : "mt-1", children: comparisonElement });
463
- $[50] = comparisonElement;
464
- $[51] = isSmall;
465
- $[52] = t18;
466
- } else {
467
- t18 = $[52];
468
- }
469
- let t19;
470
- if ($[53] !== baseClass || $[54] !== t15 || $[55] !== t17 || $[56] !== t18 || $[57] !== t8) {
471
- t19 = /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: baseClass, style: t8, children: [
472
- t15,
473
- t17,
474
- t18
475
- ] });
476
- $[53] = baseClass;
477
- $[54] = t15;
478
- $[55] = t17;
479
- $[56] = t18;
480
- $[57] = t8;
481
- $[58] = t19;
482
- } else {
483
- t19 = $[58];
484
- }
485
- return t19;
486
- }
487
- InsightsScorecardView.displayName = "InsightsScorecardView";
488
- function InsightWidgetSkeleton(t0) {
489
- const $ = reactCompilerRuntime.c(18);
490
- const {
491
- config,
492
- compact: t1,
493
- embedded: t2,
494
- fixedHeight
495
- } = t0;
496
- const compact = t1 === void 0 ? false : t1;
497
- const embedded = t2 === void 0 ? false : t2;
498
- const hasComparison = Boolean(config.comparison);
499
- const hasIcon = Boolean(config.icon);
500
- const hasDateRange = Boolean(config.dateRange);
501
- if (compact) {
502
- const t32 = embedded ? "h-full px-2.5 py-2" : "flex flex-col gap-0.5 rounded-md bg-transparent border min-w-0 px-2.5 py-2";
503
- const t4 = !embedded && ui.defaultBorderMixin;
504
- let t5;
505
- if ($[0] !== t32 || $[1] !== t4) {
506
- t5 = ui.cls("animate-pulse", t32, t4);
507
- $[0] = t32;
508
- $[1] = t4;
509
- $[2] = t5;
510
- } else {
511
- t5 = $[2];
512
- }
513
- let t6;
514
- if ($[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
515
- t6 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200 dark:bg-surface-700 rounded-sm", style: {
516
- height: 14,
517
- width: 48
518
- } });
519
- $[3] = t6;
520
- } else {
521
- t6 = $[3];
522
- }
523
- let t7;
524
- if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
525
- t7 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200 dark:bg-surface-700 rounded-sm", style: {
526
- height: 20,
527
- width: 40
528
- } });
529
- $[4] = t7;
530
- } else {
531
- t7 = $[4];
532
- }
533
- let t8;
534
- if ($[5] !== hasComparison) {
535
- t8 = hasComparison && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200/60 dark:bg-surface-700/60 rounded-sm", style: {
536
- height: 14,
537
- width: 28
538
- } });
539
- $[5] = hasComparison;
540
- $[6] = t8;
541
- } else {
542
- t8 = $[6];
543
- }
544
- let t9;
545
- if ($[7] !== t8) {
546
- t9 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-1.5", children: [
547
- t7,
548
- t8
549
- ] });
550
- $[7] = t8;
551
- $[8] = t9;
552
- } else {
553
- t9 = $[8];
554
- }
555
- let t10;
556
- if ($[9] !== t5 || $[10] !== t9) {
557
- t10 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t5, children: [
558
- t6,
559
- t9
560
- ] });
561
- $[9] = t5;
562
- $[10] = t9;
563
- $[11] = t10;
564
- } else {
565
- t10 = $[11];
566
- }
567
- return t10;
568
- }
569
- let t3;
570
- if ($[12] !== embedded || $[13] !== fixedHeight || $[14] !== hasComparison || $[15] !== hasDateRange || $[16] !== hasIcon) {
571
- t3 = /* @__PURE__ */ jsxRuntime.jsx(StandardSkeleton, { hasComparison, hasIcon, hasDateRange, embedded, fixedHeight });
572
- $[12] = embedded;
573
- $[13] = fixedHeight;
574
- $[14] = hasComparison;
575
- $[15] = hasDateRange;
576
- $[16] = hasIcon;
577
- $[17] = t3;
578
- } else {
579
- t3 = $[17];
580
- }
581
- return t3;
582
- }
583
- function StandardSkeleton(t0) {
584
- const $ = reactCompilerRuntime.c(37);
585
- const {
586
- hasComparison,
587
- hasIcon,
588
- hasDateRange,
589
- embedded,
590
- fixedHeight
591
- } = t0;
592
- const containerRef = React.useRef(null);
593
- const [containerWidth, setContainerWidth] = React.useState(null);
594
- let t1;
595
- let t2;
596
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
597
- t1 = () => {
598
- if (!containerRef.current) {
599
- return;
600
- }
601
- setContainerWidth(containerRef.current.offsetWidth);
602
- const observer = new ResizeObserver((entries) => {
603
- for (const entry of entries) {
604
- setContainerWidth(entry.contentRect.width);
605
- }
606
- });
607
- observer.observe(containerRef.current);
608
- return () => observer.disconnect();
609
- };
610
- t2 = [];
611
- $[0] = t1;
612
- $[1] = t2;
613
- } else {
614
- t1 = $[0];
615
- t2 = $[1];
616
- }
617
- React.useLayoutEffect(t1, t2);
618
- const isSmall = containerWidth !== null && containerWidth < 200;
619
- const titleHeight = isSmall ? 15 : 16.5;
620
- const valueHeight = isSmall ? 22.5 : containerWidth !== null && containerWidth < 300 ? 25 : 30;
621
- const iconSize = isSmall ? 14 : 18;
622
- let t3;
623
- let t4;
624
- if ($[2] !== embedded || $[3] !== isSmall) {
625
- const baseClass = embedded ? `flex flex-col min-w-0 h-full ${isSmall ? "px-3.5 py-3" : "px-5 py-4"}` : ui.cls("rounded-lg flex flex-col min-w-0 bg-transparent border", ui.defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4");
626
- t3 = containerRef;
627
- t4 = ui.cls("animate-pulse", baseClass);
628
- $[2] = embedded;
629
- $[3] = isSmall;
630
- $[4] = t3;
631
- $[5] = t4;
632
- } else {
633
- t3 = $[4];
634
- t4 = $[5];
635
- }
636
- let t5;
637
- if ($[6] !== embedded || $[7] !== fixedHeight || $[8] !== isSmall) {
638
- t5 = embedded ? void 0 : fixedHeight ? {
639
- height: fixedHeight
640
- } : {
641
- minHeight: isSmall ? 68 : 92
642
- };
643
- $[6] = embedded;
644
- $[7] = fixedHeight;
645
- $[8] = isSmall;
646
- $[9] = t5;
647
- } else {
648
- t5 = $[9];
649
- }
650
- const t6 = `flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`;
651
- let t7;
652
- if ($[10] !== titleHeight) {
653
- t7 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200 dark:bg-surface-700 rounded", style: {
654
- height: titleHeight,
655
- width: "60%"
656
- } });
657
- $[10] = titleHeight;
658
- $[11] = t7;
659
- } else {
660
- t7 = $[11];
661
- }
662
- let t8;
663
- if ($[12] !== hasDateRange || $[13] !== isSmall) {
664
- t8 = hasDateRange && !isSmall && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200/60 dark:bg-surface-700/60 rounded mt-0.5", style: {
665
- height: 14,
666
- width: "40%"
667
- } });
668
- $[12] = hasDateRange;
669
- $[13] = isSmall;
670
- $[14] = t8;
671
- } else {
672
- t8 = $[14];
673
- }
674
- let t9;
675
- if ($[15] !== t7 || $[16] !== t8) {
676
- t9 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0", children: [
677
- t7,
678
- t8
679
- ] });
680
- $[15] = t7;
681
- $[16] = t8;
682
- $[17] = t9;
683
- } else {
684
- t9 = $[17];
685
- }
686
- let t10;
687
- if ($[18] !== hasIcon || $[19] !== iconSize) {
688
- t10 = hasIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200 dark:bg-surface-700 rounded", style: {
689
- height: iconSize,
690
- width: iconSize
691
- } }) });
692
- $[18] = hasIcon;
693
- $[19] = iconSize;
694
- $[20] = t10;
695
- } else {
696
- t10 = $[20];
697
- }
698
- let t11;
699
- if ($[21] !== t10 || $[22] !== t6 || $[23] !== t9) {
700
- t11 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t6, children: [
701
- t9,
702
- t10
703
- ] });
704
- $[21] = t10;
705
- $[22] = t6;
706
- $[23] = t9;
707
- $[24] = t11;
708
- } else {
709
- t11 = $[24];
710
- }
711
- let t12;
712
- if ($[25] !== valueHeight) {
713
- t12 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200 dark:bg-surface-700 rounded", style: {
714
- height: valueHeight,
715
- width: "40%"
716
- } });
717
- $[25] = valueHeight;
718
- $[26] = t12;
719
- } else {
720
- t12 = $[26];
721
- }
722
- let t13;
723
- if ($[27] !== hasComparison || $[28] !== isSmall) {
724
- t13 = hasComparison && /* @__PURE__ */ jsxRuntime.jsx("div", { className: isSmall ? "mt-0.5" : "mt-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-surface-200/60 dark:bg-surface-700/60 rounded", style: {
725
- height: 16,
726
- width: "25%"
727
- } }) });
728
- $[27] = hasComparison;
729
- $[28] = isSmall;
730
- $[29] = t13;
731
- } else {
732
- t13 = $[29];
733
- }
734
- let t14;
735
- if ($[30] !== t11 || $[31] !== t12 || $[32] !== t13 || $[33] !== t3 || $[34] !== t4 || $[35] !== t5) {
736
- t14 = /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: t3, className: t4, style: t5, children: [
737
- t11,
738
- t12,
739
- t13
740
- ] });
741
- $[30] = t11;
742
- $[31] = t12;
743
- $[32] = t13;
744
- $[33] = t3;
745
- $[34] = t4;
746
- $[35] = t5;
747
- $[36] = t14;
748
- } else {
749
- t14 = $[36];
750
- }
751
- return t14;
752
- }
753
- InsightWidgetSkeleton.displayName = "InsightWidgetSkeleton";
754
- function computeFixedHeight(config) {
755
- let h = 86.5;
756
- if (config.dateRange) h += 16;
757
- if (config.comparison) h += 20;
758
- return Math.ceil(h);
759
- }
760
- function InsightWidget(t0) {
761
- const $ = reactCompilerRuntime.c(37);
762
- const {
763
- definition,
764
- collectionSlug,
765
- path,
766
- parentCollectionSlugs,
767
- compact: t1,
768
- embedded: t2
769
- } = t0;
770
- const compact = t1 === void 0 ? false : t1;
771
- const embedded = t2 === void 0 ? false : t2;
772
- let t3;
773
- if ($[0] !== collectionSlug || $[1] !== parentCollectionSlugs || $[2] !== path) {
774
- t3 = {
775
- path,
776
- collectionSlug,
777
- parentCollectionSlugs
778
- };
779
- $[0] = collectionSlug;
780
- $[1] = parentCollectionSlugs;
781
- $[2] = path;
782
- $[3] = t3;
783
- } else {
784
- t3 = $[3];
785
- }
786
- const {
787
- data,
788
- loading,
789
- error
790
- } = useInsightsData(definition, t3);
791
- let t4;
792
- if ($[4] !== compact || $[5] !== definition.scorecard || $[6] !== embedded) {
793
- t4 = !compact && !embedded ? computeFixedHeight(definition.scorecard) : void 0;
794
- $[4] = compact;
795
- $[5] = definition.scorecard;
796
- $[6] = embedded;
797
- $[7] = t4;
798
- } else {
799
- t4 = $[7];
800
- }
801
- const fixedHeight = t4;
802
- if (loading) {
803
- let t52;
804
- if ($[8] !== compact || $[9] !== definition.scorecard || $[10] !== embedded || $[11] !== fixedHeight) {
805
- t52 = /* @__PURE__ */ jsxRuntime.jsx(InsightWidgetSkeleton, { config: definition.scorecard, compact, embedded, fixedHeight });
806
- $[8] = compact;
807
- $[9] = definition.scorecard;
808
- $[10] = embedded;
809
- $[11] = fixedHeight;
810
- $[12] = t52;
811
- } else {
812
- t52 = $[12];
813
- }
814
- return t52;
815
- }
816
- if (error) {
817
- const t52 = `text-red-500/70 dark:text-red-400/70 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-red-500/5 dark:bg-red-400/5 border border-red-500/10 dark:border-red-400/10 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`;
818
- let t62;
819
- if ($[13] !== fixedHeight) {
820
- t62 = fixedHeight ? {
821
- height: fixedHeight
822
- } : void 0;
823
- $[13] = fixedHeight;
824
- $[14] = t62;
825
- } else {
826
- t62 = $[14];
827
- }
828
- let t7;
829
- if ($[15] !== definition.title) {
830
- t7 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: definition.title });
831
- $[15] = definition.title;
832
- $[16] = t7;
833
- } else {
834
- t7 = $[16];
835
- }
836
- let t8;
837
- if ($[17] !== error.message) {
838
- t8 = /* @__PURE__ */ jsxRuntime.jsx("div", { children: error.message });
839
- $[17] = error.message;
840
- $[18] = t8;
841
- } else {
842
- t8 = $[18];
843
- }
844
- let t9;
845
- if ($[19] !== t52 || $[20] !== t62 || $[21] !== t7 || $[22] !== t8) {
846
- t9 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t52, style: t62, children: [
847
- t7,
848
- t8
849
- ] });
850
- $[19] = t52;
851
- $[20] = t62;
852
- $[21] = t7;
853
- $[22] = t8;
854
- $[23] = t9;
855
- } else {
856
- t9 = $[23];
857
- }
858
- return t9;
859
- }
860
- if (!data || data.rows.length === 0) {
861
- const t52 = `text-surface-400 dark:text-surface-500 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-surface-100 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`;
862
- let t62;
863
- if ($[24] !== fixedHeight) {
864
- t62 = fixedHeight ? {
865
- height: fixedHeight
866
- } : void 0;
867
- $[24] = fixedHeight;
868
- $[25] = t62;
869
- } else {
870
- t62 = $[25];
871
- }
872
- let t7;
873
- if ($[26] !== definition.title || $[27] !== t52 || $[28] !== t62) {
874
- t7 = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: t52, style: t62, children: [
875
- definition.title,
876
- " — No data"
877
- ] });
878
- $[26] = definition.title;
879
- $[27] = t52;
880
- $[28] = t62;
881
- $[29] = t7;
882
- } else {
883
- t7 = $[29];
884
- }
885
- return t7;
886
- }
887
- const t5 = data.rows[0];
888
- let t6;
889
- if ($[30] !== compact || $[31] !== definition.scorecard || $[32] !== definition.title || $[33] !== embedded || $[34] !== fixedHeight || $[35] !== t5) {
890
- t6 = /* @__PURE__ */ jsxRuntime.jsx(InsightsScorecardView, { config: definition.scorecard, data: t5, title: definition.title, compact, embedded, fixedHeight });
891
- $[30] = compact;
892
- $[31] = definition.scorecard;
893
- $[32] = definition.title;
894
- $[33] = embedded;
895
- $[34] = fixedHeight;
896
- $[35] = t5;
897
- $[36] = t6;
898
- } else {
899
- t6 = $[36];
900
- }
901
- return t6;
902
- }
903
- InsightWidget.displayName = "InsightWidget";
904
- function HomeCardInsightSlot(t0) {
905
- const $ = reactCompilerRuntime.c(10);
906
- const {
907
- slug,
908
- insights
909
- } = t0;
910
- if (!insights || insights.length === 0) {
911
- return null;
912
- }
913
- const estimatedRows = Math.ceil(insights.length / 2);
914
- const minHeight = estimatedRows * 42 + (estimatedRows - 1) * 6;
915
- let t1;
916
- if ($[0] !== minHeight) {
917
- t1 = {
918
- minHeight
919
- };
920
- $[0] = minHeight;
921
- $[1] = t1;
922
- } else {
923
- t1 = $[1];
924
- }
925
- let t2;
926
- if ($[2] !== insights || $[3] !== slug) {
927
- let t32;
928
- if ($[5] !== slug) {
929
- t32 = (def) => /* @__PURE__ */ jsxRuntime.jsx(InsightWidget, { definition: def, collectionSlug: slug, compact: true }, def.id);
930
- $[5] = slug;
931
- $[6] = t32;
932
- } else {
933
- t32 = $[6];
934
- }
935
- t2 = insights.map(t32);
936
- $[2] = insights;
937
- $[3] = slug;
938
- $[4] = t2;
939
- } else {
940
- t2 = $[4];
941
- }
942
- let t3;
943
- if ($[7] !== t1 || $[8] !== t2) {
944
- t3 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5 mt-2", style: t1, children: t2 });
945
- $[7] = t1;
946
- $[8] = t2;
947
- $[9] = t3;
948
- } else {
949
- t3 = $[9];
950
- }
951
- return t3;
952
- }
953
- HomeCardInsightSlot.displayName = "HomeCardInsightSlot";
954
- function HomeInsightsSlot(t0) {
955
- const $ = reactCompilerRuntime.c(5);
956
- const {
957
- insights
958
- } = t0;
959
- if (!insights || insights.length === 0) {
960
- return null;
961
- }
962
- let t1;
963
- if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
964
- t1 = {
965
- minHeight: 92
966
- };
967
- $[0] = t1;
968
- } else {
969
- t1 = $[0];
970
- }
971
- let t2;
972
- if ($[1] !== insights) {
973
- t2 = insights.map(_temp);
974
- $[1] = insights;
975
- $[2] = t2;
976
- } else {
977
- t2 = $[2];
978
- }
979
- let t3;
980
- if ($[3] !== t2) {
981
- t3 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-6", style: t1, children: t2 });
982
- $[3] = t2;
983
- $[4] = t3;
984
- } else {
985
- t3 = $[4];
986
- }
987
- return t3;
988
- }
989
- function _temp(def) {
990
- return /* @__PURE__ */ jsxRuntime.jsx(InsightWidget, { definition: def }, def.id);
991
- }
992
- HomeInsightsSlot.displayName = "HomeInsightsSlot";
993
- function CollectionInsightsInline(t0) {
994
- const $ = reactCompilerRuntime.c(11);
995
- const {
996
- insights,
997
- path,
998
- parentCollectionSlugs,
999
- parentEntityIds
1000
- } = t0;
1001
- if (!insights || insights.length === 0) {
1002
- return null;
1003
- }
1004
- let t1;
1005
- if ($[0] !== insights || $[1] !== parentCollectionSlugs || $[2] !== parentEntityIds || $[3] !== path) {
1006
- let t22;
1007
- if ($[5] !== parentCollectionSlugs || $[6] !== parentEntityIds || $[7] !== path) {
1008
- t22 = (def) => /* @__PURE__ */ jsxRuntime.jsx(InsightWidget, { definition: def, path, parentCollectionSlugs, parentEntityIds }, def.id);
1009
- $[5] = parentCollectionSlugs;
1010
- $[6] = parentEntityIds;
1011
- $[7] = path;
1012
- $[8] = t22;
1013
- } else {
1014
- t22 = $[8];
1015
- }
1016
- t1 = insights.map(t22);
1017
- $[0] = insights;
1018
- $[1] = parentCollectionSlugs;
1019
- $[2] = parentEntityIds;
1020
- $[3] = path;
1021
- $[4] = t1;
1022
- } else {
1023
- t1 = $[4];
1024
- }
1025
- let t2;
1026
- if ($[9] !== t1) {
1027
- t2 = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-4", children: t1 });
1028
- $[9] = t1;
1029
- $[10] = t2;
1030
- } else {
1031
- t2 = $[10];
1032
- }
1033
- return t2;
1034
- }
1035
- CollectionInsightsInline.displayName = "CollectionInsightsInline";
1036
- function useInsightsPlugin(config) {
1037
- const {
1038
- insights,
1039
- cacheTTL
1040
- } = config;
1041
- const slots = [];
1042
- if (insights.home && insights.home.length > 0) {
1043
- const homeInsights = insights.home;
1044
- slots.push({
1045
- slot: "home.children.start",
1046
- Component: (props) => /* @__PURE__ */ jsxRuntime.jsx(HomeInsightsSlot, { ...props, insights: homeInsights }),
1047
- order: 10
1048
- });
1049
- }
1050
- if (insights.collections) {
1051
- for (const [slug, defs] of Object.entries(insights.collections)) {
1052
- if (defs.length === 0) continue;
1053
- const collectionInsights = defs;
1054
- slots.push({
1055
- slot: "collection.insights",
1056
- Component: (props) => {
1057
- const path = props.path;
1058
- const collectionSlug = path?.split("/").filter(Boolean).pop() ?? "";
1059
- if (collectionSlug !== slug) return null;
1060
- return /* @__PURE__ */ jsxRuntime.jsx(CollectionInsightsInline, { ...props, insights: collectionInsights });
1061
- },
1062
- order: 10
1063
- });
1064
- slots.push({
1065
- slot: "home.card.insight",
1066
- Component: (props) => {
1067
- const cardSlug = props.slug;
1068
- if (cardSlug !== slug) return null;
1069
- return /* @__PURE__ */ jsxRuntime.jsx(HomeCardInsightSlot, { ...props, insights: collectionInsights });
1070
- },
1071
- order: 10
1072
- });
1073
- }
1074
- }
1075
- return {
1076
- key: "plugin-insights",
1077
- slots,
1078
- providers: [{
1079
- scope: "root",
1080
- Component: InsightsProvider,
1081
- props: {
1082
- cacheTTL
1083
- }
1084
- }]
1085
- };
1086
- }
1087
- exports2.InsightWidget = InsightWidget;
1088
- exports2.InsightWidgetSkeleton = InsightWidgetSkeleton;
1089
- exports2.InsightsCache = InsightsCache;
1090
- exports2.InsightsProvider = InsightsProvider;
1091
- exports2.InsightsScorecardView = InsightsScorecardView;
1092
- exports2.useInsightsData = useInsightsData;
1093
- exports2.useInsightsEngine = useInsightsEngine;
1094
- exports2.useInsightsPlugin = useInsightsPlugin;
1095
- Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
1096
- }));
1097
- //# sourceMappingURL=index.umd.js.map
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react/jsx-runtime"), require("@rebasepro/core"), require("@rebasepro/ui")) : typeof define === "function" && define.amd ? define([
3
+ "exports",
4
+ "react",
5
+ "react/jsx-runtime",
6
+ "@rebasepro/core",
7
+ "@rebasepro/ui"
8
+ ], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.Rebase = {}, global.react, global.react_jsx_runtime, global._rebasepro_core, global._rebasepro_ui));
9
+ })(this, function(exports, react, react_jsx_runtime, _rebasepro_core, _rebasepro_ui) {
10
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
11
+ //#region \0rolldown/runtime.js
12
+ var __create = Object.create;
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
+ var __getOwnPropNames = Object.getOwnPropertyNames;
16
+ var __getProtoOf = Object.getPrototypeOf;
17
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
20
+ key = keys[i];
21
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
22
+ get: ((k) => from[k]).bind(null, key),
23
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
24
+ });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
29
+ value: mod,
30
+ enumerable: true
31
+ }) : target, mod));
32
+ //#endregion
33
+ react = __toESM(react, 1);
34
+ //#region src/engine/InsightsCache.ts
35
+ /**
36
+ * In-memory cache for insight query results.
37
+ * Supports TTL-based expiry and inflight request deduplication
38
+ * to prevent redundant network requests when multiple widgets
39
+ * share the same query.
40
+ */
41
+ var InsightsCache = class {
42
+ ttl;
43
+ cache = /* @__PURE__ */ new Map();
44
+ inflight = /* @__PURE__ */ new Map();
45
+ constructor(ttl = 6e4) {
46
+ this.ttl = ttl;
47
+ }
48
+ get(key) {
49
+ const entry = this.cache.get(key);
50
+ if (!entry) return null;
51
+ if (Date.now() - entry.timestamp > this.ttl) {
52
+ this.cache.delete(key);
53
+ return null;
54
+ }
55
+ return entry.data;
56
+ }
57
+ set(key, data) {
58
+ this.cache.set(key, {
59
+ data,
60
+ timestamp: Date.now()
61
+ });
62
+ this.inflight.delete(key);
63
+ }
64
+ getInflight(key) {
65
+ return this.inflight.get(key) ?? null;
66
+ }
67
+ setInflight(key, promise) {
68
+ this.inflight.set(key, promise);
69
+ }
70
+ invalidate(key) {
71
+ if (key) {
72
+ this.cache.delete(key);
73
+ this.inflight.delete(key);
74
+ } else {
75
+ this.cache.clear();
76
+ this.inflight.clear();
77
+ }
78
+ }
79
+ };
80
+ //#endregion
81
+ //#region src/engine/InsightsProvider.tsx
82
+ var InsightsContext = (0, react.createContext)(null);
83
+ /**
84
+ * Root-level provider for the insights data engine.
85
+ * Injected automatically by the plugin via `providers: [{ scope: "root" }]`.
86
+ *
87
+ * Manages a single `InsightsCache` instance shared by all insight widgets
88
+ * for TTL-based caching and inflight request deduplication.
89
+ */
90
+ function InsightsProvider({ cacheTTL, children }) {
91
+ const cache = (0, react.useMemo)(() => new InsightsCache(cacheTTL), [cacheTTL]);
92
+ const value = (0, react.useMemo)(() => ({ cache }), [cache]);
93
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightsContext.Provider, {
94
+ value,
95
+ children
96
+ });
97
+ }
98
+ /**
99
+ * Access the insights cache (for advanced usage).
100
+ * Returns null when called outside of an `InsightsProvider`
101
+ * (e.g. during auth-loading phase before plugin providers mount).
102
+ */
103
+ function useInsightsEngine() {
104
+ return (0, react.useContext)(InsightsContext);
105
+ }
106
+ //#endregion
107
+ //#region src/engine/useInsightsData.ts
108
+ /**
109
+ * Hook that fetches and caches data for a single insight definition.
110
+ *
111
+ * Calls the definition's own `data()` callback and manages:
112
+ * - TTL-based caching via InsightsCache
113
+ * - Inflight request deduplication (multiple mounts of the same widget)
114
+ * - Loading and error state management
115
+ *
116
+ * @param definition - The insight to fetch data for
117
+ * @param collectionSlug - Optional collection context for cache key scoping
118
+ */
119
+ function useInsightsData(definition, context) {
120
+ const cache = useInsightsEngine()?.cache ?? null;
121
+ const { initialLoading, authLoading, user, loginSkipped } = (0, _rebasepro_core.useAuthController)();
122
+ const authReady = !initialLoading && !authLoading && (Boolean(user) || loginSkipped);
123
+ const [data, setData] = (0, react.useState)(null);
124
+ const [loading, setLoading] = (0, react.useState)(true);
125
+ const [error, setError] = (0, react.useState)(null);
126
+ const cacheKey = `${definition.id}:${context.path ?? context.collectionSlug ?? "global"}`;
127
+ (0, react.useEffect)(() => {
128
+ if (!authReady || !cache) return;
129
+ let cancelled = false;
130
+ const cached = cache.get(cacheKey);
131
+ if (cached) {
132
+ setData(cached);
133
+ setLoading(false);
134
+ return;
135
+ }
136
+ const inflight = cache.getInflight(cacheKey);
137
+ if (inflight) {
138
+ setLoading(true);
139
+ inflight.then((result) => {
140
+ if (!cancelled) setData(result);
141
+ }).catch((err) => {
142
+ if (!cancelled) setError(err instanceof Error ? err : new Error(String(err)));
143
+ }).finally(() => {
144
+ if (!cancelled) setLoading(false);
145
+ });
146
+ return;
147
+ }
148
+ setLoading(true);
149
+ setError(null);
150
+ const promise = definition.data(context);
151
+ cache.setInflight(cacheKey, promise);
152
+ promise.then((result) => {
153
+ cache.set(cacheKey, result);
154
+ if (!cancelled) setData(result);
155
+ }).catch((err) => {
156
+ cache.invalidate(cacheKey);
157
+ if (!cancelled) setError(err instanceof Error ? err : new Error(String(err)));
158
+ }).finally(() => {
159
+ if (!cancelled) setLoading(false);
160
+ });
161
+ return () => {
162
+ cancelled = true;
163
+ };
164
+ }, [
165
+ definition.id,
166
+ definition.data,
167
+ context.path,
168
+ context.collectionSlug,
169
+ cacheKey,
170
+ cache,
171
+ authReady
172
+ ]);
173
+ return {
174
+ data,
175
+ loading,
176
+ error
177
+ };
178
+ }
179
+ //#endregion
180
+ //#region src/components/InsightsScorecardView.tsx
181
+ function formatNumber(value, format) {
182
+ if (value === null || value === void 0) return "N/A";
183
+ const options = {
184
+ style: format?.style ?? "decimal",
185
+ notation: format?.notation ?? "standard",
186
+ maximumFractionDigits: format?.decimals ?? 1,
187
+ minimumFractionDigits: format?.decimals ?? 1
188
+ };
189
+ if (format?.style === "currency") options.currency = format.currency ?? "USD";
190
+ let formatted = new Intl.NumberFormat("en-US", options).format(value);
191
+ if (format?.showSign && value > 0) formatted = "+" + formatted;
192
+ return formatted;
193
+ }
194
+ /**
195
+ * Scorecard widget for the Rebase design system.
196
+ *
197
+ * Renders a single KPI metric with optional comparison value and icon.
198
+ * Uses Tailwind `dark:` classes — no JS dark mode detection.
199
+ * Icons are resolved via `getIcon` from `@rebasepro/core`.
200
+ */
201
+ function InsightsScorecardView({ config, data, title, compact = false, embedded = false, fixedHeight }) {
202
+ const containerRef = (0, react.useRef)(null);
203
+ const [containerWidth, setContainerWidth] = (0, react.useState)(null);
204
+ react.default.useLayoutEffect(() => {
205
+ if (!containerRef.current) return;
206
+ setContainerWidth(containerRef.current.offsetWidth);
207
+ const observer = new ResizeObserver((entries) => {
208
+ for (const entry of entries) setContainerWidth(entry.contentRect.width);
209
+ });
210
+ observer.observe(containerRef.current);
211
+ return () => observer.disconnect();
212
+ }, []);
213
+ const mainValue = data[config.value.field];
214
+ const formattedValue = typeof mainValue === "number" ? formatNumber(mainValue, config.value.format) : String(mainValue ?? "N/A");
215
+ let comparisonElement = null;
216
+ if (config.comparison) {
217
+ const comparisonValue = data[config.comparison.field];
218
+ if (typeof comparisonValue === "number") {
219
+ const formattedComparison = formatNumber(comparisonValue, config.comparison.format);
220
+ const isPositive = comparisonValue > 0;
221
+ const isNegative = comparisonValue < 0;
222
+ let colorClass = "text-surface-500 dark:text-surface-400";
223
+ if (config.comparison.intent === "increase_is_good") {
224
+ if (isPositive) colorClass = "text-emerald-500";
225
+ if (isNegative) colorClass = "text-red-500";
226
+ } else if (config.comparison.intent === "decrease_is_good") {
227
+ if (isPositive) colorClass = "text-red-500";
228
+ if (isNegative) colorClass = "text-emerald-500";
229
+ }
230
+ comparisonElement = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
231
+ className: `font-medium ${compact ? "text-[10px]" : "text-xs"} ${colorClass}`,
232
+ children: formattedComparison
233
+ });
234
+ }
235
+ }
236
+ const isSmall = compact || containerWidth !== null && containerWidth < 200;
237
+ const iconElement = config.icon ? (0, _rebasepro_core.getIcon)(config.icon, "text-surface-400 dark:text-surface-500", void 0, isSmall ? 14 : 18) : null;
238
+ if (compact) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
239
+ className: (0, _rebasepro_ui.cls)("flex flex-col gap-0.5 px-2.5 py-2 rounded-md bg-transparent border min-w-0", _rebasepro_ui.defaultBorderMixin),
240
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
241
+ className: "text-[10px] uppercase tracking-wider text-surface-400 dark:text-surface-500 truncate",
242
+ children: title
243
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
244
+ className: "flex items-baseline gap-1.5",
245
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
246
+ className: "text-sm font-semibold tabular-nums text-surface-800 dark:text-surface-100",
247
+ children: formattedValue
248
+ }), comparisonElement]
249
+ })]
250
+ });
251
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
252
+ ref: containerRef,
253
+ className: embedded ? `flex flex-col min-w-0 h-full ${isSmall ? "px-3.5 py-3" : "px-5 py-4"}` : (0, _rebasepro_ui.cls)("rounded-lg flex flex-col min-w-0 bg-transparent border", _rebasepro_ui.defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4"),
254
+ style: embedded ? void 0 : fixedHeight ? { height: fixedHeight } : { minHeight: isSmall ? 68 : 92 },
255
+ children: [
256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
257
+ className: `flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`,
258
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
259
+ className: "flex flex-col min-w-0",
260
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
261
+ className: `font-medium leading-snug truncate text-surface-500 dark:text-surface-400 ${isSmall ? "text-[11px]" : "text-xs"}`,
262
+ children: title
263
+ }), config.dateRange && !isSmall && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
264
+ className: "text-[10px] text-surface-400 dark:text-surface-500 truncate mt-0.5",
265
+ children: config.dateRange
266
+ })]
267
+ }), iconElement && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
268
+ className: "ml-2 shrink-0",
269
+ children: iconElement
270
+ })]
271
+ }),
272
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
273
+ className: `font-semibold leading-tight tracking-tight break-all text-surface-800 dark:text-surface-100 ${isSmall ? "text-lg" : containerWidth !== null && containerWidth < 300 ? "text-xl" : "text-2xl"}`,
274
+ children: formattedValue
275
+ }),
276
+ comparisonElement && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
277
+ className: isSmall ? "mt-0.5" : "mt-1",
278
+ children: comparisonElement
279
+ })
280
+ ]
281
+ });
282
+ }
283
+ InsightsScorecardView.displayName = "InsightsScorecardView";
284
+ //#endregion
285
+ //#region src/components/InsightWidgetSkeleton.tsx
286
+ /**
287
+ * Skeleton loader for scorecard insight widgets — displays animated
288
+ * shimmer placeholders that exactly match the final rendered layout
289
+ * of InsightsScorecardView for a given config, preventing layout shift.
290
+ *
291
+ * The skeleton receives the scorecard config so it can conditionally
292
+ * render placeholder lines for comparison, dateRange, and icon —
293
+ * only when the loaded view will also render them.
294
+ *
295
+ * The standard skeleton mirrors InsightsScorecardView's responsive
296
+ * container-width breakpoints (ResizeObserver → isSmall / isMedium)
297
+ * and uses placeholder heights that exactly match the **computed**
298
+ * Tailwind line-heights (accounting for `leading-*` overrides).
299
+ * This guarantees a pixel-perfect skeleton loaded transition.
300
+ */
301
+ function InsightWidgetSkeleton({ config, compact = false, embedded = false, fixedHeight }) {
302
+ const hasComparison = Boolean(config.comparison);
303
+ const hasIcon = Boolean(config.icon);
304
+ const hasDateRange = Boolean(config.dateRange);
305
+ if (compact) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
306
+ className: (0, _rebasepro_ui.cls)("animate-pulse", embedded ? "h-full px-2.5 py-2" : "flex flex-col gap-0.5 rounded-md bg-transparent border min-w-0 px-2.5 py-2", !embedded && _rebasepro_ui.defaultBorderMixin),
307
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
308
+ className: "bg-surface-200 dark:bg-surface-700 rounded-sm",
309
+ style: {
310
+ height: 14,
311
+ width: 48
312
+ }
313
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
314
+ className: "flex items-baseline gap-1.5",
315
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
316
+ className: "bg-surface-200 dark:bg-surface-700 rounded-sm",
317
+ style: {
318
+ height: 20,
319
+ width: 40
320
+ }
321
+ }), hasComparison && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
322
+ className: "bg-surface-200/60 dark:bg-surface-700/60 rounded-sm",
323
+ style: {
324
+ height: 14,
325
+ width: 28
326
+ }
327
+ })]
328
+ })]
329
+ });
330
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StandardSkeleton, {
331
+ hasComparison,
332
+ hasIcon,
333
+ hasDateRange,
334
+ embedded,
335
+ fixedHeight
336
+ });
337
+ }
338
+ /**
339
+ * Inner component for the standard scorecard skeleton.
340
+ *
341
+ * Mirrors InsightsScorecardView's layout by:
342
+ * 1. Using the same ResizeObserver + containerWidth pattern for
343
+ * responsive breakpoints (isSmall < 200px, isMedium < 300px).
344
+ * 2. Using placeholder heights derived from the exact computed
345
+ * Tailwind line-heights that InsightsScorecardView renders.
346
+ * 3. Matching all container classes, margins, paddings, and flex
347
+ * layout properties identically.
348
+ */
349
+ function StandardSkeleton({ hasComparison, hasIcon, hasDateRange, embedded, fixedHeight }) {
350
+ const containerRef = (0, react.useRef)(null);
351
+ const [containerWidth, setContainerWidth] = (0, react.useState)(null);
352
+ react.default.useLayoutEffect(() => {
353
+ if (!containerRef.current) return;
354
+ setContainerWidth(containerRef.current.offsetWidth);
355
+ const observer = new ResizeObserver((entries) => {
356
+ for (const entry of entries) setContainerWidth(entry.contentRect.width);
357
+ });
358
+ observer.observe(containerRef.current);
359
+ return () => observer.disconnect();
360
+ }, []);
361
+ const isSmall = containerWidth !== null && containerWidth < 200;
362
+ const titleHeight = isSmall ? 15 : 16.5;
363
+ const valueHeight = isSmall ? 22.5 : containerWidth !== null && containerWidth < 300 ? 25 : 30;
364
+ const comparisonHeight = 16;
365
+ const iconSize = isSmall ? 14 : 18;
366
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
367
+ ref: containerRef,
368
+ className: (0, _rebasepro_ui.cls)("animate-pulse", embedded ? `flex flex-col min-w-0 h-full ${isSmall ? "px-3.5 py-3" : "px-5 py-4"}` : (0, _rebasepro_ui.cls)("rounded-lg flex flex-col min-w-0 bg-transparent border", _rebasepro_ui.defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4")),
369
+ style: embedded ? void 0 : fixedHeight ? { height: fixedHeight } : { minHeight: isSmall ? 68 : 92 },
370
+ children: [
371
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
372
+ className: `flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`,
373
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
374
+ className: "flex flex-col min-w-0",
375
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
376
+ className: "bg-surface-200 dark:bg-surface-700 rounded",
377
+ style: {
378
+ height: titleHeight,
379
+ width: "60%"
380
+ }
381
+ }), hasDateRange && !isSmall && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
382
+ className: "bg-surface-200/60 dark:bg-surface-700/60 rounded mt-0.5",
383
+ style: {
384
+ height: 14,
385
+ width: "40%"
386
+ }
387
+ })]
388
+ }), hasIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
389
+ className: "ml-2 shrink-0",
390
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
391
+ className: "bg-surface-200 dark:bg-surface-700 rounded",
392
+ style: {
393
+ height: iconSize,
394
+ width: iconSize
395
+ }
396
+ })
397
+ })]
398
+ }),
399
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
400
+ className: "bg-surface-200 dark:bg-surface-700 rounded",
401
+ style: {
402
+ height: valueHeight,
403
+ width: "40%"
404
+ }
405
+ }),
406
+ hasComparison && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
407
+ className: isSmall ? "mt-0.5" : "mt-1",
408
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
409
+ className: "bg-surface-200/60 dark:bg-surface-700/60 rounded",
410
+ style: {
411
+ height: comparisonHeight,
412
+ width: "25%"
413
+ }
414
+ })
415
+ })
416
+ ]
417
+ });
418
+ }
419
+ InsightWidgetSkeleton.displayName = "InsightWidgetSkeleton";
420
+ //#endregion
421
+ //#region src/components/InsightWidget.tsx
422
+ /**
423
+ * Compute a deterministic fixed height for a standard scorecard based
424
+ * on which optional elements the config declares. This eliminates
425
+ * layout shift between skeleton and loaded states.
426
+ *
427
+ * Breakdown (non-compact, non-small):
428
+ * py-4 padding: 16 + 16 = 32
429
+ * title row: 16.5 (text-xs leading-snug)
430
+ * mb-2 margin: 8
431
+ * value: 30 (text-2xl leading-tight)
432
+ * ---
433
+ * base: 86.5
434
+ * + dateRange: +16 (14px text + 2px mt-0.5)
435
+ * + comparison: +20 (16px text + 4px mt-1)
436
+ */
437
+ function computeFixedHeight(config) {
438
+ let h = 86.5;
439
+ if (config.dateRange) h += 16;
440
+ if (config.comparison) h += 20;
441
+ return Math.ceil(h);
442
+ }
443
+ /**
444
+ * Single insight widget orchestrator.
445
+ *
446
+ * Wraps skeleton and loaded states in a fixed-height container
447
+ * (computed from the scorecard config) to prevent layout shift.
448
+ *
449
+ * All theme-awareness is handled via Tailwind `dark:` classes.
450
+ */
451
+ function InsightWidget({ definition, collectionSlug, path, parentCollectionSlugs, parentEntityIds, compact = false, embedded = false }) {
452
+ const { data, loading, error } = useInsightsData(definition, {
453
+ path,
454
+ collectionSlug,
455
+ parentCollectionSlugs
456
+ });
457
+ const fixedHeight = !compact && !embedded ? computeFixedHeight(definition.scorecard) : void 0;
458
+ if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightWidgetSkeleton, {
459
+ config: definition.scorecard,
460
+ compact,
461
+ embedded,
462
+ fixedHeight
463
+ });
464
+ if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
465
+ className: `text-red-500/70 dark:text-red-400/70 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-red-500/5 dark:bg-red-400/5 border border-red-500/10 dark:border-red-400/10 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`,
466
+ style: fixedHeight ? { height: fixedHeight } : void 0,
467
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
468
+ className: "font-semibold mb-1",
469
+ children: definition.title
470
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error.message })]
471
+ });
472
+ if (!data || data.rows.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
473
+ className: `text-surface-400 dark:text-surface-500 text-[0.8125rem] ${embedded ? "px-5 py-4 h-full" : `rounded-lg bg-surface-100 dark:bg-surface-800 border border-surface-200 dark:border-surface-700 ${compact ? "px-3.5 py-3" : "px-5 py-4"}`}`,
474
+ style: fixedHeight ? { height: fixedHeight } : void 0,
475
+ children: [definition.title, " — No data"]
476
+ });
477
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightsScorecardView, {
478
+ config: definition.scorecard,
479
+ data: data.rows[0],
480
+ title: definition.title,
481
+ compact,
482
+ embedded,
483
+ fixedHeight
484
+ });
485
+ }
486
+ InsightWidget.displayName = "InsightWidget";
487
+ //#endregion
488
+ //#region src/components/HomeCardInsightSlot.tsx
489
+ /**
490
+ * Renders compact insight widgets inline within a home page collection card.
491
+ * Injected via the `home.card.insight` slot.
492
+ *
493
+ * Uses a horizontal flex layout so multiple cards sit side by side.
494
+ */
495
+ function HomeCardInsightSlot({ slug, insights }) {
496
+ if (!insights || insights.length === 0) return null;
497
+ const estimatedRows = Math.ceil(insights.length / 2);
498
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
499
+ className: "flex flex-wrap items-center gap-1.5 mt-2",
500
+ style: { minHeight: estimatedRows * 42 + (estimatedRows - 1) * 6 },
501
+ children: insights.map((def) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightWidget, {
502
+ definition: def,
503
+ collectionSlug: slug,
504
+ compact: true
505
+ }, def.id))
506
+ });
507
+ }
508
+ HomeCardInsightSlot.displayName = "HomeCardInsightSlot";
509
+ //#endregion
510
+ //#region src/components/HomeInsightsSlot.tsx
511
+ /**
512
+ * Scorecard insights panel rendered at the top of the home page.
513
+ * Injected via the `home.children.start` slot.
514
+ *
515
+ * Renders scorecards in a responsive grid (up to 4 columns).
516
+ */
517
+ function HomeInsightsSlot({ insights }) {
518
+ if (!insights || insights.length === 0) return null;
519
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
520
+ className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-6",
521
+ style: { minHeight: 92 },
522
+ children: insights.map((def) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightWidget, { definition: def }, def.id))
523
+ });
524
+ }
525
+ HomeInsightsSlot.displayName = "HomeInsightsSlot";
526
+ //#endregion
527
+ //#region src/components/CollectionInsightsInline.tsx
528
+ /**
529
+ * Renders scorecard insight widgets inline within a collection's list view,
530
+ * positioned below the title and above the main data list.
531
+ *
532
+ * Injected via the `collection.insights` slot.
533
+ */
534
+ function CollectionInsightsInline({ insights, path, parentCollectionSlugs, parentEntityIds }) {
535
+ if (!insights || insights.length === 0) return null;
536
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
537
+ className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-4",
538
+ children: insights.map((def) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsightWidget, {
539
+ definition: def,
540
+ path,
541
+ parentCollectionSlugs,
542
+ parentEntityIds
543
+ }, def.id))
544
+ });
545
+ }
546
+ CollectionInsightsInline.displayName = "CollectionInsightsInline";
547
+ //#endregion
548
+ //#region src/useInsightsPlugin.tsx
549
+ /**
550
+ * Creates the Insights plugin for Rebase.
551
+ *
552
+ * This plugin injects scorecard widgets into key UI locations:
553
+ * - **Home page header**: KPI overview via `home.children.start` slot
554
+ * - **Collection list view**: Scorecards inline (below title, above list) via `collection.insights` slot
555
+ * - **Home page cards**: Compact scorecard metrics auto-extracted from collection insights via `home.card.insight` slot
556
+ *
557
+ * Collection-level insights (`collections.<slug>`) are the single source of truth:
558
+ * scorecards render in the collection list view and are automatically extracted
559
+ * to show as compact widgets on the corresponding home page card.
560
+ *
561
+ * Each insight owns its own `data()` callback — use the Rebase client SDK,
562
+ * call a custom function, or hit any external API. Full flexibility, zero new endpoints.
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * import { useInsightsPlugin } from "@rebasepro/plugin-insights";
567
+ *
568
+ * const insightsPlugin = useInsightsPlugin({
569
+ * cacheTTL: 120_000,
570
+ * insights: {
571
+ * home: [
572
+ * { id: "revenue", title: "Revenue", data: async () => ..., scorecard: { ... } },
573
+ * ],
574
+ * collections: {
575
+ * orders: [
576
+ * { id: "total", title: "Total Orders", data: async () => ..., scorecard: { ... } },
577
+ * ],
578
+ * },
579
+ * },
580
+ * });
581
+ * ```
582
+ */
583
+ function useInsightsPlugin(config) {
584
+ const { insights, cacheTTL } = config;
585
+ return react.default.useMemo(() => {
586
+ const slots = [];
587
+ if (insights.home && insights.home.length > 0) {
588
+ const homeInsights = insights.home;
589
+ slots.push({
590
+ slot: "home.children.start",
591
+ Component: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HomeInsightsSlot, {
592
+ ...props,
593
+ insights: homeInsights
594
+ }),
595
+ order: 10
596
+ });
597
+ }
598
+ if (insights.collections) for (const [slug, defs] of Object.entries(insights.collections)) {
599
+ if (defs.length === 0) continue;
600
+ const collectionInsights = defs;
601
+ slots.push({
602
+ slot: "collection.insights",
603
+ Component: (props) => {
604
+ if ((props.path?.split("/").filter(Boolean).pop() ?? "") !== slug) return null;
605
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CollectionInsightsInline, {
606
+ ...props,
607
+ insights: collectionInsights
608
+ });
609
+ },
610
+ order: 10
611
+ });
612
+ slots.push({
613
+ slot: "home.card.insight",
614
+ Component: (props) => {
615
+ if (props.slug !== slug) return null;
616
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HomeCardInsightSlot, {
617
+ ...props,
618
+ insights: collectionInsights
619
+ });
620
+ },
621
+ order: 10
622
+ });
623
+ }
624
+ return {
625
+ key: "plugin-insights",
626
+ slots,
627
+ providers: [{
628
+ scope: "root",
629
+ Component: InsightsProvider,
630
+ props: { cacheTTL }
631
+ }]
632
+ };
633
+ }, [insights, cacheTTL]);
634
+ }
635
+ //#endregion
636
+ exports.InsightWidget = InsightWidget;
637
+ exports.InsightWidgetSkeleton = InsightWidgetSkeleton;
638
+ exports.InsightsCache = InsightsCache;
639
+ exports.InsightsProvider = InsightsProvider;
640
+ exports.InsightsScorecardView = InsightsScorecardView;
641
+ exports.useInsightsData = useInsightsData;
642
+ exports.useInsightsEngine = useInsightsEngine;
643
+ exports.useInsightsPlugin = useInsightsPlugin;
644
+ });
645
+
646
+ //# sourceMappingURL=index.umd.js.map