@rebasepro/app 0.0.1-canary.4829d6e
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 +21 -0
- package/README.md +174 -0
- package/dist/auth/api.d.ts +66 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/types.d.ts +127 -0
- package/dist/auth/useRebaseAuthController.d.ts +13 -0
- package/dist/components/AIIcon.d.ts +17 -0
- package/dist/components/AuthSimulationMenu.d.ts +0 -0
- package/dist/components/ConfirmationDialog.d.ts +9 -0
- package/dist/components/Debug/UIReferenceView.d.ts +13 -0
- package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
- package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/index.d.ts +3 -0
- package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
- package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
- package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
- package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
- package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
- package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
- package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
- package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
- package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
- package/dist/components/ErrorTooltip.d.ts +3 -0
- package/dist/components/ErrorView.d.ts +21 -0
- package/dist/components/LanguageToggle.d.ts +2 -0
- package/dist/components/LoginView/LoginView.d.ts +113 -0
- package/dist/components/LoginView/index.d.ts +2 -0
- package/dist/components/NotFoundPage.d.ts +2 -0
- package/dist/components/RebaseAuth.d.ts +10 -0
- package/dist/components/RebaseLogo.d.ts +7 -0
- package/dist/components/SchemaDriftBanner.d.ts +27 -0
- package/dist/components/UnsavedChangesDialog.d.ts +9 -0
- package/dist/components/UserDisplay.d.ts +7 -0
- package/dist/components/UserSelectPopover.d.ts +63 -0
- package/dist/components/UserSettingsView.d.ts +2 -0
- package/dist/components/common/index.d.ts +6 -0
- package/dist/components/common/table_height.d.ts +5 -0
- package/dist/components/common/types.d.ts +66 -0
- package/dist/components/common/useColumnsIds.d.ts +9 -0
- package/dist/components/common/useDataTableController.d.ts +45 -0
- package/dist/components/common/useDebouncedData.d.ts +9 -0
- package/dist/components/common/useScrollRestoration.d.ts +14 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/contexts/AdminModeController.d.ts +4 -0
- package/dist/contexts/AnalyticsContext.d.ts +3 -0
- package/dist/contexts/AuthControllerContext.d.ts +3 -0
- package/dist/contexts/CollectionScopeContext.d.ts +50 -0
- package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
- package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
- package/dist/contexts/DataDriverContext.d.ts +3 -0
- package/dist/contexts/DataSourcesContext.d.ts +31 -0
- package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
- package/dist/contexts/DialogsProvider.d.ts +4 -0
- package/dist/contexts/EffectiveRoleController.d.ts +4 -0
- package/dist/contexts/ModeController.d.ts +4 -0
- package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
- package/dist/contexts/RebaseDataContext.d.ts +3 -0
- package/dist/contexts/SnackbarProvider.d.ts +2 -0
- package/dist/contexts/StorageSourceContext.d.ts +3 -0
- package/dist/contexts/StorageSourcesContext.d.ts +25 -0
- package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
- package/dist/contexts/index.d.ts +17 -0
- package/dist/core/PluginLifecycleManager.d.ts +17 -0
- package/dist/core/PluginProviderStack.d.ts +21 -0
- package/dist/core/Rebase.d.ts +15 -0
- package/dist/core/RebaseProps.d.ts +291 -0
- package/dist/core/RebaseRouter.d.ts +4 -0
- package/dist/core/RebaseRoutes.d.ts +17 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/hooks/ApiConfigContext.d.ts +24 -0
- package/dist/hooks/data/delete.d.ts +33 -0
- package/dist/hooks/data/save.d.ts +40 -0
- package/dist/hooks/data/useCollection.d.ts +62 -0
- package/dist/hooks/data/useData.d.ts +13 -0
- package/dist/hooks/data/useDataOrder.d.ts +12 -0
- package/dist/hooks/data/useFetch.d.ts +43 -0
- package/dist/hooks/data/useRelationSelector.d.ts +52 -0
- package/dist/hooks/index.d.ts +36 -0
- package/dist/hooks/useAdminModeController.d.ts +19 -0
- package/dist/hooks/useAnalyticsController.d.ts +5 -0
- package/dist/hooks/useAuthController.d.ts +11 -0
- package/dist/hooks/useAuthSubscription.d.ts +2 -0
- package/dist/hooks/useBackendStorageSource.d.ts +30 -0
- package/dist/hooks/useBridgeRegistration.d.ts +18 -0
- package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
- package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
- package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
- package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
- package/dist/hooks/useBuildModeController.d.ts +6 -0
- package/dist/hooks/useClipboard.d.ts +57 -0
- package/dist/hooks/useCollapsedGroups.d.ts +27 -0
- package/dist/hooks/useComponentOverride.d.ts +32 -0
- package/dist/hooks/useCustomizationController.d.ts +11 -0
- package/dist/hooks/useDialogsController.d.ts +11 -0
- package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
- package/dist/hooks/useLargeLayout.d.ts +1 -0
- package/dist/hooks/useModeController.d.ts +19 -0
- package/dist/hooks/usePermissions.d.ts +12 -0
- package/dist/hooks/useRebaseClient.d.ts +5 -0
- package/dist/hooks/useRebaseContext.d.ts +11 -0
- package/dist/hooks/useRebaseRegistry.d.ts +34 -0
- package/dist/hooks/useResolvedComponent.d.ts +47 -0
- package/dist/hooks/useSlot.d.ts +18 -0
- package/dist/hooks/useSnackbarController.d.ts +20 -0
- package/dist/hooks/useStorageSource.d.ts +6 -0
- package/dist/hooks/useStudioBridge.d.ts +79 -0
- package/dist/hooks/useTranslation.d.ts +17 -0
- package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
- package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
- package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.es.js +16843 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +17021 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/internal/common.d.ts +14 -0
- package/dist/internal/useRestoreScroll.d.ts +15 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/en.d.ts +10 -0
- package/dist/locales/es.d.ts +10 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/hi.d.ts +2 -0
- package/dist/locales/it.d.ts +2 -0
- package/dist/locales/pt.d.ts +7 -0
- package/dist/util/constants.d.ts +1 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/entity_cache.d.ts +22 -0
- package/dist/util/enums.d.ts +5 -0
- package/dist/util/icon_list.d.ts +5 -0
- package/dist/util/icons.d.ts +20 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/previews.d.ts +4 -0
- package/dist/util/useStorageUploadController.d.ts +44 -0
- package/dist/vitePlugin.d.ts +60 -0
- package/dist/vitePlugin.js +113 -0
- package/package.json +145 -0
- package/src/auth/api.ts +148 -0
- package/src/auth/index.ts +25 -0
- package/src/auth/types.ts +115 -0
- package/src/auth/useRebaseAuthController.ts +328 -0
- package/src/components/AIIcon.tsx +47 -0
- package/src/components/AuthSimulationMenu.tsx +0 -0
- package/src/components/ConfirmationDialog.tsx +48 -0
- package/src/components/Debug/UIReferenceView.tsx +958 -0
- package/src/components/Debug/UIStyleGuide.tsx +156 -0
- package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
- package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
- package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
- package/src/components/Debug/collection-views/index.ts +3 -0
- package/src/components/Debug/collection-views/sample_data.ts +42 -0
- package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
- package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
- package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
- package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
- package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
- package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
- package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
- package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
- package/src/components/ErrorTooltip.tsx +12 -0
- package/src/components/ErrorView.tsx +94 -0
- package/src/components/LanguageToggle.tsx +59 -0
- package/src/components/LoginView/LoginView.tsx +932 -0
- package/src/components/LoginView/index.ts +2 -0
- package/src/components/NotFoundPage.tsx +27 -0
- package/src/components/RebaseAuth.tsx +27 -0
- package/src/components/RebaseLogo.tsx +29 -0
- package/src/components/SchemaDriftBanner.tsx +102 -0
- package/src/components/UnsavedChangesDialog.tsx +46 -0
- package/src/components/UserDisplay.tsx +54 -0
- package/src/components/UserSelectPopover.tsx +399 -0
- package/src/components/UserSettingsView.tsx +318 -0
- package/src/components/common/index.ts +6 -0
- package/src/components/common/table_height.tsx +21 -0
- package/src/components/common/types.tsx +66 -0
- package/src/components/common/useColumnsIds.tsx +222 -0
- package/src/components/common/useDataTableController.tsx +514 -0
- package/src/components/common/useDebouncedData.ts +49 -0
- package/src/components/common/useScrollRestoration.tsx +68 -0
- package/src/components/index.tsx +26 -0
- package/src/contexts/AdminModeController.tsx +11 -0
- package/src/contexts/AnalyticsContext.tsx +4 -0
- package/src/contexts/AuthControllerContext.tsx +4 -0
- package/src/contexts/CollectionScopeContext.tsx +67 -0
- package/src/contexts/ComponentOverrideContext.tsx +81 -0
- package/src/contexts/CustomizationControllerContext.tsx +4 -0
- package/src/contexts/DataDriverContext.tsx +4 -0
- package/src/contexts/DataSourcesContext.tsx +36 -0
- package/src/contexts/DatabaseAdminContext.tsx +4 -0
- package/src/contexts/DialogsProvider.tsx +56 -0
- package/src/contexts/EffectiveRoleController.tsx +12 -0
- package/src/contexts/ModeController.tsx +11 -0
- package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
- package/src/contexts/RebaseDataContext.tsx +4 -0
- package/src/contexts/SnackbarProvider.tsx +15 -0
- package/src/contexts/StorageSourceContext.tsx +4 -0
- package/src/contexts/StorageSourcesContext.tsx +30 -0
- package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
- package/src/contexts/index.ts +17 -0
- package/src/core/PluginLifecycleManager.tsx +95 -0
- package/src/core/PluginProviderStack.tsx +40 -0
- package/src/core/Rebase.tsx +439 -0
- package/src/core/RebaseProps.tsx +320 -0
- package/src/core/RebaseRouter.tsx +17 -0
- package/src/core/RebaseRoutes.tsx +24 -0
- package/src/core/index.tsx +5 -0
- package/src/hooks/ApiConfigContext.tsx +41 -0
- package/src/hooks/data/delete.ts +55 -0
- package/src/hooks/data/save.ts +77 -0
- package/src/hooks/data/useCollection.tsx +176 -0
- package/src/hooks/data/useData.tsx +18 -0
- package/src/hooks/data/useDataOrder.ts +26 -0
- package/src/hooks/data/useFetch.tsx +140 -0
- package/src/hooks/data/useRelationSelector.tsx +234 -0
- package/src/hooks/index.tsx +45 -0
- package/src/hooks/useAdminModeController.tsx +23 -0
- package/src/hooks/useAnalyticsController.tsx +8 -0
- package/src/hooks/useAuthController.tsx +14 -0
- package/src/hooks/useAuthSubscription.ts +87 -0
- package/src/hooks/useBackendStorageSource.ts +288 -0
- package/src/hooks/useBridgeRegistration.tsx +32 -0
- package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
- package/src/hooks/useBuildAdminModeController.tsx +24 -0
- package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
- package/src/hooks/useBuildModeController.tsx +71 -0
- package/src/hooks/useClipboard.tsx +158 -0
- package/src/hooks/useCollapsedGroups.ts +116 -0
- package/src/hooks/useComponentOverride.tsx +59 -0
- package/src/hooks/useCustomizationController.tsx +14 -0
- package/src/hooks/useDialogsController.tsx +15 -0
- package/src/hooks/useEffectiveRoleController.tsx +10 -0
- package/src/hooks/useLargeLayout.tsx +65 -0
- package/src/hooks/useModeController.tsx +23 -0
- package/src/hooks/usePermissions.ts +44 -0
- package/src/hooks/useRebaseClient.tsx +10 -0
- package/src/hooks/useRebaseContext.tsx +83 -0
- package/src/hooks/useRebaseRegistry.tsx +91 -0
- package/src/hooks/useResolvedComponent.tsx +159 -0
- package/src/hooks/useSlot.tsx +64 -0
- package/src/hooks/useSnackbarController.tsx +52 -0
- package/src/hooks/useStorageSource.tsx +11 -0
- package/src/hooks/useStudioBridge.tsx +209 -0
- package/src/hooks/useTranslation.ts +33 -0
- package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
- package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
- package/src/i18n/RebaseI18nProvider.tsx +160 -0
- package/src/index.ts +25 -0
- package/src/internal/common.tsx +16 -0
- package/src/internal/useRestoreScroll.tsx +69 -0
- package/src/locales/de.ts +902 -0
- package/src/locales/en.ts +980 -0
- package/src/locales/es.ts +922 -0
- package/src/locales/fr.ts +901 -0
- package/src/locales/hi.ts +901 -0
- package/src/locales/it.ts +901 -0
- package/src/locales/pt.ts +909 -0
- package/src/util/constants.ts +7 -0
- package/src/util/createFormexStub.tsx +66 -0
- package/src/util/entity_cache.ts +239 -0
- package/src/util/enums.ts +32 -0
- package/src/util/icon_list.ts +22 -0
- package/src/util/icons.tsx +149 -0
- package/src/util/index.ts +12 -0
- package/src/util/previews.ts +105 -0
- package/src/util/useStorageUploadController.tsx +350 -0
- package/src/vitePlugin.ts +196 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import type { RebaseProps } from "./RebaseProps";
|
|
3
|
+
import type { CustomizationController, RebasePlugin, SlotContribution } from "@rebasepro/types";
|
|
4
|
+
import type { ComponentOverrideMap } from "@rebasepro/types";
|
|
5
|
+
|
|
6
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { CenteredView, Typography } from "@rebasepro/ui";
|
|
8
|
+
import { RebaseContext, User, CollectionRegistryController, DataDriver, DataSourceDefinition, RebaseData, DEFAULT_DATA_SOURCE_KEY, StorageSource, StorageSourceDefinition, DEFAULT_STORAGE_SOURCE_KEY } from "@rebasepro/types";
|
|
9
|
+
import { PluginProviderStack } from "./PluginProviderStack";
|
|
10
|
+
import { PluginLifecycleManager } from "./PluginLifecycleManager";
|
|
11
|
+
import { AuthControllerContext } from "../contexts";
|
|
12
|
+
import { useCustomizationController, useRebaseContext, useAuthSubscription } from "../hooks";
|
|
13
|
+
import { ApiConfigProvider, useApiConfig } from "../hooks/ApiConfigContext";
|
|
14
|
+
import { ErrorView } from "../components";
|
|
15
|
+
import { StorageSourceContext } from "../contexts/StorageSourceContext";
|
|
16
|
+
import { UserConfigurationPersistenceContext } from "../contexts/UserConfigurationPersistenceContext";
|
|
17
|
+
import { RebaseDataContext } from "../contexts/RebaseDataContext";
|
|
18
|
+
import { DataSourcesContext, DataSourcesContextValue } from "../contexts/DataSourcesContext";
|
|
19
|
+
import { StorageSourcesContext, StorageSourcesContextValue } from "../contexts/StorageSourcesContext";
|
|
20
|
+
import { DatabaseAdminContext } from "../contexts/DatabaseAdminContext";
|
|
21
|
+
import { ModeControllerProvider, AdminModeControllerProvider, SnackbarProvider } from "../contexts";
|
|
22
|
+
import { RebaseI18nProvider } from "../i18n/RebaseI18nProvider";
|
|
23
|
+
import { RebaseRegistryProvider } from "../hooks/useRebaseRegistry";
|
|
24
|
+
import { SchemaDriftProvider } from "../components/SchemaDriftBanner";
|
|
25
|
+
import { GlobalComponentOverrideProvider } from "../contexts/ComponentOverrideContext";
|
|
26
|
+
import { useBuildModeController } from "../hooks/useBuildModeController";
|
|
27
|
+
import { useBuildAdminModeController } from "../hooks/useBuildAdminModeController";
|
|
28
|
+
import { RebaseClientInstanceContext } from "../contexts/RebaseClientInstanceContext";
|
|
29
|
+
import { DialogsProvider } from "../contexts/DialogsProvider";
|
|
30
|
+
import { buildRebaseData, wrapAsEntityData, CollectionRegistry } from "@rebasepro/common";
|
|
31
|
+
import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
|
|
32
|
+
import { AnalyticsContext } from "../contexts/AnalyticsContext";
|
|
33
|
+
|
|
34
|
+
import { EffectiveRoleControllerContext } from "../contexts/EffectiveRoleController";
|
|
35
|
+
import { useBuildEffectiveRoleController } from "../hooks/useBuildEffectiveRoleController";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* If you are using independent components of the CMS
|
|
39
|
+
* you need to wrap them with this main component, so the internal hooks work.
|
|
40
|
+
*
|
|
41
|
+
* This is the main component of Rebase. It acts as the provider of all the
|
|
42
|
+
* internal contexts and hooks.
|
|
43
|
+
*
|
|
44
|
+
* You only need to use this component if you are building a custom app.
|
|
45
|
+
*
|
|
46
|
+
* @group Core
|
|
47
|
+
*/
|
|
48
|
+
export function Rebase<USER extends User>(props: RebaseProps<USER>) {
|
|
49
|
+
|
|
50
|
+
const {
|
|
51
|
+
children,
|
|
52
|
+
entityLinkBuilder,
|
|
53
|
+
userConfigPersistence,
|
|
54
|
+
dateTimeFormat,
|
|
55
|
+
locale,
|
|
56
|
+
client,
|
|
57
|
+
authController: authControllerProp,
|
|
58
|
+
storageSource: storageSourceProp,
|
|
59
|
+
dataSources: dataSourcesProp,
|
|
60
|
+
storageSources: storageSourcesProp,
|
|
61
|
+
|
|
62
|
+
databaseAdmin,
|
|
63
|
+
plugins: pluginsProp,
|
|
64
|
+
slots: directSlots = [],
|
|
65
|
+
onAnalyticsEvent,
|
|
66
|
+
propertyConfigs,
|
|
67
|
+
entityViews,
|
|
68
|
+
entityActions,
|
|
69
|
+
|
|
70
|
+
effectiveRoleController,
|
|
71
|
+
apiUrl,
|
|
72
|
+
translations,
|
|
73
|
+
components: componentsProp
|
|
74
|
+
} = props;
|
|
75
|
+
|
|
76
|
+
const plugins = pluginsProp;
|
|
77
|
+
|
|
78
|
+
// Validate plugin key uniqueness
|
|
79
|
+
if (plugins) {
|
|
80
|
+
const keys = plugins.map((p) => p.key);
|
|
81
|
+
if (new Set(keys).size !== keys.length) {
|
|
82
|
+
console.error("Duplicate plugin keys detected:", keys.filter((k, i) => keys.indexOf(k) !== i));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Merge direct slots with plugin slots
|
|
87
|
+
const resolvedSlots: SlotContribution[] = useMemo(() => [
|
|
88
|
+
...directSlots,
|
|
89
|
+
...((plugins ?? []).flatMap((p) => p.slots ?? []))
|
|
90
|
+
], [directSlots, plugins]);
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
// Auth fallback logic
|
|
94
|
+
const clientAuthController = useAuthSubscription(authControllerProp ? undefined : client?.auth);
|
|
95
|
+
const authController = authControllerProp ?? clientAuthController;
|
|
96
|
+
|
|
97
|
+
const normalizedDataSources = useMemo(() => {
|
|
98
|
+
return dataSourcesProp ?? [];
|
|
99
|
+
}, [dataSourcesProp]);
|
|
100
|
+
|
|
101
|
+
// Build the data-source context: the declared registry plus a RebaseData
|
|
102
|
+
// per direct/custom source (those carrying a client-side driver). Server-
|
|
103
|
+
// mediated sources have no entry — they ride the default client.
|
|
104
|
+
//
|
|
105
|
+
// Shallow-compared against the previous build (key/engine/transport +
|
|
106
|
+
// driver instances) so inline `dataSources` literals don't rebuild
|
|
107
|
+
// RebaseData instances every render and thrash data-fetch effects that
|
|
108
|
+
// key off the data identity.
|
|
109
|
+
const dataSourcesRef = useRef<{
|
|
110
|
+
sig: { key: string; engine: string; transport?: string; driver?: DataDriver }[];
|
|
111
|
+
value: DataSourcesContextValue;
|
|
112
|
+
} | null>(null);
|
|
113
|
+
const dataSourcesValue = useMemo<DataSourcesContextValue>(() => {
|
|
114
|
+
const sig = normalizedDataSources.map((d) => ({ key: d.key, engine: d.engine, transport: d.transport, driver: d.driver }));
|
|
115
|
+
const prev = dataSourcesRef.current;
|
|
116
|
+
if (prev
|
|
117
|
+
&& prev.sig.length === sig.length
|
|
118
|
+
&& sig.every((s, i) => prev.sig[i].key === s.key
|
|
119
|
+
&& prev.sig[i].engine === s.engine
|
|
120
|
+
&& prev.sig[i].transport === s.transport
|
|
121
|
+
&& prev.sig[i].driver === s.driver)) {
|
|
122
|
+
return prev.value;
|
|
123
|
+
}
|
|
124
|
+
const registry: Record<string, DataSourceDefinition> = {};
|
|
125
|
+
const sources: Record<string, RebaseData> = {};
|
|
126
|
+
for (const ds of normalizedDataSources) {
|
|
127
|
+
const { driver, ...definition } = ds;
|
|
128
|
+
// Materialize the inferred transport so downstream consumers
|
|
129
|
+
// (routing, editor capabilities) always see a concrete value.
|
|
130
|
+
registry[ds.key] = {
|
|
131
|
+
...definition,
|
|
132
|
+
transport: ds.transport ?? (driver ? "direct" : "server")
|
|
133
|
+
};
|
|
134
|
+
if (driver) sources[ds.key] = buildRebaseData(driver);
|
|
135
|
+
}
|
|
136
|
+
const value: DataSourcesContextValue = { registry, sources };
|
|
137
|
+
dataSourcesRef.current = { sig, value };
|
|
138
|
+
return value;
|
|
139
|
+
}, [normalizedDataSources]);
|
|
140
|
+
|
|
141
|
+
// Default data source — serves every collection not routed to a
|
|
142
|
+
// registered direct/custom source. Resolution:
|
|
143
|
+
// 1. A "(default)"-keyed data source with a driver.
|
|
144
|
+
// 2. `client.data`.
|
|
145
|
+
// 3. The sole registered source, when it is the only candidate.
|
|
146
|
+
const resolvedData = useMemo(() => {
|
|
147
|
+
const registeredDefault = dataSourcesValue.sources[DEFAULT_DATA_SOURCE_KEY];
|
|
148
|
+
if (registeredDefault) return registeredDefault;
|
|
149
|
+
// CMS boundary: the SDK client returns flat rows; wrap them into the
|
|
150
|
+
// Entity view-model the admin (`useData()`) renders.
|
|
151
|
+
if (client?.data) return wrapAsEntityData(client.data);
|
|
152
|
+
const built = Object.values(dataSourcesValue.sources);
|
|
153
|
+
if (built.length === 1) return built[0];
|
|
154
|
+
if (built.length > 1) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
"[Rebase] Several data sources are registered but none is the default. " +
|
|
157
|
+
"Pass a `client`, or key one `dataSources` entry \"(default)\"."
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
throw new Error("Rebase requires either `client` or a `dataSources` entry with a driver to be provided");
|
|
161
|
+
}, [client, dataSourcesValue]);
|
|
162
|
+
|
|
163
|
+
// Storage fallback logic
|
|
164
|
+
const resolvedStorage = storageSourceProp ?? client?.storage;
|
|
165
|
+
|
|
166
|
+
// ── Storage sources (mirrors the dataSources pattern) ────────────
|
|
167
|
+
// Storage-source definitions discovered from the backend via
|
|
168
|
+
// `GET /api/storage/sources`. The backend is the single source of truth;
|
|
169
|
+
// server-transport sources are auto-wired on the client, `direct` sources
|
|
170
|
+
// are completed by the `storageSources` prop (which holds live instances).
|
|
171
|
+
const [remoteStorageSources, setRemoteStorageSources] = useState<StorageSourceDefinition[]>([]);
|
|
172
|
+
const authUser = authController.user;
|
|
173
|
+
const loginSkipped = authController.loginSkipped;
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (!client?.fetchStorageSources) return;
|
|
176
|
+
let cancelled = false;
|
|
177
|
+
client.fetchStorageSources()
|
|
178
|
+
.then((defs) => { if (!cancelled) setRemoteStorageSources(defs); })
|
|
179
|
+
.catch((e) => {
|
|
180
|
+
// A 401 before auth is expected; the effect re-runs once the
|
|
181
|
+
// user logs in (authUser/loginSkipped change) and retries.
|
|
182
|
+
console.debug("[Rebase] Could not load storage sources", e);
|
|
183
|
+
});
|
|
184
|
+
return () => { cancelled = true; };
|
|
185
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
186
|
+
}, [client, authUser, loginSkipped]);
|
|
187
|
+
|
|
188
|
+
// Normalize the prop + discovered definitions into a registry + sources map.
|
|
189
|
+
const storageSourcesRef = useRef<{
|
|
190
|
+
propList: { key: string; source?: StorageSource; transport?: string }[];
|
|
191
|
+
remote: StorageSourceDefinition[];
|
|
192
|
+
resolvedStorage?: StorageSource;
|
|
193
|
+
client?: typeof client;
|
|
194
|
+
value: StorageSourcesContextValue;
|
|
195
|
+
} | null>(null);
|
|
196
|
+
const storageSourcesValue = useMemo<StorageSourcesContextValue>(() => {
|
|
197
|
+
const list = storageSourcesProp ?? [];
|
|
198
|
+
const prev = storageSourcesRef.current;
|
|
199
|
+
// Stable identity unless an input actually changed (the prop may be a
|
|
200
|
+
// fresh array literal on every render; sources are compared by identity).
|
|
201
|
+
if (prev
|
|
202
|
+
&& prev.remote === remoteStorageSources
|
|
203
|
+
&& prev.resolvedStorage === resolvedStorage
|
|
204
|
+
&& prev.client === client
|
|
205
|
+
&& prev.propList.length === list.length
|
|
206
|
+
&& list.every((s, i) => prev.propList[i].key === s.key
|
|
207
|
+
&& prev.propList[i].source === s.source
|
|
208
|
+
&& prev.propList[i].transport === s.transport)) {
|
|
209
|
+
return prev.value;
|
|
210
|
+
}
|
|
211
|
+
const registry: Record<string, StorageSourceDefinition> = {};
|
|
212
|
+
const sources: Record<string, StorageSource> = {};
|
|
213
|
+
|
|
214
|
+
// 1. Definitions discovered from the backend (labels, engine, transport).
|
|
215
|
+
for (const def of remoteStorageSources) {
|
|
216
|
+
registry[def.key] = def;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 2. Server-backed named sources wired on the client registry: the
|
|
220
|
+
// default, `createRebaseClient({ storageSources })`, and any
|
|
221
|
+
// server-transport sources auto-registered by `fetchStorageSources`.
|
|
222
|
+
if (client?.storageRegistry) {
|
|
223
|
+
for (const key of client.storageRegistry.list()) {
|
|
224
|
+
const source = client.storageRegistry.get(key);
|
|
225
|
+
if (source) sources[key] = source;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 3. App-provided definitions: `direct` live sources and overrides.
|
|
230
|
+
for (const ss of list) {
|
|
231
|
+
const { source, ...definition } = ss;
|
|
232
|
+
registry[ss.key] = definition;
|
|
233
|
+
if (source) {
|
|
234
|
+
// `direct` transport: app-provided live source (e.g. Firebase).
|
|
235
|
+
sources[ss.key] = source;
|
|
236
|
+
} else if (!sources[ss.key]
|
|
237
|
+
&& ss.transport === "server"
|
|
238
|
+
&& ss.key !== DEFAULT_STORAGE_SOURCE_KEY
|
|
239
|
+
&& client?.createStorageSource) {
|
|
240
|
+
// `server` transport declared only on the prop: build a
|
|
241
|
+
// backend-routed source so requests carry `?storageId=key`.
|
|
242
|
+
sources[ss.key] = client.createStorageSource(ss.key);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// 4. Default/server storage from the client.
|
|
246
|
+
if (resolvedStorage && !sources[DEFAULT_STORAGE_SOURCE_KEY]) {
|
|
247
|
+
sources[DEFAULT_STORAGE_SOURCE_KEY] = resolvedStorage;
|
|
248
|
+
}
|
|
249
|
+
const value: StorageSourcesContextValue = { registry, sources };
|
|
250
|
+
storageSourcesRef.current = {
|
|
251
|
+
propList: list.map((s) => ({ key: s.key, source: s.source, transport: s.transport })),
|
|
252
|
+
remote: remoteStorageSources,
|
|
253
|
+
resolvedStorage,
|
|
254
|
+
client,
|
|
255
|
+
value
|
|
256
|
+
};
|
|
257
|
+
return value;
|
|
258
|
+
}, [storageSourcesProp, remoteStorageSources, resolvedStorage, client]);
|
|
259
|
+
|
|
260
|
+
// Database admin — use explicit prop, or derive from client.ws / driver when available.
|
|
261
|
+
const resolvedDatabaseAdmin = useMemo(() => {
|
|
262
|
+
if (databaseAdmin) return databaseAdmin;
|
|
263
|
+
|
|
264
|
+
// 1. The default source's DataDriver exposes `.admin` capability object
|
|
265
|
+
const defaultDriver = normalizedDataSources.find((d) => d.key === DEFAULT_DATA_SOURCE_KEY && d.driver)?.driver
|
|
266
|
+
?? (!client && normalizedDataSources.length === 1 ? normalizedDataSources[0].driver : undefined);
|
|
267
|
+
if (defaultDriver?.admin) {
|
|
268
|
+
return defaultDriver.admin;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 2. Auto-derive from the client's WebSocket connection (Rebase backend)
|
|
272
|
+
const ws = client?.ws;
|
|
273
|
+
if (ws && typeof (ws as unknown as Record<string, unknown>).executeSql === "function") {
|
|
274
|
+
const wsAdmin = ws as unknown as import("@rebasepro/types").DatabaseAdmin;
|
|
275
|
+
return {
|
|
276
|
+
executeSql: wsAdmin.executeSql!.bind(wsAdmin),
|
|
277
|
+
fetchAvailableDatabases: wsAdmin.fetchAvailableDatabases?.bind(wsAdmin),
|
|
278
|
+
fetchAvailableRoles: wsAdmin.fetchAvailableRoles?.bind(wsAdmin),
|
|
279
|
+
fetchCurrentDatabase: wsAdmin.fetchCurrentDatabase?.bind(wsAdmin),
|
|
280
|
+
fetchUnmappedTables: wsAdmin.fetchUnmappedTables?.bind(wsAdmin),
|
|
281
|
+
fetchTableMetadata: wsAdmin.fetchTableMetadata?.bind(wsAdmin),
|
|
282
|
+
// Branch admin capabilities
|
|
283
|
+
...(typeof wsAdmin.createBranch === "function" ? {
|
|
284
|
+
createBranch: wsAdmin.createBranch.bind(wsAdmin),
|
|
285
|
+
deleteBranch: wsAdmin.deleteBranch!.bind(wsAdmin),
|
|
286
|
+
listBranches: wsAdmin.listBranches!.bind(wsAdmin)
|
|
287
|
+
} : {})
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return undefined;
|
|
292
|
+
}, [databaseAdmin, client, normalizedDataSources]);
|
|
293
|
+
|
|
294
|
+
if (!resolvedStorage && typeof console !== "undefined") {
|
|
295
|
+
console.warn(
|
|
296
|
+
"[Rebase] No storageSource provided. File upload features will not work. " +
|
|
297
|
+
"Provide storageSource via props or through a RebaseClient."
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const pluginsLoading = plugins?.some((p) => p.loading) ?? false;
|
|
302
|
+
|
|
303
|
+
const loading = authController.initialLoading || pluginsLoading;
|
|
304
|
+
|
|
305
|
+
const customizationController: CustomizationController = useMemo(() => ({
|
|
306
|
+
dateTimeFormat,
|
|
307
|
+
locale,
|
|
308
|
+
entityLinkBuilder,
|
|
309
|
+
plugins,
|
|
310
|
+
resolvedSlots,
|
|
311
|
+
entityViews: entityViews ?? [],
|
|
312
|
+
entityActions: entityActions ?? [],
|
|
313
|
+
propertyConfigs: propertyConfigs ?? {},
|
|
314
|
+
components: componentsProp
|
|
315
|
+
}), [dateTimeFormat, locale, entityLinkBuilder, plugins, resolvedSlots, entityViews, entityActions, propertyConfigs, componentsProp]);
|
|
316
|
+
|
|
317
|
+
const analyticsController = useMemo(() => ({
|
|
318
|
+
onAnalyticsEvent
|
|
319
|
+
}), []);
|
|
320
|
+
|
|
321
|
+
const fallbackEffectiveRoleController = useBuildEffectiveRoleController();
|
|
322
|
+
const activeEffectiveRoleController = effectiveRoleController ?? fallbackEffectiveRoleController;
|
|
323
|
+
|
|
324
|
+
const modeController = useBuildModeController();
|
|
325
|
+
const adminModeController = useBuildAdminModeController();
|
|
326
|
+
|
|
327
|
+
if (authController.authError) {
|
|
328
|
+
return (
|
|
329
|
+
<CenteredView maxWidth={"md"}>
|
|
330
|
+
<ErrorView
|
|
331
|
+
title={"Error loading auth"}
|
|
332
|
+
error={authController.authError as Error | string}/>
|
|
333
|
+
</CenteredView>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const content = (
|
|
338
|
+
<RebaseI18nProvider locale={locale} translations={translations}>
|
|
339
|
+
<GlobalComponentOverrideProvider overrides={componentsProp}>
|
|
340
|
+
<SnackbarProvider>
|
|
341
|
+
<ModeControllerProvider value={modeController}>
|
|
342
|
+
<AdminModeControllerProvider value={adminModeController}>
|
|
343
|
+
<RebaseClientInstanceContext.Provider value={client}>
|
|
344
|
+
<AnalyticsContext.Provider value={analyticsController}>
|
|
345
|
+
<CustomizationControllerContext.Provider value={customizationController}>
|
|
346
|
+
<UserConfigurationPersistenceContext.Provider
|
|
347
|
+
value={userConfigPersistence}>
|
|
348
|
+
<StorageSourcesContext.Provider
|
|
349
|
+
value={storageSourcesValue}>
|
|
350
|
+
<StorageSourceContext.Provider
|
|
351
|
+
value={resolvedStorage!}>
|
|
352
|
+
<DataSourcesContext.Provider
|
|
353
|
+
value={dataSourcesValue}>
|
|
354
|
+
<RebaseDataContext.Provider
|
|
355
|
+
value={resolvedData}>
|
|
356
|
+
<DatabaseAdminContext.Provider
|
|
357
|
+
value={resolvedDatabaseAdmin}>
|
|
358
|
+
<AuthControllerContext.Provider
|
|
359
|
+
value={authController}>
|
|
360
|
+
<EffectiveRoleControllerContext.Provider value={activeEffectiveRoleController}>
|
|
361
|
+
<DialogsProvider>
|
|
362
|
+
<SchemaDriftProvider>
|
|
363
|
+
<RebaseRegistryProvider>
|
|
364
|
+
<RebaseInternal
|
|
365
|
+
loading={loading}>
|
|
366
|
+
{children}
|
|
367
|
+
</RebaseInternal>
|
|
368
|
+
</RebaseRegistryProvider>
|
|
369
|
+
</SchemaDriftProvider>
|
|
370
|
+
</DialogsProvider>
|
|
371
|
+
</EffectiveRoleControllerContext.Provider>
|
|
372
|
+
</AuthControllerContext.Provider>
|
|
373
|
+
</DatabaseAdminContext.Provider>
|
|
374
|
+
</RebaseDataContext.Provider>
|
|
375
|
+
</DataSourcesContext.Provider>
|
|
376
|
+
</StorageSourceContext.Provider>
|
|
377
|
+
</StorageSourcesContext.Provider>
|
|
378
|
+
</UserConfigurationPersistenceContext.Provider>
|
|
379
|
+
</CustomizationControllerContext.Provider>
|
|
380
|
+
</AnalyticsContext.Provider>
|
|
381
|
+
</RebaseClientInstanceContext.Provider>
|
|
382
|
+
</AdminModeControllerProvider>
|
|
383
|
+
</ModeControllerProvider>
|
|
384
|
+
</SnackbarProvider>
|
|
385
|
+
</GlobalComponentOverrideProvider>
|
|
386
|
+
</RebaseI18nProvider>
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const resolvedApiUrl = apiUrl || client?.baseUrl || (typeof window !== "undefined" ? window.location.origin : "");
|
|
390
|
+
|
|
391
|
+
if (resolvedApiUrl) {
|
|
392
|
+
return (
|
|
393
|
+
<ApiConfigProvider apiUrl={resolvedApiUrl} getAuthToken={authController.getAuthToken}>
|
|
394
|
+
{content}
|
|
395
|
+
</ApiConfigProvider>
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return content;
|
|
400
|
+
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function RebaseInternal({
|
|
404
|
+
loading,
|
|
405
|
+
children
|
|
406
|
+
}: {
|
|
407
|
+
loading: boolean;
|
|
408
|
+
children: React.ReactNode | ((props: { context: RebaseContext; loading: boolean; }) => React.ReactNode);
|
|
409
|
+
}) {
|
|
410
|
+
|
|
411
|
+
const context = useRebaseContext();
|
|
412
|
+
const customizationController = useCustomizationController();
|
|
413
|
+
|
|
414
|
+
const childrenResult = typeof children === "function" ? children({
|
|
415
|
+
context,
|
|
416
|
+
loading
|
|
417
|
+
}) : children;
|
|
418
|
+
|
|
419
|
+
const plugins = customizationController.plugins;
|
|
420
|
+
const authController = context.authController;
|
|
421
|
+
const authReady = !loading
|
|
422
|
+
&& !authController.authLoading
|
|
423
|
+
&& (Boolean(authController.user) || authController.loginSkipped);
|
|
424
|
+
|
|
425
|
+
if (plugins && plugins.length > 0) {
|
|
426
|
+
return (
|
|
427
|
+
<PluginProviderStack
|
|
428
|
+
plugins={plugins}
|
|
429
|
+
scope="root"
|
|
430
|
+
scopeProps={{ context }}>
|
|
431
|
+
{authReady && <PluginLifecycleManager plugins={plugins} context={context}/>}
|
|
432
|
+
{childrenResult}
|
|
433
|
+
</PluginProviderStack>
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return childrenResult;
|
|
438
|
+
}
|
|
439
|
+
|