@rebasepro/app 0.9.1-canary.ff338b5 → 0.10.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.
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
- import { AdminModeController } from "../hooks";
2
+ import type { AdminModeController } from "../hooks/useAdminModeController";
3
3
  export declare const AdminModeControllerContext: React.Context<AdminModeController>;
4
4
  export declare const AdminModeControllerProvider: React.Provider<AdminModeController>;
@@ -1,4 +1,4 @@
1
1
  import React from "react";
2
- import { ModeController } from "../hooks";
2
+ import type { ModeController } from "../hooks/useModeController";
3
3
  export declare const ModeControllerContext: React.Context<ModeController>;
4
4
  export declare const ModeControllerProvider: React.Provider<ModeController>;
@@ -1,4 +1,4 @@
1
- import { AdminModeController } from "./index";
1
+ import type { AdminModeController } from "./useAdminModeController";
2
2
  /**
3
3
  * Use this hook to build an admin mode controller that determines
4
4
  * whether the UI shows Developer or Editor tools.
@@ -1,4 +1,4 @@
1
- import { ModeController } from "./index";
1
+ import type { ModeController } from "./useModeController";
2
2
  /**
3
3
  * Use this hook to build a color mode controller that determines
4
4
  * the theme of the CMS
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { Blocker, BlockerFunction } from "react-router-dom";
3
+ /**
4
+ * Owns the single React Router blocker for the whole app.
5
+ *
6
+ * React Router only honours **one** blocker at a time: `shouldBlockNavigation`
7
+ * picks the last-registered blocker function and silently ignores every other
8
+ * one (it only logs a dev warning). Because blockers register in a `useEffect`,
9
+ * the winner is whichever surface mounted most recently — so an unsaved-changes
10
+ * guard could be disabled by an unrelated component mounting after it.
11
+ *
12
+ * This provider registers the only `useBlocker` in the tree and multiplexes it,
13
+ * so every surface that needs to guard navigation gets a say regardless of
14
+ * mount order. Surfaces register through {@link useNavigationBlocker}.
15
+ */
16
+ export declare function NavigationBlockerProvider({ children }: {
17
+ children: React.ReactNode;
18
+ }): React.JSX.Element;
19
+ /**
20
+ * Guard navigation with `predicate`, sharing the app-wide blocker.
21
+ *
22
+ * Returns a {@link Blocker} that is only ever in the `blocked` state when *this*
23
+ * registration is what blocked the navigation — so several guards can coexist
24
+ * without each of them popping a dialog.
25
+ *
26
+ * Returns an idle blocker when no {@link NavigationBlockerProvider} is mounted
27
+ * above, rather than competing for React Router's single blocker slot.
28
+ */
29
+ export declare function useNavigationBlocker(predicate: BlockerFunction): Blocker;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./contexts";
7
7
  export { CONTAINER_FULL_WIDTH, ADDITIONAL_TAB_WIDTH, FORM_CONTAINER_WIDTH } from "./internal/common";
8
8
  export { useRestoreScroll } from "./internal/useRestoreScroll";
9
9
  export { useUnsavedChangesDialog } from "./hooks/useUnsavedChangesDialog";
10
+ export { NavigationBlockerProvider, useNavigationBlocker } from "./hooks/useNavigationBlocker";
10
11
  export type { UnsavedChangesDialogProps } from "./components/UnsavedChangesDialog";
11
12
  export { UnsavedChangesDialog } from "./components/UnsavedChangesDialog";
12
13
  export * from "./i18n/RebaseI18nProvider";
