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