@rebasepro/plugin-insights 0.0.1-canary.4f204c2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +6 -0
- package/dist/common/src/collections/CollectionRegistry.d.ts +56 -0
- package/dist/common/src/collections/index.d.ts +1 -0
- package/dist/common/src/data/buildRebaseData.d.ts +14 -0
- package/dist/common/src/index.d.ts +3 -0
- package/dist/common/src/util/builders.d.ts +57 -0
- package/dist/common/src/util/callbacks.d.ts +6 -0
- package/dist/common/src/util/collections.d.ts +11 -0
- package/dist/common/src/util/common.d.ts +2 -0
- package/dist/common/src/util/conditions.d.ts +26 -0
- package/dist/common/src/util/entities.d.ts +58 -0
- package/dist/common/src/util/enums.d.ts +3 -0
- package/dist/common/src/util/index.d.ts +16 -0
- package/dist/common/src/util/navigation_from_path.d.ts +34 -0
- package/dist/common/src/util/navigation_utils.d.ts +20 -0
- package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
- package/dist/common/src/util/paths.d.ts +14 -0
- package/dist/common/src/util/permissions.d.ts +5 -0
- package/dist/common/src/util/references.d.ts +2 -0
- package/dist/common/src/util/relations.d.ts +22 -0
- package/dist/common/src/util/resolutions.d.ts +72 -0
- package/dist/common/src/util/storage.d.ts +24 -0
- package/dist/core/src/components/AIIcon.d.ts +16 -0
- package/dist/core/src/components/ConfirmationDialog.d.ts +9 -0
- package/dist/core/src/components/Debug/UIReferenceView.d.ts +1 -0
- package/dist/core/src/components/Debug/UIStyleGuide.d.ts +1 -0
- package/dist/core/src/components/ErrorTooltip.d.ts +2 -0
- package/dist/core/src/components/ErrorView.d.ts +21 -0
- package/dist/core/src/components/LanguageToggle.d.ts +1 -0
- package/dist/core/src/components/LoginView/LoginView.d.ts +68 -0
- package/dist/core/src/components/LoginView/index.d.ts +2 -0
- package/dist/core/src/components/NotFoundPage.d.ts +1 -0
- package/dist/core/src/components/RebaseAuth.d.ts +10 -0
- package/dist/core/src/components/RebaseLogo.d.ts +7 -0
- package/dist/core/src/components/UnsavedChangesDialog.d.ts +9 -0
- package/dist/core/src/components/UserDisplay.d.ts +7 -0
- package/dist/core/src/components/UserSelectPopover.d.ts +62 -0
- package/dist/core/src/components/UserSettingsView.d.ts +1 -0
- package/dist/core/src/components/common/index.d.ts +6 -0
- package/dist/core/src/components/common/table_height.d.ts +5 -0
- package/dist/core/src/components/common/types.d.ts +63 -0
- package/dist/core/src/components/common/useColumnsIds.d.ts +9 -0
- package/dist/core/src/components/common/useDataTableController.d.ts +45 -0
- package/dist/core/src/components/common/useDebouncedData.d.ts +9 -0
- package/dist/core/src/components/common/useScrollRestoration.d.ts +14 -0
- package/dist/core/src/components/index.d.ts +16 -0
- package/dist/core/src/contexts/AdminModeController.d.ts +4 -0
- package/dist/core/src/contexts/AnalyticsContext.d.ts +3 -0
- package/dist/core/src/contexts/AuthControllerContext.d.ts +3 -0
- package/dist/core/src/contexts/CustomizationControllerContext.d.ts +3 -0
- package/dist/core/src/contexts/DataDriverContext.d.ts +3 -0
- package/dist/core/src/contexts/DatabaseAdminContext.d.ts +3 -0
- package/dist/core/src/contexts/DialogsProvider.d.ts +4 -0
- package/dist/core/src/contexts/EffectiveRoleController.d.ts +4 -0
- package/dist/core/src/contexts/InternalUserManagementContext.d.ts +3 -0
- package/dist/core/src/contexts/ModeController.d.ts +4 -0
- package/dist/core/src/contexts/RebaseClientInstanceContext.d.ts +6 -0
- package/dist/core/src/contexts/RebaseDataContext.d.ts +3 -0
- package/dist/core/src/contexts/SnackbarProvider.d.ts +2 -0
- package/dist/core/src/contexts/StorageSourceContext.d.ts +3 -0
- package/dist/core/src/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
- package/dist/core/src/contexts/index.d.ts +13 -0
- package/dist/core/src/core/PluginLifecycleManager.d.ts +17 -0
- package/dist/core/src/core/PluginProviderStack.d.ts +21 -0
- package/dist/core/src/core/Rebase.d.ts +14 -0
- package/dist/core/src/core/RebaseProps.d.ts +136 -0
- package/dist/core/src/core/RebaseRouter.d.ts +4 -0
- package/dist/core/src/core/RebaseRoutes.d.ts +17 -0
- package/dist/core/src/core/index.d.ts +4 -0
- package/dist/core/src/hooks/ApiConfigContext.d.ts +24 -0
- package/dist/core/src/hooks/data/delete.d.ts +31 -0
- package/dist/core/src/hooks/data/save.d.ts +34 -0
- package/dist/core/src/hooks/data/useCollectionFetch.d.ts +51 -0
- package/dist/core/src/hooks/data/useData.d.ts +13 -0
- package/dist/core/src/hooks/data/useDataOrder.d.ts +12 -0
- package/dist/core/src/hooks/data/useEntityFetch.d.ts +38 -0
- package/dist/core/src/hooks/data/useRelationSelector.d.ts +52 -0
- package/dist/core/src/hooks/data/useUserSelector.d.ts +31 -0
- package/dist/core/src/hooks/index.d.ts +37 -0
- package/dist/core/src/hooks/useAdminModeController.d.ts +19 -0
- package/dist/core/src/hooks/useAnalyticsController.d.ts +5 -0
- package/dist/core/src/hooks/useAuthController.d.ts +11 -0
- package/dist/core/src/hooks/useAuthSubscription.d.ts +2 -0
- package/dist/core/src/hooks/useBackendStorageSource.d.ts +30 -0
- package/dist/core/src/hooks/useBridgeRegistration.d.ts +18 -0
- package/dist/core/src/hooks/useBrowserTitleAndIcon.d.ts +6 -0
- package/dist/core/src/hooks/useBuildAdminModeController.d.ts +6 -0
- package/dist/core/src/hooks/useBuildEffectiveRoleController.d.ts +8 -0
- package/dist/core/src/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
- package/dist/core/src/hooks/useBuildModeController.d.ts +6 -0
- package/dist/core/src/hooks/useClipboard.d.ts +57 -0
- package/dist/core/src/hooks/useCollapsedGroups.d.ts +12 -0
- package/dist/core/src/hooks/useCustomizationController.d.ts +11 -0
- package/dist/core/src/hooks/useDialogsController.d.ts +11 -0
- package/dist/core/src/hooks/useEffectiveRoleController.d.ts +7 -0
- package/dist/core/src/hooks/useInternalUserManagementController.d.ts +12 -0
- package/dist/core/src/hooks/useLargeLayout.d.ts +1 -0
- package/dist/core/src/hooks/useModeController.d.ts +19 -0
- package/dist/core/src/hooks/usePermissions.d.ts +12 -0
- package/dist/core/src/hooks/useRebaseClient.d.ts +5 -0
- package/dist/core/src/hooks/useRebaseContext.d.ts +11 -0
- package/dist/core/src/hooks/useRebaseRegistry.d.ts +34 -0
- package/dist/core/src/hooks/useSlot.d.ts +18 -0
- package/dist/core/src/hooks/useSnackbarController.d.ts +20 -0
- package/dist/core/src/hooks/useStorageSource.d.ts +7 -0
- package/dist/core/src/hooks/useStudioBridge.d.ts +91 -0
- package/dist/core/src/hooks/useTranslation.d.ts +17 -0
- package/dist/core/src/hooks/useUnsavedChangesDialog.d.ts +12 -0
- package/dist/core/src/hooks/useUserConfigurationPersistence.d.ts +8 -0
- package/dist/core/src/hooks/useValidateAuthenticator.d.ts +21 -0
- package/dist/core/src/i18n/RebaseI18nProvider.d.ts +33 -0
- package/dist/core/src/index.d.ts +15 -0
- package/dist/core/src/internal/common.d.ts +3 -0
- package/dist/core/src/internal/useRestoreScroll.d.ts +6 -0
- package/dist/core/src/locales/de.d.ts +2 -0
- package/dist/core/src/locales/en.d.ts +10 -0
- package/dist/core/src/locales/es.d.ts +10 -0
- package/dist/core/src/locales/fr.d.ts +2 -0
- package/dist/core/src/locales/hi.d.ts +2 -0
- package/dist/core/src/locales/it.d.ts +2 -0
- package/dist/core/src/locales/pt.d.ts +7 -0
- package/dist/core/src/util/constants.d.ts +1 -0
- package/dist/core/src/util/createFormexStub.d.ts +2 -0
- package/dist/core/src/util/entity_cache.d.ts +27 -0
- package/dist/core/src/util/enums.d.ts +5 -0
- package/dist/core/src/util/icon_list.d.ts +5 -0
- package/dist/core/src/util/icon_synonyms.d.ts +1 -0
- package/dist/core/src/util/icons.d.ts +20 -0
- package/dist/core/src/util/index.d.ts +10 -0
- package/dist/core/src/util/previews.d.ts +4 -0
- package/dist/core/src/util/useStorageUploadController.d.ts +38 -0
- package/dist/core/src/util/useTraceUpdate.d.ts +2 -0
- package/dist/formex/src/Field.d.ts +52 -0
- package/dist/formex/src/Formex.d.ts +7 -0
- package/dist/formex/src/index.d.ts +5 -0
- package/dist/formex/src/types.d.ts +40 -0
- package/dist/formex/src/useCreateFormex.d.ts +14 -0
- package/dist/formex/src/utils.d.ts +16 -0
- package/dist/index.es.js +945 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +944 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/plugin-insights/src/components/CollectionInsightsInline.d.ts +16 -0
- package/dist/plugin-insights/src/components/HomeCardInsightSlot.d.ts +16 -0
- package/dist/plugin-insights/src/components/HomeInsightsSlot.d.ts +13 -0
- package/dist/plugin-insights/src/components/InsightWidget.d.ts +19 -0
- package/dist/plugin-insights/src/components/InsightWidgetSkeleton.d.ts +20 -0
- package/dist/plugin-insights/src/components/InsightsScorecardView.d.ts +19 -0
- package/dist/plugin-insights/src/engine/InsightsCache.d.ts +18 -0
- package/dist/plugin-insights/src/engine/InsightsProvider.d.ts +22 -0
- package/dist/plugin-insights/src/engine/useInsightsData.d.ts +17 -0
- package/dist/plugin-insights/src/index.d.ts +8 -0
- package/dist/plugin-insights/src/types/engine.d.ts +79 -0
- package/dist/plugin-insights/src/types/index.d.ts +2 -0
- package/dist/plugin-insights/src/types/widgets.d.ts +59 -0
- package/dist/plugin-insights/src/useInsightsPlugin.d.ts +37 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
- package/dist/types/src/controllers/auth.d.ts +119 -0
- package/dist/types/src/controllers/client.d.ts +170 -0
- package/dist/types/src/controllers/collection_registry.d.ts +45 -0
- package/dist/types/src/controllers/customization_controller.d.ts +60 -0
- package/dist/types/src/controllers/data.d.ts +168 -0
- package/dist/types/src/controllers/data_driver.d.ts +160 -0
- package/dist/types/src/controllers/database_admin.d.ts +11 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
- package/dist/types/src/controllers/effective_role.d.ts +4 -0
- package/dist/types/src/controllers/email.d.ts +34 -0
- package/dist/types/src/controllers/index.d.ts +18 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
- package/dist/types/src/controllers/navigation.d.ts +213 -0
- package/dist/types/src/controllers/registry.d.ts +54 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +90 -0
- package/dist/types/src/controllers/snackbar.d.ts +24 -0
- package/dist/types/src/controllers/storage.d.ts +171 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/rebase_context.d.ts +105 -0
- package/dist/types/src/types/backend.d.ts +536 -0
- package/dist/types/src/types/builders.d.ts +15 -0
- package/dist/types/src/types/chips.d.ts +5 -0
- package/dist/types/src/types/collections.d.ts +856 -0
- package/dist/types/src/types/cron.d.ts +102 -0
- package/dist/types/src/types/data_source.d.ts +64 -0
- package/dist/types/src/types/entities.d.ts +145 -0
- package/dist/types/src/types/entity_actions.d.ts +98 -0
- package/dist/types/src/types/entity_callbacks.d.ts +173 -0
- package/dist/types/src/types/entity_link_builder.d.ts +7 -0
- package/dist/types/src/types/entity_overrides.d.ts +10 -0
- package/dist/types/src/types/entity_views.d.ts +61 -0
- package/dist/types/src/types/export_import.d.ts +21 -0
- package/dist/types/src/types/index.d.ts +23 -0
- package/dist/types/src/types/locales.d.ts +4 -0
- package/dist/types/src/types/modify_collections.d.ts +5 -0
- package/dist/types/src/types/plugins.d.ts +279 -0
- package/dist/types/src/types/properties.d.ts +1176 -0
- package/dist/types/src/types/property_config.d.ts +70 -0
- package/dist/types/src/types/relations.d.ts +336 -0
- package/dist/types/src/types/slots.d.ts +252 -0
- package/dist/types/src/types/translations.d.ts +870 -0
- package/dist/types/src/types/user_management_delegate.d.ts +121 -0
- package/dist/types/src/types/websockets.d.ts +78 -0
- package/dist/types/src/users/index.d.ts +2 -0
- package/dist/types/src/users/roles.d.ts +22 -0
- package/dist/types/src/users/user.d.ts +46 -0
- package/dist/ui/src/components/Alert.d.ts +12 -0
- package/dist/ui/src/components/Autocomplete.d.ts +21 -0
- package/dist/ui/src/components/Avatar.d.ts +11 -0
- package/dist/ui/src/components/Badge.d.ts +8 -0
- package/dist/ui/src/components/BooleanSwitch.d.ts +14 -0
- package/dist/ui/src/components/BooleanSwitchWithLabel.d.ts +17 -0
- package/dist/ui/src/components/Button.d.ts +14 -0
- package/dist/ui/src/components/Card.d.ts +9 -0
- package/dist/ui/src/components/CenteredView.d.ts +9 -0
- package/dist/ui/src/components/Checkbox.d.ts +13 -0
- package/dist/ui/src/components/Chip.d.ts +26 -0
- package/dist/ui/src/components/CircularProgress.d.ts +5 -0
- package/dist/ui/src/components/CircularProgressCenter.d.ts +11 -0
- package/dist/ui/src/components/Collapse.d.ts +9 -0
- package/dist/ui/src/components/ColorPicker.d.ts +30 -0
- package/dist/ui/src/components/Container.d.ts +8 -0
- package/dist/ui/src/components/DateTimeField.d.ts +24 -0
- package/dist/ui/src/components/DebouncedTextField.d.ts +2 -0
- package/dist/ui/src/components/Dialog.d.ts +39 -0
- package/dist/ui/src/components/DialogActions.d.ts +7 -0
- package/dist/ui/src/components/DialogContent.d.ts +7 -0
- package/dist/ui/src/components/DialogTitle.d.ts +10 -0
- package/dist/ui/src/components/ErrorBoundary.d.ts +11 -0
- package/dist/ui/src/components/ExpandablePanel.d.ts +12 -0
- package/dist/ui/src/components/FileUpload.d.ts +23 -0
- package/dist/ui/src/components/IconButton.d.ts +12 -0
- package/dist/ui/src/components/InfoLabel.d.ts +5 -0
- package/dist/ui/src/components/InputLabel.d.ts +11 -0
- package/dist/ui/src/components/Label.d.ts +7 -0
- package/dist/ui/src/components/LoadingButton.d.ts +7 -0
- package/dist/ui/src/components/Markdown.d.ts +10 -0
- package/dist/ui/src/components/Menu.d.ts +23 -0
- package/dist/ui/src/components/Menubar.d.ts +80 -0
- package/dist/ui/src/components/MultiSelect.d.ts +48 -0
- package/dist/ui/src/components/Paper.d.ts +6 -0
- package/dist/ui/src/components/Popover.d.ts +24 -0
- package/dist/ui/src/components/RadioGroup.d.ts +28 -0
- package/dist/ui/src/components/ResizablePanels.d.ts +18 -0
- package/dist/ui/src/components/SearchBar.d.ts +22 -0
- package/dist/ui/src/components/Select.d.ts +43 -0
- package/dist/ui/src/components/Separator.d.ts +5 -0
- package/dist/ui/src/components/Sheet.d.ts +22 -0
- package/dist/ui/src/components/Skeleton.d.ts +6 -0
- package/dist/ui/src/components/Slider.d.ts +21 -0
- package/dist/ui/src/components/Table.d.ts +34 -0
- package/dist/ui/src/components/Tabs.d.ts +19 -0
- package/dist/ui/src/components/TextField.d.ts +58 -0
- package/dist/ui/src/components/TextareaAutosize.d.ts +43 -0
- package/dist/ui/src/components/ToggleButtonGroup.d.ts +30 -0
- package/dist/ui/src/components/Tooltip.d.ts +19 -0
- package/dist/ui/src/components/Typography.d.ts +36 -0
- package/dist/ui/src/components/VirtualTable/VirtualTable.d.ts +11 -0
- package/dist/ui/src/components/VirtualTable/VirtualTableCell.d.ts +21 -0
- package/dist/ui/src/components/VirtualTable/VirtualTableHeader.d.ts +29 -0
- package/dist/ui/src/components/VirtualTable/VirtualTableHeaderRow.d.ts +2 -0
- package/dist/ui/src/components/VirtualTable/VirtualTableProps.d.ts +243 -0
- package/dist/ui/src/components/VirtualTable/VirtualTableRow.d.ts +3 -0
- package/dist/ui/src/components/VirtualTable/index.d.ts +3 -0
- package/dist/ui/src/components/VirtualTable/types.d.ts +38 -0
- package/dist/ui/src/components/common/SelectInputLabel.d.ts +5 -0
- package/dist/ui/src/components/index.d.ts +53 -0
- package/dist/ui/src/hooks/PortalContainerContext.d.ts +31 -0
- package/dist/ui/src/hooks/index.d.ts +6 -0
- package/dist/ui/src/hooks/useDebounceCallback.d.ts +1 -0
- package/dist/ui/src/hooks/useDebounceValue.d.ts +1 -0
- package/dist/ui/src/hooks/useDebouncedCallback.d.ts +1 -0
- package/dist/ui/src/hooks/useInjectStyles.d.ts +7 -0
- package/dist/ui/src/hooks/useOutsideAlerter.d.ts +5 -0
- package/dist/ui/src/icons/GitHubIcon.d.ts +2 -0
- package/dist/ui/src/icons/HandleIcon.d.ts +1 -0
- package/dist/ui/src/icons/Icon.d.ts +20 -0
- package/dist/ui/src/icons/cool_icon_keys.d.ts +1 -0
- package/dist/ui/src/icons/icon_keys.d.ts +1 -0
- package/dist/ui/src/icons/index.d.ts +6 -0
- package/dist/ui/src/index.d.ts +5 -0
- package/dist/ui/src/styles.d.ts +12 -0
- package/dist/ui/src/util/chip_colors.d.ts +4 -0
- package/dist/ui/src/util/cls.d.ts +2 -0
- package/dist/ui/src/util/debounce.d.ts +10 -0
- package/dist/ui/src/util/hash.d.ts +1 -0
- package/dist/ui/src/util/index.d.ts +4 -0
- package/dist/ui/src/util/key_to_icon_component.d.ts +1 -0
- package/package.json +80 -0
- package/src/components/CollectionInsightsInline.tsx +30 -0
- package/src/components/HomeCardInsightSlot.tsx +36 -0
- package/src/components/HomeInsightsSlot.tsx +30 -0
- package/src/components/InsightWidget.tsx +65 -0
- package/src/components/InsightWidgetSkeleton.tsx +122 -0
- package/src/components/InsightsScorecardView.tsx +160 -0
- package/src/engine/InsightsCache.ts +52 -0
- package/src/engine/InsightsProvider.tsx +38 -0
- package/src/engine/useInsightsData.ts +100 -0
- package/src/index.ts +22 -0
- package/src/types/engine.ts +85 -0
- package/src/types/index.ts +5 -0
- package/src/types/widgets.ts +66 -0
- package/src/useInsightsPlugin.tsx +117 -0
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rebasepro/plugin-insights",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1-canary.4f204c2",
|
|
5
|
+
"main": "./dist/index.umd.js",
|
|
6
|
+
"module": "./dist/index.es.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"source": "src/index.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"development": "./src/index.ts",
|
|
13
|
+
"import": "./dist/index.es.js",
|
|
14
|
+
"require": "./dist/index.umd.js"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"lucide-react": "1.14.0",
|
|
20
|
+
"react-compiler-runtime": "1.0.0",
|
|
21
|
+
"@rebasepro/core": "0.0.1-canary.4f204c2",
|
|
22
|
+
"@rebasepro/types": "0.0.1-canary.4f204c2"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"react": ">=19.0.0",
|
|
26
|
+
"react-dom": ">=19.0.0"
|
|
27
|
+
},
|
|
28
|
+
"browserslist": {
|
|
29
|
+
"production": [
|
|
30
|
+
">0.2%",
|
|
31
|
+
"not dead",
|
|
32
|
+
"not op_mini all"
|
|
33
|
+
],
|
|
34
|
+
"development": [
|
|
35
|
+
"last 1 chrome version",
|
|
36
|
+
"last 1 firefox version",
|
|
37
|
+
"last 1 safari version"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
42
|
+
"@types/jest": "^29.5.14",
|
|
43
|
+
"@types/react": "^19.0.8",
|
|
44
|
+
"@types/react-dom": "^19.0.3",
|
|
45
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
46
|
+
"babel-jest": "^29.7.0",
|
|
47
|
+
"babel-plugin-react-compiler": "^19.0.0-beta-af1b7da-20250417",
|
|
48
|
+
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
|
49
|
+
"jest": "^29.7.0",
|
|
50
|
+
"ts-jest": "^29.4.5",
|
|
51
|
+
"typescript": "^5.9.3",
|
|
52
|
+
"vite": "^7.2.4"
|
|
53
|
+
},
|
|
54
|
+
"jest": {
|
|
55
|
+
"transform": {
|
|
56
|
+
"^.+\\.tsx?$": "ts-jest"
|
|
57
|
+
},
|
|
58
|
+
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
|
|
59
|
+
"moduleFileExtensions": [
|
|
60
|
+
"ts",
|
|
61
|
+
"tsx",
|
|
62
|
+
"js",
|
|
63
|
+
"jsx",
|
|
64
|
+
"json",
|
|
65
|
+
"node"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist",
|
|
70
|
+
"src"
|
|
71
|
+
],
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"dev": "vite",
|
|
77
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
78
|
+
"test": "jest --passWithNoTests"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { InsightDefinition } from "../types";
|
|
3
|
+
import { InsightWidget } from "./InsightWidget";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders scorecard insight widgets inline within a collection's list view,
|
|
7
|
+
* positioned below the title and above the main data list.
|
|
8
|
+
*
|
|
9
|
+
* Injected via the `collection.insights` slot.
|
|
10
|
+
*/
|
|
11
|
+
export function CollectionInsightsInline({
|
|
12
|
+
insights,
|
|
13
|
+
}: {
|
|
14
|
+
path: string;
|
|
15
|
+
collection: unknown;
|
|
16
|
+
parentCollectionIds: string[];
|
|
17
|
+
insights: InsightDefinition[];
|
|
18
|
+
}) {
|
|
19
|
+
if (!insights || insights.length === 0) return null;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-4">
|
|
23
|
+
{insights.map((def) => (
|
|
24
|
+
<InsightWidget key={def.id} definition={def} />
|
|
25
|
+
))}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
CollectionInsightsInline.displayName = "CollectionInsightsInline";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { InsightDefinition } from "../types";
|
|
3
|
+
import { InsightWidget } from "./InsightWidget";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Renders compact insight widgets inline within a home page collection card.
|
|
7
|
+
* Injected via the `home.card.insight` slot.
|
|
8
|
+
*
|
|
9
|
+
* Uses a horizontal flex layout so multiple cards sit side by side.
|
|
10
|
+
*/
|
|
11
|
+
export function HomeCardInsightSlot({
|
|
12
|
+
slug,
|
|
13
|
+
insights,
|
|
14
|
+
}: {
|
|
15
|
+
slug: string;
|
|
16
|
+
collection: unknown;
|
|
17
|
+
context: unknown;
|
|
18
|
+
insights: InsightDefinition[];
|
|
19
|
+
}) {
|
|
20
|
+
if (!insights || insights.length === 0) return null;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="flex flex-wrap items-center gap-1.5 mt-2" style={{ minHeight: 46 }}>
|
|
24
|
+
{insights.map((def) => (
|
|
25
|
+
<InsightWidget
|
|
26
|
+
key={def.id}
|
|
27
|
+
definition={def}
|
|
28
|
+
collectionSlug={slug}
|
|
29
|
+
compact={true}
|
|
30
|
+
/>
|
|
31
|
+
))}
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
HomeCardInsightSlot.displayName = "HomeCardInsightSlot";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { InsightDefinition } from "../types";
|
|
3
|
+
import { InsightWidget } from "./InsightWidget";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Scorecard insights panel rendered at the top of the home page.
|
|
7
|
+
* Injected via the `home.children.start` slot.
|
|
8
|
+
*
|
|
9
|
+
* Renders scorecards in a responsive grid (up to 4 columns).
|
|
10
|
+
*/
|
|
11
|
+
export function HomeInsightsSlot({
|
|
12
|
+
insights,
|
|
13
|
+
}: {
|
|
14
|
+
insights: InsightDefinition[];
|
|
15
|
+
}) {
|
|
16
|
+
if (!insights || insights.length === 0) return null;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div
|
|
20
|
+
className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-3 pb-6"
|
|
21
|
+
style={{ minHeight: 92 }}
|
|
22
|
+
>
|
|
23
|
+
{insights.map((def) => (
|
|
24
|
+
<InsightWidget key={def.id} definition={def} />
|
|
25
|
+
))}
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
HomeInsightsSlot.displayName = "HomeInsightsSlot";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { InsightDefinition, DataRow } from "../types";
|
|
3
|
+
import { useInsightsData } from "../engine/useInsightsData";
|
|
4
|
+
import { InsightsScorecardView } from "./InsightsScorecardView";
|
|
5
|
+
import { InsightWidgetSkeleton } from "./InsightWidgetSkeleton";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Single insight widget orchestrator.
|
|
9
|
+
*
|
|
10
|
+
* Fetches data via the engine, renders the scorecard visualization,
|
|
11
|
+
* and manages loading/error states.
|
|
12
|
+
*
|
|
13
|
+
* All theme-awareness is handled via Tailwind `dark:` classes.
|
|
14
|
+
*/
|
|
15
|
+
export function InsightWidget({
|
|
16
|
+
definition,
|
|
17
|
+
collectionSlug,
|
|
18
|
+
compact = false,
|
|
19
|
+
embedded = false,
|
|
20
|
+
}: {
|
|
21
|
+
definition: InsightDefinition;
|
|
22
|
+
collectionSlug?: string;
|
|
23
|
+
compact?: boolean;
|
|
24
|
+
/** When true, inner views skip their own borders since the parent card provides them. */
|
|
25
|
+
embedded?: boolean;
|
|
26
|
+
}) {
|
|
27
|
+
const { data, loading, error } = useInsightsData(definition, collectionSlug);
|
|
28
|
+
|
|
29
|
+
if (loading) {
|
|
30
|
+
return <InsightWidgetSkeleton config={definition.scorecard} compact={compact} embedded={embedded} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (error) {
|
|
34
|
+
return (
|
|
35
|
+
<div
|
|
36
|
+
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"}`}`}
|
|
37
|
+
>
|
|
38
|
+
<div className="font-semibold mb-1">{definition.title}</div>
|
|
39
|
+
<div>{error.message}</div>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!data || data.rows.length === 0) {
|
|
45
|
+
return (
|
|
46
|
+
<div
|
|
47
|
+
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"}`}`}
|
|
48
|
+
>
|
|
49
|
+
{definition.title} — No data
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<InsightsScorecardView
|
|
56
|
+
config={definition.scorecard}
|
|
57
|
+
data={data.rows[0] as DataRow}
|
|
58
|
+
title={definition.title}
|
|
59
|
+
compact={compact}
|
|
60
|
+
embedded={embedded}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
InsightWidget.displayName = "InsightWidget";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cls, defaultBorderMixin } from "@rebasepro/ui";
|
|
3
|
+
import type { ScorecardConfig } from "../types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Skeleton loader for scorecard insight widgets — displays animated
|
|
7
|
+
* shimmer placeholders that exactly match the final rendered layout
|
|
8
|
+
* of InsightsScorecardView for a given config, preventing layout shift.
|
|
9
|
+
*
|
|
10
|
+
* The skeleton receives the scorecard config so it can conditionally
|
|
11
|
+
* render placeholder lines for comparison, dateRange, and icon —
|
|
12
|
+
* only when the loaded view will also render them.
|
|
13
|
+
*/
|
|
14
|
+
export function InsightWidgetSkeleton({
|
|
15
|
+
config,
|
|
16
|
+
compact = false,
|
|
17
|
+
embedded = false,
|
|
18
|
+
}: {
|
|
19
|
+
/** Scorecard config — used to match optional elements (comparison, dateRange, icon). */
|
|
20
|
+
config: ScorecardConfig;
|
|
21
|
+
compact?: boolean;
|
|
22
|
+
/** When true, skip own border since the parent card provides it. */
|
|
23
|
+
embedded?: boolean;
|
|
24
|
+
}) {
|
|
25
|
+
const hasComparison = Boolean(config.comparison);
|
|
26
|
+
const hasIcon = Boolean(config.icon);
|
|
27
|
+
const hasDateRange = Boolean(config.dateRange);
|
|
28
|
+
|
|
29
|
+
// ── Compact scorecard skeleton ──────────────────────────────────────
|
|
30
|
+
// Matches InsightsScorecardView compact layout:
|
|
31
|
+
// container: flex flex-col gap-0.5 px-2.5 py-2 rounded-md border
|
|
32
|
+
// title: text-[10px] uppercase → line-height ~14px
|
|
33
|
+
// value row: text-sm font-semibold → line-height ~20px
|
|
34
|
+
// + optional comparison text-[10px] inside value row
|
|
35
|
+
if (compact) {
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
className={cls(
|
|
39
|
+
"animate-pulse",
|
|
40
|
+
embedded
|
|
41
|
+
? "h-full px-2.5 py-2"
|
|
42
|
+
: "flex flex-col gap-0.5 rounded-md bg-transparent border min-w-0 px-2.5 py-2",
|
|
43
|
+
!embedded && defaultBorderMixin
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
{/* Title line */}
|
|
47
|
+
<div className="bg-surface-200 dark:bg-surface-700 rounded-sm"
|
|
48
|
+
style={{ height: 14, width: 48 }}
|
|
49
|
+
/>
|
|
50
|
+
{/* Value + optional comparison row */}
|
|
51
|
+
<div className="flex items-baseline gap-1.5">
|
|
52
|
+
<div className="bg-surface-200 dark:bg-surface-700 rounded-sm"
|
|
53
|
+
style={{ height: 20, width: 40 }}
|
|
54
|
+
/>
|
|
55
|
+
{hasComparison && (
|
|
56
|
+
<div className="bg-surface-200/60 dark:bg-surface-700/60 rounded-sm"
|
|
57
|
+
style={{ height: 14, width: 28 }}
|
|
58
|
+
/>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── Standard scorecard skeleton ─────────────────────────────────────
|
|
66
|
+
// Matches InsightsScorecardView standard layout (isSmall = false):
|
|
67
|
+
// container: rounded-lg px-5 py-4 border, minHeight 92
|
|
68
|
+
// title row: flex justify-between mb-2
|
|
69
|
+
// title: text-xs → line-height ~16px
|
|
70
|
+
// dateRange: text-[10px] mt-0.5 → ~14px (optional)
|
|
71
|
+
// icon: 18×18 ml-2 (optional)
|
|
72
|
+
// value: text-2xl → line-height ~32px
|
|
73
|
+
// comparison: text-xs mt-1 → ~16px (optional)
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
className={cls(
|
|
77
|
+
"animate-pulse",
|
|
78
|
+
embedded
|
|
79
|
+
? "h-full px-5 py-4"
|
|
80
|
+
: "rounded-lg bg-transparent border px-5 py-4",
|
|
81
|
+
!embedded && defaultBorderMixin
|
|
82
|
+
)}
|
|
83
|
+
style={embedded ? undefined : { minHeight: 92 }}
|
|
84
|
+
>
|
|
85
|
+
{/* Title row */}
|
|
86
|
+
<div className="flex items-center justify-between mb-2">
|
|
87
|
+
<div className="flex flex-col min-w-0">
|
|
88
|
+
{/* Title */}
|
|
89
|
+
<div className="bg-surface-200 dark:bg-surface-700 rounded"
|
|
90
|
+
style={{ height: 16, width: "60%" }}
|
|
91
|
+
/>
|
|
92
|
+
{/* DateRange (only if config has it) */}
|
|
93
|
+
{hasDateRange && (
|
|
94
|
+
<div className="bg-surface-200/60 dark:bg-surface-700/60 rounded mt-0.5"
|
|
95
|
+
style={{ height: 14, width: "40%" }}
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
{/* Icon placeholder (only if config has it) */}
|
|
100
|
+
{hasIcon && (
|
|
101
|
+
<div className="bg-surface-200 dark:bg-surface-700 rounded ml-2 shrink-0"
|
|
102
|
+
style={{ height: 18, width: 18 }}
|
|
103
|
+
/>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{/* Main value */}
|
|
108
|
+
<div className="bg-surface-200 dark:bg-surface-700 rounded"
|
|
109
|
+
style={{ height: 32, width: "40%" }}
|
|
110
|
+
/>
|
|
111
|
+
|
|
112
|
+
{/* Comparison (only if config has it) */}
|
|
113
|
+
{hasComparison && (
|
|
114
|
+
<div className="bg-surface-200/60 dark:bg-surface-700/60 rounded mt-1"
|
|
115
|
+
style={{ height: 16, width: "25%" }}
|
|
116
|
+
/>
|
|
117
|
+
)}
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
InsightWidgetSkeleton.displayName = "InsightWidgetSkeleton";
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React, { useRef, useState } from "react";
|
|
2
|
+
import { getIcon } from "@rebasepro/core";
|
|
3
|
+
import { cls, defaultBorderMixin } from "@rebasepro/ui";
|
|
4
|
+
import type { DataRow, ScorecardConfig, ScorecardFormat } from "../types";
|
|
5
|
+
|
|
6
|
+
function formatNumber(value: number, format?: ScorecardFormat): string {
|
|
7
|
+
if (value === null || value === undefined) return "N/A";
|
|
8
|
+
|
|
9
|
+
const options: Intl.NumberFormatOptions = {
|
|
10
|
+
style: format?.style ?? "decimal",
|
|
11
|
+
notation: format?.notation ?? "standard",
|
|
12
|
+
maximumFractionDigits: format?.decimals ?? 1,
|
|
13
|
+
minimumFractionDigits: format?.decimals ?? 1,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
if (format?.style === "currency") {
|
|
17
|
+
options.currency = format.currency ?? "USD";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let formatted = new Intl.NumberFormat("en-US", options).format(value);
|
|
21
|
+
|
|
22
|
+
if (format?.showSign && value > 0) {
|
|
23
|
+
formatted = "+" + formatted;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return formatted;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Scorecard widget for the Rebase design system.
|
|
31
|
+
*
|
|
32
|
+
* Renders a single KPI metric with optional comparison value and icon.
|
|
33
|
+
* Uses Tailwind `dark:` classes — no JS dark mode detection.
|
|
34
|
+
* Icons are resolved via `getIcon` from `@rebasepro/core`.
|
|
35
|
+
*/
|
|
36
|
+
export function InsightsScorecardView({
|
|
37
|
+
config,
|
|
38
|
+
data,
|
|
39
|
+
title,
|
|
40
|
+
compact = false,
|
|
41
|
+
embedded = false,
|
|
42
|
+
}: {
|
|
43
|
+
config: ScorecardConfig;
|
|
44
|
+
data: DataRow;
|
|
45
|
+
title: string;
|
|
46
|
+
compact?: boolean;
|
|
47
|
+
/** When true, skip own border/bg since the parent card provides them. */
|
|
48
|
+
embedded?: boolean;
|
|
49
|
+
}) {
|
|
50
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
51
|
+
const [containerWidth, setContainerWidth] = useState<number | null>(null);
|
|
52
|
+
|
|
53
|
+
React.useLayoutEffect(() => {
|
|
54
|
+
if (!containerRef.current) return;
|
|
55
|
+
// Read initial width synchronously before paint
|
|
56
|
+
setContainerWidth(containerRef.current.offsetWidth);
|
|
57
|
+
const observer = new ResizeObserver((entries) => {
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
setContainerWidth(entry.contentRect.width);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
observer.observe(containerRef.current);
|
|
63
|
+
return () => observer.disconnect();
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
const mainValue = data[config.value.field];
|
|
67
|
+
const formattedValue = typeof mainValue === "number"
|
|
68
|
+
? formatNumber(mainValue, config.value.format)
|
|
69
|
+
: String(mainValue ?? "N/A");
|
|
70
|
+
|
|
71
|
+
// Comparison rendering
|
|
72
|
+
let comparisonElement: React.ReactNode = null;
|
|
73
|
+
if (config.comparison) {
|
|
74
|
+
const comparisonValue = data[config.comparison.field];
|
|
75
|
+
if (typeof comparisonValue === "number") {
|
|
76
|
+
const formattedComparison = formatNumber(comparisonValue, config.comparison.format);
|
|
77
|
+
const isPositive = comparisonValue > 0;
|
|
78
|
+
const isNegative = comparisonValue < 0;
|
|
79
|
+
|
|
80
|
+
let colorClass = "text-surface-500 dark:text-surface-400";
|
|
81
|
+
if (config.comparison.intent === "increase_is_good") {
|
|
82
|
+
if (isPositive) colorClass = "text-emerald-500";
|
|
83
|
+
if (isNegative) colorClass = "text-red-500";
|
|
84
|
+
} else if (config.comparison.intent === "decrease_is_good") {
|
|
85
|
+
if (isPositive) colorClass = "text-red-500";
|
|
86
|
+
if (isNegative) colorClass = "text-emerald-500";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
comparisonElement = (
|
|
90
|
+
<span className={`font-medium ${compact ? "text-[10px]" : "text-xs"} ${colorClass}`}>
|
|
91
|
+
{formattedComparison}
|
|
92
|
+
</span>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const isSmall = compact || (containerWidth !== null && containerWidth < 200);
|
|
98
|
+
|
|
99
|
+
// Resolve icon via getIcon (Lucide-based resolution)
|
|
100
|
+
const iconElement = config.icon
|
|
101
|
+
? getIcon(config.icon, "text-surface-400 dark:text-surface-500", undefined, isSmall ? 14 : 18)
|
|
102
|
+
: null;
|
|
103
|
+
|
|
104
|
+
// ── Compact card-inline layout ──────────────────────────────────────
|
|
105
|
+
if (compact) {
|
|
106
|
+
return (
|
|
107
|
+
<div className={cls("flex flex-col gap-0.5 px-2.5 py-2 rounded-md bg-transparent border min-w-0", defaultBorderMixin)}>
|
|
108
|
+
<span className="text-[10px] uppercase tracking-wider text-surface-400 dark:text-surface-500 truncate">
|
|
109
|
+
{title}
|
|
110
|
+
</span>
|
|
111
|
+
<div className="flex items-baseline gap-1.5">
|
|
112
|
+
<span className="text-sm font-semibold tabular-nums text-surface-800 dark:text-surface-100">
|
|
113
|
+
{formattedValue}
|
|
114
|
+
</span>
|
|
115
|
+
{comparisonElement}
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Standard scorecard layout ───────────────────────────────────────
|
|
122
|
+
const baseClass = embedded
|
|
123
|
+
? `flex flex-col min-w-0 h-full ${isSmall ? "px-3.5 py-3" : "px-5 py-4"}`
|
|
124
|
+
: cls("rounded-lg flex flex-col min-w-0 bg-transparent border", defaultBorderMixin, isSmall ? "px-3.5 py-3" : "px-5 py-4");
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<div ref={containerRef} className={baseClass} style={embedded ? undefined : { minHeight: isSmall ? 68 : 92 }}>
|
|
128
|
+
{/* Title row */}
|
|
129
|
+
<div className={`flex items-center justify-between ${isSmall ? "mb-1" : "mb-2"}`}>
|
|
130
|
+
<div className="flex flex-col min-w-0">
|
|
131
|
+
<span className={`font-medium leading-snug truncate text-surface-500 dark:text-surface-400 ${isSmall ? "text-[11px]" : "text-xs"}`}>
|
|
132
|
+
{title}
|
|
133
|
+
</span>
|
|
134
|
+
{config.dateRange && !isSmall && (
|
|
135
|
+
<span className="text-[10px] text-surface-400 dark:text-surface-500 truncate mt-0.5">
|
|
136
|
+
{config.dateRange}
|
|
137
|
+
</span>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
{iconElement && (
|
|
141
|
+
<span className="ml-2 shrink-0">{iconElement}</span>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
{/* Main value */}
|
|
146
|
+
<div 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"}`}>
|
|
147
|
+
{formattedValue}
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
{/* Comparison */}
|
|
151
|
+
{comparisonElement && (
|
|
152
|
+
<div className={isSmall ? "mt-0.5" : "mt-1"}>
|
|
153
|
+
{comparisonElement}
|
|
154
|
+
</div>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
InsightsScorecardView.displayName = "InsightsScorecardView";
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { InsightDataResult } from "../types";
|
|
2
|
+
|
|
3
|
+
interface CacheEntry {
|
|
4
|
+
data: InsightDataResult;
|
|
5
|
+
timestamp: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* In-memory cache for insight query results.
|
|
10
|
+
* Supports TTL-based expiry and inflight request deduplication
|
|
11
|
+
* to prevent redundant network requests when multiple widgets
|
|
12
|
+
* share the same query.
|
|
13
|
+
*/
|
|
14
|
+
export class InsightsCache {
|
|
15
|
+
private cache = new Map<string, CacheEntry>();
|
|
16
|
+
private inflight = new Map<string, Promise<InsightDataResult>>();
|
|
17
|
+
|
|
18
|
+
constructor(private ttl: number = 60_000) {}
|
|
19
|
+
|
|
20
|
+
get(key: string): InsightDataResult | null {
|
|
21
|
+
const entry = this.cache.get(key);
|
|
22
|
+
if (!entry) return null;
|
|
23
|
+
if (Date.now() - entry.timestamp > this.ttl) {
|
|
24
|
+
this.cache.delete(key);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return entry.data;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
set(key: string, data: InsightDataResult): void {
|
|
31
|
+
this.cache.set(key, { data, timestamp: Date.now() });
|
|
32
|
+
this.inflight.delete(key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getInflight(key: string): Promise<InsightDataResult> | null {
|
|
36
|
+
return this.inflight.get(key) ?? null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setInflight(key: string, promise: Promise<InsightDataResult>): void {
|
|
40
|
+
this.inflight.set(key, promise);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
invalidate(key?: string): void {
|
|
44
|
+
if (key) {
|
|
45
|
+
this.cache.delete(key);
|
|
46
|
+
this.inflight.delete(key);
|
|
47
|
+
} else {
|
|
48
|
+
this.cache.clear();
|
|
49
|
+
this.inflight.clear();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { createContext, useContext, useMemo, type PropsWithChildren } from "react";
|
|
2
|
+
import { InsightsCache } from "./InsightsCache";
|
|
3
|
+
|
|
4
|
+
interface InsightsContextValue {
|
|
5
|
+
cache: InsightsCache;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const InsightsContext = createContext<InsightsContextValue | null>(null);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Root-level provider for the insights data engine.
|
|
12
|
+
* Injected automatically by the plugin via `providers: [{ scope: "root" }]`.
|
|
13
|
+
*
|
|
14
|
+
* Manages a single `InsightsCache` instance shared by all insight widgets
|
|
15
|
+
* for TTL-based caching and inflight request deduplication.
|
|
16
|
+
*/
|
|
17
|
+
export function InsightsProvider({
|
|
18
|
+
cacheTTL,
|
|
19
|
+
children
|
|
20
|
+
}: PropsWithChildren<{ cacheTTL?: number }>) {
|
|
21
|
+
const cache = useMemo(() => new InsightsCache(cacheTTL), [cacheTTL]);
|
|
22
|
+
const value = useMemo(() => ({ cache }), [cache]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<InsightsContext.Provider value={value}>
|
|
26
|
+
{children}
|
|
27
|
+
</InsightsContext.Provider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Access the insights cache (for advanced usage).
|
|
33
|
+
* Returns null when called outside of an `InsightsProvider`
|
|
34
|
+
* (e.g. during auth-loading phase before plugin providers mount).
|
|
35
|
+
*/
|
|
36
|
+
export function useInsightsEngine(): InsightsContextValue | null {
|
|
37
|
+
return useContext(InsightsContext);
|
|
38
|
+
}
|