package/dist/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { createContext, lazy, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
1
+ import React, { createContext, lazy, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
2
2
  import { Alert, AlertCircleIcon, AlertTriangleIcon, AppWindow, ArrowLeftIcon, Avatar, BooleanSwitch, Button, CHIP_COLORS, Card, CenteredView, CheckIcon, Checkbox, ChevronDownIcon, ChevronsLeftIcon, ChevronsRightIcon, Chip, CircleUserIcon, CircularProgress, ColumnsIcon, Container, Dialog, DialogActions, DialogContent, DialogTitle, ErrorBoundary, FileIcon, FileTextIcon, FilterChip, FilterIcon, FolderIcon, IconButton, KanbanIcon, KanbanView, LanguagesIcon, LayoutGridIcon, ListIcon, LoadingButton, LogOutIcon, MailIcon, Menu, MenuItem, MoonIcon, MultiSelect, MultiSelectItem, PanelLeftIcon, Paper, PencilIcon, PlusIcon, Popover, SearchBar, Select, SelectItem, Separator, SettingsIcon, Skeleton, SunIcon, SunMoonIcon, Tab, Table, TableBody, TableCell, TableHeader, TableRow, Tabs, TagIcon, TextField, ToggleButtonGroup, Tooltip, Trash2Icon, TypeIcon, Typography, UserIcon, Wand2Icon, cls, colorClassesMapping, coolIconKeys, defaultBorderMixin, getColorSchemeForSeed, iconKeys, iconSize, lucideIcons } from "@rebasepro/ui";
3
3
  import { DEFAULT_DATA_SOURCE_KEY, DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, RebaseApiError, Vector, isLazyComponentRef } from "@rebasepro/types";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1080,6 +1080,91 @@ async function deleteEntityWithCallbacks({ data, entity, collection, callbacks,
1080
1080
  });
1081
1081
  }
1082
1082
  //#endregion
1083
+ //#region src/hooks/useNavigationBlocker.tsx
1084
+ var IDLE_BLOCKER = {
1085
+ state: "unblocked",
1086
+ proceed: void 0,
1087
+ reset: void 0,
1088
+ location: void 0
1089
+ };
1090
+ var NavigationBlockerContext = createContext(null);
1091
+ /**
1092
+ * Owns the single React Router blocker for the whole app.
1093
+ *
1094
+ * React Router only honours **one** blocker at a time: `shouldBlockNavigation`
1095
+ * picks the last-registered blocker function and silently ignores every other
1096
+ * one (it only logs a dev warning). Because blockers register in a `useEffect`,
1097
+ * the winner is whichever surface mounted most recently — so an unsaved-changes
1098
+ * guard could be disabled by an unrelated component mounting after it.
1099
+ *
1100
+ * This provider registers the only `useBlocker` in the tree and multiplexes it,
1101
+ * so every surface that needs to guard navigation gets a say regardless of
1102
+ * mount order. Surfaces register through {@link useNavigationBlocker}.
1103
+ */
1104
+ function NavigationBlockerProvider({ children }) {
1105
+ const predicates = useRef(/* @__PURE__ */ new Map());
1106
+ const [blockedBy, setBlockedBy] = useState(null);
1107
+ const blocker = useBlocker(useCallback((args) => {
1108
+ for (const [id, predicate] of predicates.current) if (predicate(args)) {
1109
+ setBlockedBy(id);
1110
+ return true;
1111
+ }
1112
+ setBlockedBy(null);
1113
+ return false;
1114
+ }, []));
1115
+ const register = useCallback((id, predicate) => {
1116
+ predicates.current.set(id, predicate);
1117
+ }, []);
1118
+ const unregister = useCallback((id) => {
1119
+ predicates.current.delete(id);
1120
+ setBlockedBy((current) => current === id ? null : current);
1121
+ }, []);
1122
+ const value = useMemo(() => ({
1123
+ register,
1124
+ unregister,
1125
+ blocker,
1126
+ blockedBy
1127
+ }), [
1128
+ register,
1129
+ unregister,
1130
+ blocker,
1131
+ blockedBy
1132
+ ]);
1133
+ return /* @__PURE__ */ jsx(NavigationBlockerContext.Provider, {
1134
+ value,
1135
+ children
1136
+ });
1137
+ }
1138
+ /**
1139
+ * Guard navigation with `predicate`, sharing the app-wide blocker.
1140
+ *
1141
+ * Returns a {@link Blocker} that is only ever in the `blocked` state when *this*
1142
+ * registration is what blocked the navigation — so several guards can coexist
1143
+ * without each of them popping a dialog.
1144
+ *
1145
+ * Returns an idle blocker when no {@link NavigationBlockerProvider} is mounted
1146
+ * above, rather than competing for React Router's single blocker slot.
1147
+ */
1148
+ function useNavigationBlocker(predicate) {
1149
+ const context = useContext(NavigationBlockerContext);
1150
+ const id = useId();
1151
+ const predicateRef = useRef(predicate);
1152
+ predicateRef.current = predicate;
1153
+ const register = context?.register;
1154
+ const unregister = context?.unregister;
1155
+ useEffect(() => {
1156
+ if (!register || !unregister) return;
1157
+ register(id, (args) => predicateRef.current(args));
1158
+ return () => unregister(id);
1159
+ }, [
1160
+ register,
1161
+ unregister,
1162
+ id
1163
+ ]);
1164
+ if (!context) return IDLE_BLOCKER;
1165
+ return context.blockedBy === id ? context.blocker : IDLE_BLOCKER;
1166
+ }
1167
+ //#endregion
1083
1168
  //#region src/hooks/useUnsavedChangesDialog.tsx
1084
1169
  /**
1085
1170
  * A single, unified hook to prevent navigation when there are unsaved changes.
@@ -1090,7 +1175,7 @@ async function deleteEntityWithCallbacks({ data, entity, collection, callbacks,
1090
1175
  */
1091
1176
  function useUnsavedChangesDialog(when, onOk) {
1092
1177
  const [manualDialogOpen, setManualDialogOpen] = useState(false);
1093
- const blocker = useBlocker(({ currentLocation, nextLocation }) => when && currentLocation.pathname !== nextLocation.pathname);
1178
+ const blocker = useNavigationBlocker(useCallback(({ currentLocation, nextLocation }) => when && currentLocation.pathname !== nextLocation.pathname, [when]));
1094
1179
  useEffect(() => {
1095
1180
  if (!when) return;
1096
1181
  const handleBeforeUnload = (e) => {
@@ -15570,6 +15655,7 @@ function Rebase(props) {
15570
15655
  executeSql: wsAdmin.executeSql.bind(wsAdmin),
15571
15656
  fetchAvailableDatabases: wsAdmin.fetchAvailableDatabases?.bind(wsAdmin),
15572
15657
  fetchAvailableRoles: wsAdmin.fetchAvailableRoles?.bind(wsAdmin),
15658
+ fetchApplicationRoles: wsAdmin.fetchApplicationRoles?.bind(wsAdmin),
15573
15659
  fetchCurrentDatabase: wsAdmin.fetchCurrentDatabase?.bind(wsAdmin),
15574
15660
  fetchUnmappedTables: wsAdmin.fetchUnmappedTables?.bind(wsAdmin),
15575
15661
  fetchTableMetadata: wsAdmin.fetchTableMetadata?.bind(wsAdmin),
@@ -16888,6 +16974,6 @@ function useBridgeRegistration(key, value) {
16888
16974
  ]);
16889
16975
  }
16890
16976
  //#endregion
16891
- export { ADDITIONAL_TAB_WIDTH, AIIcon, AIModifiedIndicator, AdminModeControllerContext, AdminModeControllerProvider, AnalyticsContext, ApiConfigProvider, AuthApiError, AuthControllerContext, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, CollectionResolverRegistrationContext, CollectionScopeContext, CollectionScopeProvider, ComponentOverrideContext, ConfirmationDialog, CrmDashboardDemo, CustomizationControllerContext, DEFAULT_PAGE_SIZE, DataDriverContext, DataSourcesContext, DialogsControllerContext, DialogsProvider, EffectiveRoleControllerContext, EffectiveRoleControllerProvider, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, GlobalComponentOverrideProvider, IconForView, LanguageToggle, LoginView, ModeControllerContext, ModeControllerProvider, NotFoundPage, PluginProviderStack, REBASE_LOCALE_STORAGE_KEY, Rebase, RebaseAuth, RebaseClientInstanceContext, RebaseDataContext, RebaseI18nProvider, RebaseLogo, RebaseRegistryProvider, RebaseRouter, RebaseRoutes, STUDIO_NAVIGATION_GROUPS, SchemaDriftBanner, SchemaDriftProvider, SnackbarProvider, StorageSourceContext, StorageSourcesContext, StudioBridgeContext, StudioBridgeProvider, StudioBridgeRegistryContext, StudioBridgeRegistryProvider, UIReferenceView, UIStyleGuide, UnsavedChangesDialog, UserConfigurationPersistenceContext, UserDisplay, UserSelectPopover, UserSettingsView, buildCollapsedDefaults, buildEnumLabel, clearAuthConfigCache, clearFetchCache, createAuthConfigCache, createFormexStub, deleteEntityWithCallbacks, en, es, fetchAuthConfig, flattenKeys, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityPreviewKeys, getEntityTitlePropertyKey, getFormFieldKeys, getIcon, getRelationIncludeParams, getRowHeight, getSubcollectionColumnId, iconsSearch, isEnumValueDisabled, isSchemaDriftError, populateFetchCache, removeEntityFromCache, removeEntityFromMemoryCache, resolveComponentRef, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiConfig, useAuthController, useAuthSubscription, useBackendStorageSource, useBridgeRegistration, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildEffectiveRoleController, useBuildLocalConfigurationPersistence, useBuildModeController, useClipboard, useCollapsedGroups, useCollection, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useDebouncedData, useDialogsController, useEffectiveRoleController, useFetch, useLargeLayout, useModeController, usePermissions, useRebaseAuthController, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useSchemaDriftContext, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useStudioBreadcrumbs, useStudioCollectionRegistry, useStudioNavigationState, useStudioSidePanelController, useStudioUrlController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence };
16977
+ export { ADDITIONAL_TAB_WIDTH, AIIcon, AIModifiedIndicator, AdminModeControllerContext, AdminModeControllerProvider, AnalyticsContext, ApiConfigProvider, AuthApiError, AuthControllerContext, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, CollectionResolverRegistrationContext, CollectionScopeContext, CollectionScopeProvider, ComponentOverrideContext, ConfirmationDialog, CrmDashboardDemo, CustomizationControllerContext, DEFAULT_PAGE_SIZE, DataDriverContext, DataSourcesContext, DialogsControllerContext, DialogsProvider, EffectiveRoleControllerContext, EffectiveRoleControllerProvider, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, GlobalComponentOverrideProvider, IconForView, LanguageToggle, LoginView, ModeControllerContext, ModeControllerProvider, NavigationBlockerProvider, NotFoundPage, PluginProviderStack, REBASE_LOCALE_STORAGE_KEY, Rebase, RebaseAuth, RebaseClientInstanceContext, RebaseDataContext, RebaseI18nProvider, RebaseLogo, RebaseRegistryProvider, RebaseRouter, RebaseRoutes, STUDIO_NAVIGATION_GROUPS, SchemaDriftBanner, SchemaDriftProvider, SnackbarProvider, StorageSourceContext, StorageSourcesContext, StudioBridgeContext, StudioBridgeProvider, StudioBridgeRegistryContext, StudioBridgeRegistryProvider, UIReferenceView, UIStyleGuide, UnsavedChangesDialog, UserConfigurationPersistenceContext, UserDisplay, UserSelectPopover, UserSettingsView, buildCollapsedDefaults, buildEnumLabel, clearAuthConfigCache, clearFetchCache, createAuthConfigCache, createFormexStub, deleteEntityWithCallbacks, en, es, fetchAuthConfig, flattenKeys, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityPreviewKeys, getEntityTitlePropertyKey, getFormFieldKeys, getIcon, getRelationIncludeParams, getRowHeight, getSubcollectionColumnId, iconsSearch, isEnumValueDisabled, isSchemaDriftError, populateFetchCache, removeEntityFromCache, removeEntityFromMemoryCache, resolveComponentRef, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiConfig, useAuthController, useAuthSubscription, useBackendStorageSource, useBridgeRegistration, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildEffectiveRoleController, useBuildLocalConfigurationPersistence, useBuildModeController, useClipboard, useCollapsedGroups, useCollection, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useDebouncedData, useDialogsController, useEffectiveRoleController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseAuthController, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useSchemaDriftContext, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useStudioBreadcrumbs, useStudioCollectionRegistry, useStudioNavigationState, useStudioSidePanelController, useStudioUrlController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence };
16892
16978
 
16893
16979
  //# sourceMappingURL=index.es.js.map