@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,158 @@
|
|
|
1
|
+
// FORKED FROM https://github.com/fayeed/use-clipboard
|
|
2
|
+
|
|
3
|
+
import { MutableRefObject, useCallback, useEffect, useRef, useState, useMemo } from "react";
|
|
4
|
+
|
|
5
|
+
export interface UseClipboardProps {
|
|
6
|
+
/**
|
|
7
|
+
* It's callback function that is called after the `copy` command
|
|
8
|
+
* is executed.
|
|
9
|
+
*
|
|
10
|
+
* @param text: The selected clipboard text.
|
|
11
|
+
*/
|
|
12
|
+
onSuccess?: (text: string) => void;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Triggers when the hook encounters an error.
|
|
16
|
+
* If passed hook won't throw an error.
|
|
17
|
+
*
|
|
18
|
+
* @param error: cause of the error
|
|
19
|
+
*/
|
|
20
|
+
onError?: (error: string) => void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Disables the new clipboard API `navigator.clipboard` even if
|
|
24
|
+
* it is supported.
|
|
25
|
+
*/
|
|
26
|
+
disableClipboardAPI?: boolean;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* revert back the isCopied flag to false again if a value is set.
|
|
30
|
+
*/
|
|
31
|
+
copiedDuration?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface useClipboardReturnType {
|
|
35
|
+
/**
|
|
36
|
+
* Use ref to pull the text content from.
|
|
37
|
+
*/
|
|
38
|
+
ref: MutableRefObject<any>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Use it to perform the copy operation
|
|
42
|
+
*/
|
|
43
|
+
copy: (text?: string) => void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Use it to perform the cut operation
|
|
47
|
+
*/
|
|
48
|
+
cut: () => void;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Indicates wheater the content was successfully copied or not.
|
|
52
|
+
*/
|
|
53
|
+
isCoppied: boolean;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Current selected clipboard content.
|
|
57
|
+
*/
|
|
58
|
+
clipboard: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Clears the user clipboard.
|
|
62
|
+
*/
|
|
63
|
+
clearClipboard: () => void;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check to see if the browser supports the new `navigator.clipboard` API.
|
|
67
|
+
*/
|
|
68
|
+
isSupported: () => boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const useClipboard = (
|
|
72
|
+
options?: UseClipboardProps
|
|
73
|
+
): useClipboardReturnType => {
|
|
74
|
+
const { onSuccess, onError, disableClipboardAPI = false, copiedDuration } =
|
|
75
|
+
options || {};
|
|
76
|
+
const ref = useRef<any>(null);
|
|
77
|
+
const [isCoppied, setIsCoppied] = useState(false);
|
|
78
|
+
const [clipboard, setClipbaord] = useState("");
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (copiedDuration) setTimeout(() => setIsCoppied(false), copiedDuration);
|
|
82
|
+
}, [isCoppied]);
|
|
83
|
+
|
|
84
|
+
const isSupported = useCallback(() => navigator.clipboard !== undefined, []);
|
|
85
|
+
|
|
86
|
+
const handleError = useCallback((error: string) => {
|
|
87
|
+
if (onError) onError(error);
|
|
88
|
+
else throw new Error(error);
|
|
89
|
+
}, [onError]);
|
|
90
|
+
|
|
91
|
+
const handleSuccess = useCallback((text: string) => {
|
|
92
|
+
if (onSuccess) onSuccess(text);
|
|
93
|
+
setIsCoppied(true);
|
|
94
|
+
setClipbaord(text);
|
|
95
|
+
}, [onSuccess]);
|
|
96
|
+
|
|
97
|
+
const copyToClipboard = useCallback((text: string) => {
|
|
98
|
+
navigator.clipboard
|
|
99
|
+
.writeText(text)
|
|
100
|
+
.then(() => handleSuccess(text))
|
|
101
|
+
.catch((err) => {
|
|
102
|
+
handleError(err);
|
|
103
|
+
setIsCoppied(false);
|
|
104
|
+
});
|
|
105
|
+
}, [handleError, handleSuccess]);
|
|
106
|
+
|
|
107
|
+
const clearClipboard = useCallback(() => {
|
|
108
|
+
if (isSupported()) {
|
|
109
|
+
navigator.clipboard.writeText("");
|
|
110
|
+
}
|
|
111
|
+
}, [isSupported]);
|
|
112
|
+
|
|
113
|
+
const action = useCallback(
|
|
114
|
+
(operation = "copy", text?: string) => {
|
|
115
|
+
const element = ref.current as HTMLElement;
|
|
116
|
+
|
|
117
|
+
const isInput =
|
|
118
|
+
element &&
|
|
119
|
+
(element.tagName === "INPUT" || element.tagName === "TEXTAREA");
|
|
120
|
+
|
|
121
|
+
const input = ref.current as HTMLInputElement;
|
|
122
|
+
|
|
123
|
+
if (isSupported() && !disableClipboardAPI) {
|
|
124
|
+
if (text) {
|
|
125
|
+
copyToClipboard(text);
|
|
126
|
+
} else if (element) {
|
|
127
|
+
if (isInput) {
|
|
128
|
+
copyToClipboard(input.value);
|
|
129
|
+
|
|
130
|
+
if (operation === "cut") {
|
|
131
|
+
input.value = "";
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
copyToClipboard(element.innerText);
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
handleError("Both the ref & text were undefined");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
[disableClipboardAPI, copyToClipboard, handleError]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const copy = useCallback((text?: string) =>
|
|
145
|
+
action("copy", typeof text === "object" ? undefined : text), [action]);
|
|
146
|
+
|
|
147
|
+
const cut = useCallback(() => action("cut"), [action]);
|
|
148
|
+
|
|
149
|
+
return useMemo(() => ({
|
|
150
|
+
ref,
|
|
151
|
+
isCoppied,
|
|
152
|
+
clipboard,
|
|
153
|
+
clearClipboard,
|
|
154
|
+
isSupported,
|
|
155
|
+
copy,
|
|
156
|
+
cut
|
|
157
|
+
}), [isCoppied, clipboard, clearClipboard, isSupported, copy, cut]);
|
|
158
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useCallback, useEffect, useState, useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
const STORAGE_KEY_PREFIX = "rebase-collapsed-groups";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Custom hook for managing collapsed/expanded state of navigation groups
|
|
7
|
+
* with localStorage persistence. Automatically cleans up stale group entries
|
|
8
|
+
* when groups are removed from the navigation.
|
|
9
|
+
*
|
|
10
|
+
* Groups that have never been toggled by the user fall back to
|
|
11
|
+
* `defaults[groupName]` (driven by `collapsedByDefault` in config).
|
|
12
|
+
*
|
|
13
|
+
* @param groupNames - Array of group names to track
|
|
14
|
+
* @param namespace - Namespace for localStorage key (e.g., "home", "drawer") to allow independent state
|
|
15
|
+
* @param defaults - Optional map of group name → collapsed boolean from config
|
|
16
|
+
*/
|
|
17
|
+
export function useCollapsedGroups(
|
|
18
|
+
groupNames: string[],
|
|
19
|
+
namespace = "default",
|
|
20
|
+
defaults?: Record<string, boolean>
|
|
21
|
+
) {
|
|
22
|
+
const storageKey = `${STORAGE_KEY_PREFIX}-${namespace}`;
|
|
23
|
+
|
|
24
|
+
// Load collapsed groups from localStorage on mount
|
|
25
|
+
const [collapsedGroups, setCollapsedGroups] = useState<Record<string, boolean>>(() => {
|
|
26
|
+
try {
|
|
27
|
+
const stored = localStorage.getItem(storageKey);
|
|
28
|
+
return stored ? JSON.parse(stored) : {};
|
|
29
|
+
} catch {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Save to localStorage whenever collapsedGroups changes
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
try {
|
|
37
|
+
localStorage.setItem(storageKey, JSON.stringify(collapsedGroups));
|
|
38
|
+
} catch {
|
|
39
|
+
// Silently fail if localStorage is not available
|
|
40
|
+
}
|
|
41
|
+
}, [collapsedGroups, storageKey]);
|
|
42
|
+
|
|
43
|
+
// Clean up collapsed groups state when groups change - remove entries for groups that no longer exist
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
// Only clean up if we have actual groups loaded (avoid cleaning up during initial load)
|
|
46
|
+
if (groupNames.length === 0) return;
|
|
47
|
+
|
|
48
|
+
const currentGroupNames = new Set(groupNames);
|
|
49
|
+
|
|
50
|
+
setCollapsedGroups(prev => {
|
|
51
|
+
const cleaned = Object.fromEntries(
|
|
52
|
+
Object.entries(prev).filter(([groupName]) => currentGroupNames.has(groupName))
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Only update if something actually changed
|
|
56
|
+
const prevKeys = Object.keys(prev);
|
|
57
|
+
const cleanedKeys = Object.keys(cleaned);
|
|
58
|
+
|
|
59
|
+
if (prevKeys.length === cleanedKeys.length && prevKeys.every(key => cleanedKeys.includes(key))) {
|
|
60
|
+
return prev;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return cleaned;
|
|
64
|
+
});
|
|
65
|
+
}, [groupNames]);
|
|
66
|
+
|
|
67
|
+
const isGroupCollapsed = useCallback((name: string) => {
|
|
68
|
+
// If the user has explicitly toggled this group, use that value
|
|
69
|
+
if (name in collapsedGroups) {
|
|
70
|
+
return collapsedGroups[name];
|
|
71
|
+
}
|
|
72
|
+
// Otherwise fall back to the config default
|
|
73
|
+
return defaults?.[name] ?? false;
|
|
74
|
+
}, [collapsedGroups, defaults]);
|
|
75
|
+
|
|
76
|
+
const toggleGroupCollapsed = useCallback((name: string) => {
|
|
77
|
+
setCollapsedGroups(prev => {
|
|
78
|
+
// Resolve current effective state (explicit or default)
|
|
79
|
+
const currentlyCollapsed = name in prev
|
|
80
|
+
? prev[name]
|
|
81
|
+
: (defaults?.[name] ?? false);
|
|
82
|
+
return { ...prev,
|
|
83
|
+
[name]: !currentlyCollapsed };
|
|
84
|
+
});
|
|
85
|
+
}, [defaults]);
|
|
86
|
+
|
|
87
|
+
return useMemo(() => ({
|
|
88
|
+
isGroupCollapsed,
|
|
89
|
+
toggleGroupCollapsed
|
|
90
|
+
}), [isGroupCollapsed, toggleGroupCollapsed]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Build a defaults map from navigationGroupMappings for a given namespace.
|
|
95
|
+
* Returns a Record<groupName, collapsed> that can be passed to useCollapsedGroups.
|
|
96
|
+
*/
|
|
97
|
+
export function buildCollapsedDefaults(
|
|
98
|
+
mappings: Array<{ name: string; collapsedByDefault?: boolean | { drawer?: boolean; home?: boolean } }> | undefined,
|
|
99
|
+
namespace: "drawer" | "home"
|
|
100
|
+
): Record<string, boolean> {
|
|
101
|
+
if (!mappings) return {};
|
|
102
|
+
const result: Record<string, boolean> = {};
|
|
103
|
+
for (const mapping of mappings) {
|
|
104
|
+
const val = mapping.collapsedByDefault;
|
|
105
|
+
if (val === undefined) continue;
|
|
106
|
+
if (typeof val === "boolean") {
|
|
107
|
+
result[mapping.name] = val;
|
|
108
|
+
} else {
|
|
109
|
+
const ns = val[namespace];
|
|
110
|
+
if (ns !== undefined) {
|
|
111
|
+
result[mapping.name] = ns;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, { useContext, useMemo } from "react";
|
|
2
|
+
import type { OverridableComponentName } from "@rebasepro/types";
|
|
3
|
+
import { ComponentOverrideContext } from "../contexts/ComponentOverrideContext";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolves a potentially overridden component.
|
|
7
|
+
*
|
|
8
|
+
* Resolution order:
|
|
9
|
+
* 1. Collection-scoped override (highest priority)
|
|
10
|
+
* 2. Global override
|
|
11
|
+
* 3. Default component (fallback)
|
|
12
|
+
*
|
|
13
|
+
* Supports two override modes:
|
|
14
|
+
* - **Eject** (default): The override component fully replaces the default.
|
|
15
|
+
* - **Wrap** (`wrap: true`): The override component wraps the default.
|
|
16
|
+
* The default is passed as `OriginalComponent` in props.
|
|
17
|
+
*
|
|
18
|
+
* @param name - The overridable component name (e.g. `"Entity.Form"`)
|
|
19
|
+
* @param DefaultComponent - The built-in default component
|
|
20
|
+
* @returns The resolved component — either the default, a full replacement, or a wrapper
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { useComponentOverride } from "@rebasepro/app";
|
|
25
|
+
*
|
|
26
|
+
* function EntityFormWrapper(props: EntityFormProps) {
|
|
27
|
+
* const ResolvedForm = useComponentOverride("Entity.Form", DefaultEntityForm);
|
|
28
|
+
* return <ResolvedForm {...props} />;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @group Hooks
|
|
33
|
+
*/
|
|
34
|
+
export function useComponentOverride<P>(
|
|
35
|
+
name: OverridableComponentName,
|
|
36
|
+
DefaultComponent: React.ComponentType<P>
|
|
37
|
+
): React.ComponentType<P> {
|
|
38
|
+
const { globalOverrides, collectionOverrides } = useContext(ComponentOverrideContext);
|
|
39
|
+
|
|
40
|
+
return useMemo(() => {
|
|
41
|
+
// Collection-level overrides have highest priority
|
|
42
|
+
const override = collectionOverrides[name] ?? globalOverrides[name];
|
|
43
|
+
|
|
44
|
+
if (!override) return DefaultComponent;
|
|
45
|
+
|
|
46
|
+
if (override.wrap) {
|
|
47
|
+
// Wrapping mode: inject OriginalComponent as a prop
|
|
48
|
+
const UserComponent = override.Component;
|
|
49
|
+
const Wrapper = (props: P) => (
|
|
50
|
+
<UserComponent {...(props as Record<string, unknown>)} OriginalComponent={DefaultComponent} />
|
|
51
|
+
);
|
|
52
|
+
Wrapper.displayName = `Wrapped(${name})`;
|
|
53
|
+
return Wrapper as React.ComponentType<P>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Eject mode: full replacement
|
|
57
|
+
return override.Component as React.ComponentType<P>;
|
|
58
|
+
}, [collectionOverrides, globalOverrides, name, DefaultComponent]);
|
|
59
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CustomizationController } from "@rebasepro/types";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import { CustomizationControllerContext } from "../contexts/CustomizationControllerContext";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Use this hook to retrieve the customization controller.
|
|
7
|
+
* This hook includes all the customization options that can be used
|
|
8
|
+
* to customize the CMS.
|
|
9
|
+
*
|
|
10
|
+
* You will likely not need to use this hook directly.
|
|
11
|
+
*
|
|
12
|
+
* @group Hooks and utilities
|
|
13
|
+
*/
|
|
14
|
+
export const useCustomizationController = (): CustomizationController => useContext(CustomizationControllerContext);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DialogsController } from "@rebasepro/types";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import { DialogsControllerContext } from "../contexts/DialogsProvider";
|
|
4
|
+
;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Use this hook to open a dialog imperatively.
|
|
8
|
+
* Alternatively, you can use dialogs declaratively using the `Dialog` component.
|
|
9
|
+
*
|
|
10
|
+
* Consider that in order to use this hook you need to have a parent
|
|
11
|
+
* `Rebase`
|
|
12
|
+
*
|
|
13
|
+
* @group Hooks and utilities
|
|
14
|
+
*/
|
|
15
|
+
export const useDialogsController = (): DialogsController => useContext(DialogsControllerContext);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { EffectiveRoleControllerContext } from "../contexts/EffectiveRoleController";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook to retrieve the {@link EffectiveRoleController}
|
|
6
|
+
*
|
|
7
|
+
* @see EffectiveRoleController
|
|
8
|
+
* @category Hooks and utilities
|
|
9
|
+
*/
|
|
10
|
+
export const useEffectiveRoleController = () => useContext(EffectiveRoleControllerContext);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
type LayoutListener = (isLargeLayout: boolean) => void;
|
|
4
|
+
|
|
5
|
+
const breakpoints = {
|
|
6
|
+
xs: 0,
|
|
7
|
+
sm: 640,
|
|
8
|
+
md: 768,
|
|
9
|
+
lg: 1024,
|
|
10
|
+
xl: 1280,
|
|
11
|
+
"2xl": 1536,
|
|
12
|
+
"3xl": 1920
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Global state and listeners array
|
|
16
|
+
let isLargeLayoutGlobal = checkLargeLayout("lg"); // Default value
|
|
17
|
+
const listeners: LayoutListener[] = [];
|
|
18
|
+
|
|
19
|
+
// Utility to notify all listeners
|
|
20
|
+
const notifyListeners = () => {
|
|
21
|
+
listeners.forEach(listener => listener(isLargeLayoutGlobal));
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Listen to resize events once, at a global level
|
|
25
|
+
if (typeof window !== "undefined")
|
|
26
|
+
window.addEventListener("resize", () => {
|
|
27
|
+
const newIsLargeLayout = checkLargeLayout("lg");
|
|
28
|
+
if (newIsLargeLayout !== isLargeLayoutGlobal) {
|
|
29
|
+
isLargeLayoutGlobal = newIsLargeLayout;
|
|
30
|
+
notifyListeners();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export const useLargeLayout = () => {
|
|
35
|
+
const [isLargeLayout, setIsLargeLayout] = useState(isLargeLayoutGlobal);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
// Listener function to update component state
|
|
39
|
+
const listener: LayoutListener = (newIsLargeLayout) => {
|
|
40
|
+
setIsLargeLayout(newIsLargeLayout);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Register listener
|
|
44
|
+
listeners.push(listener);
|
|
45
|
+
|
|
46
|
+
// Initial state
|
|
47
|
+
setIsLargeLayout(isLargeLayoutGlobal);
|
|
48
|
+
|
|
49
|
+
// Clean up by removing the listener
|
|
50
|
+
return () => {
|
|
51
|
+
const index = listeners.indexOf(listener);
|
|
52
|
+
if (index > -1) {
|
|
53
|
+
listeners.splice(index, 1);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
return isLargeLayout;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function checkLargeLayout(breakpoint: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" = "lg"): boolean {
|
|
62
|
+
if (typeof window === "undefined")
|
|
63
|
+
return false;
|
|
64
|
+
return window.matchMedia(`(min-width: ${breakpoints[breakpoint] + 1}px)`).matches;
|
|
65
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ModeControllerContext } from "../contexts/ModeController";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Use this controller to change color mode
|
|
6
|
+
* @group Hooks and utilities
|
|
7
|
+
*/
|
|
8
|
+
export interface ModeController {
|
|
9
|
+
mode: "light" | "dark";
|
|
10
|
+
setMode: (mode: "light" | "dark" | "system") => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Hook to retrieve the current mode ("light" | "dark"), and `setMode`
|
|
15
|
+
* or `toggle` functions to change it.
|
|
16
|
+
*
|
|
17
|
+
* Consider that in order to use this hook you need to have a parent
|
|
18
|
+
* `Rebase`
|
|
19
|
+
*
|
|
20
|
+
* @see ModeController
|
|
21
|
+
* @group Hooks and utilities
|
|
22
|
+
*/
|
|
23
|
+
export const useModeController = () => useContext(ModeControllerContext);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
import { useAuthController } from "./useAuthController";
|
|
3
|
+
import { Entity } from "@rebasepro/types";
|
|
4
|
+
import { canCreateEntity, canEditEntity, canDeleteEntity, canReadCollection } from "@rebasepro/common";
|
|
5
|
+
import { useCallback, useMemo } from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Hook to evaluate roles and permissions for the current user.
|
|
9
|
+
* It abstracts away the need to pass `authController` to permission evaluation functions.
|
|
10
|
+
*/
|
|
11
|
+
export function usePermissions() {
|
|
12
|
+
const authController = useAuthController();
|
|
13
|
+
|
|
14
|
+
const canCreate = useCallback(
|
|
15
|
+
(collection: CollectionConfig<any>, path: string) =>
|
|
16
|
+
canCreateEntity(collection, authController, path, null),
|
|
17
|
+
[authController]
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const canEdit = useCallback(
|
|
21
|
+
(collection: CollectionConfig<any>, path: string, entity: Entity<any> | null) =>
|
|
22
|
+
canEditEntity(collection, authController, path, entity),
|
|
23
|
+
[authController]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const canDelete = useCallback(
|
|
27
|
+
(collection: CollectionConfig<any>, path: string, entity: Entity<any> | null) =>
|
|
28
|
+
canDeleteEntity(collection, authController, path, entity),
|
|
29
|
+
[authController]
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const canRead = useCallback(
|
|
33
|
+
(collection: CollectionConfig<any>) =>
|
|
34
|
+
canReadCollection(collection, authController),
|
|
35
|
+
[authController]
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return useMemo(() => ({
|
|
39
|
+
canCreate,
|
|
40
|
+
canEdit,
|
|
41
|
+
canDelete,
|
|
42
|
+
canRead
|
|
43
|
+
}), [canCreate, canEdit, canDelete, canRead]);
|
|
44
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { RebaseClientInstanceContext } from "../contexts/RebaseClientInstanceContext";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook to retrieve the full RebaseClient instance from context.
|
|
6
|
+
* Returns `undefined` if no client was provided to `<Rebase>`.
|
|
7
|
+
*/
|
|
8
|
+
export function useRebaseClient<T = any>(): T | undefined {
|
|
9
|
+
return useContext(RebaseClientInstanceContext) as T | undefined;
|
|
10
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { AuthController, RebaseContext, User } from "@rebasepro/types";
|
|
2
|
+
import { wrapAsSdkData } from "@rebasepro/common";
|
|
3
|
+
import { useAuthController } from "./useAuthController";
|
|
4
|
+
import { useRebaseClient } from "./useRebaseClient";
|
|
5
|
+
import { useData } from "./data/useData";
|
|
6
|
+
import { useStorageSource } from "./useStorageSource";
|
|
7
|
+
import { useSnackbarController } from "./useSnackbarController";
|
|
8
|
+
import { useUserConfigurationPersistence } from "./useUserConfigurationPersistence";
|
|
9
|
+
import { useDialogsController } from "./useDialogsController";
|
|
10
|
+
import { useCustomizationController } from "./useCustomizationController";
|
|
11
|
+
import { useAnalyticsController } from "./useAnalyticsController";
|
|
12
|
+
import { useEffectiveRoleController } from "./useEffectiveRoleController";
|
|
13
|
+
import React, { useEffect, useContext } from "react";
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// DatabaseAdmin is provided by <Rebase> via DatabaseAdminContext.
|
|
17
|
+
import { DatabaseAdminContext } from "../contexts/DatabaseAdminContext";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hook to retrieve the {@link RebaseContext}.
|
|
21
|
+
*
|
|
22
|
+
* Consider that in order to use this hook you need to have a parent
|
|
23
|
+
* `Rebase` component.
|
|
24
|
+
*
|
|
25
|
+
* @see RebaseContext
|
|
26
|
+
* @group Hooks and utilities
|
|
27
|
+
*/
|
|
28
|
+
export const useRebaseContext = <USER extends User = User, AuthControllerType extends AuthController<USER> = AuthController<USER>>(): RebaseContext<USER, AuthControllerType> => {
|
|
29
|
+
|
|
30
|
+
const client = useRebaseClient<any>();
|
|
31
|
+
|
|
32
|
+
const authController = useAuthController<USER, AuthControllerType>();
|
|
33
|
+
// `context.data` is the flat SDK view — identical in shape to the backend
|
|
34
|
+
// `context.data` and the frontend SDK client, so callbacks behave the same
|
|
35
|
+
// everywhere. The admin CMS reads Entities via `useData()` directly.
|
|
36
|
+
const entityData = useData();
|
|
37
|
+
const data = React.useMemo(() => wrapAsSdkData(entityData), [entityData]);
|
|
38
|
+
const storageSource = useStorageSource();
|
|
39
|
+
const snackbarController = useSnackbarController();
|
|
40
|
+
const userConfigPersistence = useUserConfigurationPersistence();
|
|
41
|
+
const dialogsController = useDialogsController();
|
|
42
|
+
const customizationController = useCustomizationController();
|
|
43
|
+
const analyticsController = useAnalyticsController();
|
|
44
|
+
const effectiveRoleController = useEffectiveRoleController();
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// Will get `databaseAdmin` from context
|
|
48
|
+
const databaseAdmin = useContext(DatabaseAdminContext);
|
|
49
|
+
|
|
50
|
+
const rebaseContextRef = React.useRef<RebaseContext<USER, AuthControllerType>>({
|
|
51
|
+
authController,
|
|
52
|
+
data,
|
|
53
|
+
storageSource,
|
|
54
|
+
snackbarController,
|
|
55
|
+
userConfigPersistence,
|
|
56
|
+
dialogsController,
|
|
57
|
+
customizationController,
|
|
58
|
+
analyticsController,
|
|
59
|
+
effectiveRoleController,
|
|
60
|
+
databaseAdmin,
|
|
61
|
+
client: client! // Client should be provided
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
rebaseContextRef.current = {
|
|
66
|
+
authController,
|
|
67
|
+
data,
|
|
68
|
+
storageSource,
|
|
69
|
+
snackbarController,
|
|
70
|
+
userConfigPersistence,
|
|
71
|
+
dialogsController,
|
|
72
|
+
customizationController,
|
|
73
|
+
analyticsController,
|
|
74
|
+
effectiveRoleController,
|
|
75
|
+
databaseAdmin,
|
|
76
|
+
client: client!
|
|
77
|
+
};
|
|
78
|
+
}, [authController, data, storageSource, snackbarController, userConfigPersistence,
|
|
79
|
+
dialogsController, customizationController, analyticsController,
|
|
80
|
+
effectiveRoleController, databaseAdmin, client]);
|
|
81
|
+
|
|
82
|
+
return rebaseContextRef.current;
|
|
83
|
+
}
|