@rebasepro/core 0.2.3 → 0.2.5
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/dist/components/LoginView/LoginView.d.ts +25 -1
- package/dist/components/common/types.d.ts +10 -7
- package/dist/components/common/useDebouncedData.d.ts +1 -1
- package/dist/core/RebaseProps.d.ts +13 -2
- package/dist/core/RebaseRouter.d.ts +1 -1
- package/dist/hooks/data/useCollectionFetch.d.ts +12 -1
- package/dist/hooks/index.d.ts +0 -1
- package/dist/index.es.js +565 -454
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +565 -454
- package/dist/index.umd.js.map +1 -1
- package/dist/util/entity_cache.d.ts +0 -5
- package/dist/util/index.d.ts +0 -2
- package/dist/util/useStorageUploadController.d.ts +2 -2
- package/package.json +6 -6
- package/src/components/BootstrapAdminBanner.tsx +12 -3
- package/src/components/LoginView/LoginView.tsx +177 -10
- package/src/components/UserSettingsView.tsx +95 -2
- package/src/components/common/types.tsx +7 -7
- package/src/components/common/useDebouncedData.ts +2 -2
- package/src/core/Rebase.tsx +3 -2
- package/src/core/RebaseProps.tsx +15 -2
- package/src/core/RebaseRouter.tsx +1 -1
- package/src/hooks/data/useCollectionFetch.tsx +27 -4
- package/src/hooks/data/useUserSelector.tsx +1 -1
- package/src/hooks/index.tsx +0 -1
- package/src/hooks/useResolvedComponent.tsx +4 -3
- package/src/locales/en.ts +13 -0
- package/src/locales/es.ts +11 -1
- package/src/util/entity_cache.ts +1 -27
- package/src/util/icon_list.ts +2 -2
- package/src/util/index.ts +2 -2
- package/src/util/previews.ts +9 -1
- package/src/util/useStorageUploadController.tsx +4 -4
- package/dist/hooks/useValidateAuthenticator.d.ts +0 -21
- package/dist/util/icon_synonyms.d.ts +0 -1
- package/dist/util/useTraceUpdate.d.ts +0 -2
- package/src/hooks/useValidateAuthenticator.tsx +0 -116
- package/src/util/icon_synonyms.ts +0 -1
- package/src/util/useTraceUpdate.tsx +0 -24
package/src/core/RebaseProps.tsx
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Locale, User, AuthController, AnalyticsEvent, DataDriver, StorageSource, UserConfigurationPersistence, CollectionRegistryController, DatabaseAdmin, UrlController, NavigationStateController, RebaseData, RebaseClient, RebaseContext, UserManagementDelegate, EntityLinkBuilder, RebasePlugin, SlotContribution, PropertyConfig, EntityCustomView, EntityAction } from "@rebasepro/types";
|
|
2
|
+
import { Locale, User, AuthController, AnalyticsEvent, DataDriver, StorageSource, UserConfigurationPersistence, CollectionRegistryController, DatabaseAdmin, UrlController, NavigationStateController, RebaseData, RebaseClient, RebaseContext, UserManagementDelegate, EntityLinkBuilder, RebasePlugin, SlotContribution, PropertyConfig, EntityCustomView, EntityAction, RebaseTranslations } from "@rebasepro/types";
|
|
3
|
+
|
|
4
|
+
/** DeepPartial helper — allows partial overrides at any nesting level */
|
|
5
|
+
type DeepPartial<T> = T extends object
|
|
6
|
+
? { [K in keyof T]?: DeepPartial<T[K]> }
|
|
7
|
+
: T;
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* Controller to simulate different roles when dev mode is active.
|
|
@@ -138,7 +143,7 @@ export type RebaseProps<USER extends User> = {
|
|
|
138
143
|
/**
|
|
139
144
|
* Entity Views
|
|
140
145
|
*/
|
|
141
|
-
entityViews?: EntityCustomView
|
|
146
|
+
entityViews?: EntityCustomView[];
|
|
142
147
|
|
|
143
148
|
/**
|
|
144
149
|
* Entity Actions
|
|
@@ -161,4 +166,12 @@ export type RebaseProps<USER extends User> = {
|
|
|
161
166
|
*/
|
|
162
167
|
effectiveRoleController?: EffectiveRoleController;
|
|
163
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Override or extend any Rebase UI string, keyed by locale.
|
|
171
|
+
*/
|
|
172
|
+
translations?: {
|
|
173
|
+
[locale: string]: DeepPartial<RebaseTranslations>;
|
|
174
|
+
};
|
|
175
|
+
|
|
164
176
|
};
|
|
177
|
+
|
|
@@ -22,6 +22,16 @@ export interface CollectionFetchProps<M extends Record<string, any>> {
|
|
|
22
22
|
*/
|
|
23
23
|
itemCount?: number;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Number of items to skip
|
|
27
|
+
*/
|
|
28
|
+
offset?: number;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Page number (1-indexed), alternative to offset
|
|
32
|
+
*/
|
|
33
|
+
page?: number;
|
|
34
|
+
|
|
25
35
|
/**
|
|
26
36
|
* Filter the fetched data by the property
|
|
27
37
|
*/
|
|
@@ -46,6 +56,7 @@ export interface CollectionFetchResult<M extends Record<string, any>> {
|
|
|
46
56
|
dataLoading: boolean;
|
|
47
57
|
noMoreToLoad: boolean;
|
|
48
58
|
dataLoadingError?: Error;
|
|
59
|
+
totalCount?: number;
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
/**
|
|
@@ -55,6 +66,8 @@ export interface CollectionFetchResult<M extends Record<string, any>> {
|
|
|
55
66
|
* @param filterValues
|
|
56
67
|
* @param sortBy
|
|
57
68
|
* @param itemCount
|
|
69
|
+
* @param offset
|
|
70
|
+
* @param page
|
|
58
71
|
* @param searchString
|
|
59
72
|
* @group Hooks and utilities
|
|
60
73
|
*/
|
|
@@ -65,6 +78,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
65
78
|
filterValues,
|
|
66
79
|
sortBy,
|
|
67
80
|
itemCount,
|
|
81
|
+
offset,
|
|
82
|
+
page,
|
|
68
83
|
searchString
|
|
69
84
|
}: CollectionFetchProps<M>): CollectionFetchResult<M> {
|
|
70
85
|
const dataClient = useData();
|
|
@@ -99,12 +114,13 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
99
114
|
const [dataLoading, setDataLoading] = useState<boolean>(false);
|
|
100
115
|
const [dataLoadingError, setDataLoadingError] = useState<Error | undefined>();
|
|
101
116
|
const [noMoreToLoad, setNoMoreToLoad] = useState<boolean>(false);
|
|
117
|
+
const [totalCount, setTotalCount] = useState<number | undefined>();
|
|
102
118
|
|
|
103
119
|
useEffect(() => {
|
|
104
120
|
|
|
105
121
|
setDataLoading(true);
|
|
106
122
|
|
|
107
|
-
const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean } }) => {
|
|
123
|
+
const onEntitiesUpdate = async (res: { data: Entity<M>[], meta: { hasMore: boolean; total?: number } }) => {
|
|
108
124
|
const entities = res.data;
|
|
109
125
|
setDataLoading(false);
|
|
110
126
|
setDataLoadingError(undefined);
|
|
@@ -112,6 +128,7 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
112
128
|
...e
|
|
113
129
|
})));
|
|
114
130
|
setNoMoreToLoad(!res.meta.hasMore);
|
|
131
|
+
setTotalCount(res.meta.total);
|
|
115
132
|
};
|
|
116
133
|
|
|
117
134
|
const onError = (error: Error) => {
|
|
@@ -119,6 +136,7 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
119
136
|
setDataLoading(false);
|
|
120
137
|
setData([]);
|
|
121
138
|
setDataLoadingError(error);
|
|
139
|
+
setTotalCount(undefined);
|
|
122
140
|
};
|
|
123
141
|
|
|
124
142
|
const accessor = dataClient.collection(path);
|
|
@@ -133,6 +151,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
133
151
|
return accessor.listen({
|
|
134
152
|
where: whereParams,
|
|
135
153
|
limit: itemCount,
|
|
154
|
+
offset,
|
|
155
|
+
page,
|
|
136
156
|
orderBy: orderByParams,
|
|
137
157
|
searchString,
|
|
138
158
|
include: includeParams
|
|
@@ -141,6 +161,8 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
141
161
|
accessor.find({
|
|
142
162
|
where: whereParams,
|
|
143
163
|
limit: itemCount,
|
|
164
|
+
offset,
|
|
165
|
+
page,
|
|
144
166
|
orderBy: orderByParams,
|
|
145
167
|
searchString,
|
|
146
168
|
include: includeParams
|
|
@@ -150,13 +172,14 @@ export function useCollectionFetch<M extends Record<string, any>, USER extends U
|
|
|
150
172
|
return () => {
|
|
151
173
|
};
|
|
152
174
|
}
|
|
153
|
-
}, [path, itemCount, currentSort, sortByProperty, filterValues, searchString, dataClient, collection]);
|
|
175
|
+
}, [path, itemCount, offset, page, currentSort, sortByProperty, filterValues, searchString, dataClient, collection]);
|
|
154
176
|
|
|
155
177
|
return useMemo(() => ({
|
|
156
178
|
data,
|
|
157
179
|
dataLoading,
|
|
158
180
|
dataLoadingError,
|
|
159
|
-
noMoreToLoad
|
|
160
|
-
|
|
181
|
+
noMoreToLoad,
|
|
182
|
+
totalCount
|
|
183
|
+
}), [data, dataLoading, dataLoadingError, noMoreToLoad, totalCount]);
|
|
161
184
|
|
|
162
185
|
}
|
|
@@ -142,7 +142,7 @@ export function useUserSelector(
|
|
|
142
142
|
}, []);
|
|
143
143
|
|
|
144
144
|
const getUser = useCallback((uid: string): User | null => {
|
|
145
|
-
return userManagement?.getUser(uid) ?? null;
|
|
145
|
+
return userManagement?.getUser?.(uid) ?? null;
|
|
146
146
|
}, [userManagement]);
|
|
147
147
|
|
|
148
148
|
return useMemo(() => ({
|
package/src/hooks/index.tsx
CHANGED
|
@@ -33,7 +33,6 @@ export * from "./useCustomizationController";
|
|
|
33
33
|
export * from "./useBuildLocalConfigurationPersistence";
|
|
34
34
|
export * from "./useBuildModeController";
|
|
35
35
|
|
|
36
|
-
export * from "./useValidateAuthenticator";
|
|
37
36
|
export * from "./useRebaseRegistry";
|
|
38
37
|
export * from "./useBackendStorageSource";
|
|
39
38
|
export * from "./usePermissions";
|
|
@@ -13,7 +13,8 @@ import { isLazyComponentRef } from "@rebasepro/types";
|
|
|
13
13
|
* to the `React.lazy()` wrapper it produced. Strings are keyed by a separate
|
|
14
14
|
* plain Map since they can't be WeakMap keys.
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
const lazyCache = new WeakMap<object | Function, React.ComponentType<any>>();
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Resolves a `ComponentRef` into a renderable `React.ComponentType`.
|
|
@@ -62,7 +63,7 @@ export function useResolvedComponent<P = unknown>(
|
|
|
62
63
|
* same loader always returns the same lazy component identity.
|
|
63
64
|
*/
|
|
64
65
|
function getOrCreateLazy<P>(
|
|
65
|
-
key: object |
|
|
66
|
+
key: object | Function,
|
|
66
67
|
loader: () => Promise<{ default: React.ComponentType<P> }>
|
|
67
68
|
): React.ComponentType<P> {
|
|
68
69
|
const cached = lazyCache.get(key);
|
|
@@ -108,7 +109,7 @@ export function resolveComponentRef<P = unknown>(
|
|
|
108
109
|
|
|
109
110
|
// 3. Function — either a React component or a lazy import loader.
|
|
110
111
|
if (typeof ref === "function") {
|
|
111
|
-
const fn = ref as
|
|
112
|
+
const fn = ref as Function;
|
|
112
113
|
|
|
113
114
|
// Class components (React.Component / PureComponent) have this flag
|
|
114
115
|
if (fn.prototype?.isReactComponent) {
|
package/src/locales/en.ts
CHANGED
|
@@ -164,6 +164,9 @@ export const en: RebaseTranslations = {
|
|
|
164
164
|
navigation_drawer: "Navigation drawer",
|
|
165
165
|
collapse: "Collapse",
|
|
166
166
|
expand: "Expand",
|
|
167
|
+
change_language: "Change language",
|
|
168
|
+
toggle_theme: "Toggle theme",
|
|
169
|
+
user_menu: "User menu",
|
|
167
170
|
|
|
168
171
|
// ─── Error states ─────────────────────────────────────────────
|
|
169
172
|
error: "Error",
|
|
@@ -451,7 +454,17 @@ export const en: RebaseTranslations = {
|
|
|
451
454
|
select_references: "Select references",
|
|
452
455
|
account_settings: "Account Settings",
|
|
453
456
|
profile: "Profile",
|
|
457
|
+
security: "Security",
|
|
454
458
|
sessions: "Sessions",
|
|
459
|
+
change_password: "Change Password",
|
|
460
|
+
current_password: "Current Password",
|
|
461
|
+
new_password: "New Password",
|
|
462
|
+
confirm_password: "Confirm New Password",
|
|
463
|
+
password_changed: "Password changed successfully. You will be logged out.",
|
|
464
|
+
passwords_dont_match: "Passwords don't match",
|
|
465
|
+
password_too_short: "Password must be at least 8 characters",
|
|
466
|
+
password_change_not_available: "Password change is not available for accounts using external sign-in providers.",
|
|
467
|
+
changing_password: "Changing...",
|
|
455
468
|
display_name: "Display Name",
|
|
456
469
|
photo_url: "Photo URL",
|
|
457
470
|
save_profile: "Save Profile",
|
package/src/locales/es.ts
CHANGED
|
@@ -652,7 +652,17 @@ no_filter: "No filter",
|
|
|
652
652
|
select_references: "Select references",
|
|
653
653
|
account_settings: "Account Settings",
|
|
654
654
|
profile: "Profile",
|
|
655
|
-
sessions: "
|
|
655
|
+
sessions: "Sesiones",
|
|
656
|
+
security: "Seguridad",
|
|
657
|
+
change_password: "Cambiar Contraseña",
|
|
658
|
+
current_password: "Contraseña Actual",
|
|
659
|
+
new_password: "Nueva Contraseña",
|
|
660
|
+
confirm_password: "Confirmar Nueva Contraseña",
|
|
661
|
+
password_changed: "Contraseña cambiada con éxito. Se cerrará tu sesión.",
|
|
662
|
+
passwords_dont_match: "Las contraseñas no coinciden",
|
|
663
|
+
password_too_short: "La contraseña debe tener al menos 8 caracteres",
|
|
664
|
+
password_change_not_available: "El cambio de contraseña no está disponible para cuentas que usan proveedores de inicio de sesión externos.",
|
|
665
|
+
changing_password: "Cambiando...",
|
|
656
666
|
display_name: "Display Name",
|
|
657
667
|
photo_url: "Photo URL",
|
|
658
668
|
save_profile: "Save Profile",
|
package/src/util/entity_cache.ts
CHANGED
|
@@ -154,9 +154,7 @@ export function getEntityFromMemoryCache(path: string): object | undefined {
|
|
|
154
154
|
return entityCache.get(path);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
return entityCache.has(path);
|
|
159
|
-
}
|
|
157
|
+
|
|
160
158
|
|
|
161
159
|
/**
|
|
162
160
|
* Retrieves an entity from the in-memory cache or `sessionStorage`.
|
|
@@ -212,31 +210,7 @@ export function removeEntityFromCache(path: string): void {
|
|
|
212
210
|
}
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
/**
|
|
216
|
-
* Clears the entire in-memory cache and removes all related entities from `sessionStorage`.
|
|
217
|
-
*/
|
|
218
|
-
export function clearEntityCache(): void {
|
|
219
|
-
// Clear the in-memory cache
|
|
220
|
-
entityCache.clear();
|
|
221
213
|
|
|
222
|
-
// Remove all entities with the specified prefix from sessionStorage
|
|
223
|
-
if (isSessionStorageAvailable) {
|
|
224
|
-
try {
|
|
225
|
-
const keysToRemove: string[] = [];
|
|
226
|
-
for (let i = 0; i < sessionStorage.length; i++) {
|
|
227
|
-
const fullKey = sessionStorage.key(i);
|
|
228
|
-
if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
|
|
229
|
-
keysToRemove.push(fullKey);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Remove the keys after collecting them to avoid issues while iterating
|
|
234
|
-
keysToRemove.forEach((key) => sessionStorage.removeItem(key));
|
|
235
|
-
} catch (error) {
|
|
236
|
-
console.error("Failed to clear entity cache from sessionStorage:", error);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
214
|
|
|
241
215
|
export function flattenKeys(obj: Record<string, unknown> | unknown[], prefix = "", result: string[] = []): string[] {
|
|
242
216
|
|
package/src/util/icon_list.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
const iconSynonyms: Record<string, string> = {};
|
|
2
2
|
import { iconKeys } from "@rebasepro/ui";
|
|
3
3
|
import Fuse from "fuse.js";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
const map = iconKeys
|
|
7
7
|
.map((importName) => {
|
|
8
|
-
const iconSynonym = importName in iconSynonyms ?
|
|
8
|
+
const iconSynonym = importName in iconSynonyms ? iconSynonyms[importName] : "";
|
|
9
9
|
return {
|
|
10
10
|
key: importName,
|
|
11
11
|
synonyms: iconSynonym
|
package/src/util/index.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
|
|
2
2
|
export * from "./icon_list";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
export * from "./icons";
|
|
5
5
|
export * from "./createFormexStub";
|
|
6
6
|
export * from "./entity_cache";
|
|
7
7
|
|
|
8
8
|
export * from "./useStorageUploadController";
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
export * from "./previews";
|
|
11
11
|
export * from "./enums";
|
|
12
12
|
export * from "./constants";
|
package/src/util/previews.ts
CHANGED
|
@@ -22,6 +22,11 @@ function isRelationProperty(property: Property) {
|
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function isHiddenProperty(property: Property | undefined): boolean {
|
|
26
|
+
if (!property) return false;
|
|
27
|
+
return Boolean(property.ui?.hideFromCollection);
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
export function getEntityPreviewKeys(
|
|
26
31
|
authController: AuthController,
|
|
27
32
|
targetCollection: EntityCollection<any>,
|
|
@@ -45,7 +50,7 @@ export function getEntityPreviewKeys(
|
|
|
45
50
|
})
|
|
46
51
|
.filter(key => {
|
|
47
52
|
const property = targetCollection.properties[key];
|
|
48
|
-
return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property);
|
|
53
|
+
return property && !isPropertyBuilder(property) && !isReferenceProperty(property) && !isRelationProperty(property) && !isHiddenProperty(property);
|
|
49
54
|
}).slice(0, limit);
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -62,6 +67,9 @@ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collect
|
|
|
62
67
|
const property = collection.properties[key];
|
|
63
68
|
if (property && !isPropertyBuilder(property)) {
|
|
64
69
|
const prop = property as Property;
|
|
70
|
+
if (isHiddenProperty(prop)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
65
73
|
if (prop.type === "string" && !prop.ui?.multiline && !prop.ui?.markdown && !prop.storage && !prop.isId) {
|
|
66
74
|
if (!firstStringCandidate) {
|
|
67
75
|
firstStringCandidate = key;
|
|
@@ -21,7 +21,7 @@ export interface StorageFieldItem {
|
|
|
21
21
|
storagePathOrDownloadUrl?: string;
|
|
22
22
|
file?: File;
|
|
23
23
|
fileName?: string;
|
|
24
|
-
metadata?:
|
|
24
|
+
metadata?: Record<string, unknown>,
|
|
25
25
|
size: StorageFieldSize
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -63,7 +63,7 @@ export function useStorageUploadController<M extends Record<string, unknown>>({
|
|
|
63
63
|
|
|
64
64
|
const processFile = storage?.processFile;
|
|
65
65
|
|
|
66
|
-
const metadata: Record<string,
|
|
66
|
+
const metadata: Record<string, unknown> | undefined = storage?.metadata;
|
|
67
67
|
const size = multipleFilesSupported ? "medium" : "large";
|
|
68
68
|
|
|
69
69
|
const imageResize = storage?.imageResize;
|
|
@@ -116,7 +116,7 @@ export function useStorageUploadController<M extends Record<string, unknown>>({
|
|
|
116
116
|
|
|
117
117
|
const onFileUploadComplete = useCallback(async (uploadedPath: string,
|
|
118
118
|
entry: StorageFieldItem,
|
|
119
|
-
metadata?:
|
|
119
|
+
metadata?: Record<string, unknown>,
|
|
120
120
|
uploadedUrl?: string) => {
|
|
121
121
|
|
|
122
122
|
console.debug("onFileUploadComplete", uploadedPath, entry);
|
|
@@ -242,7 +242,7 @@ export function useStorageUploadController<M extends Record<string, unknown>>({
|
|
|
242
242
|
|
|
243
243
|
function getInternalInitialValue(multipleFilesSupported: boolean,
|
|
244
244
|
value: string | string[] | null,
|
|
245
|
-
metadata: Record<string,
|
|
245
|
+
metadata: Record<string, unknown> | undefined,
|
|
246
246
|
size: StorageFieldSize): StorageFieldItem[] {
|
|
247
247
|
let strings: string[] = [];
|
|
248
248
|
if (multipleFilesSupported) {
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { AuthController, Authenticator, RebaseData, StorageSource, User } from "@rebasepro/types";
|
|
2
|
-
/**
|
|
3
|
-
* This hook is used internally for validating an authenticator.
|
|
4
|
-
*
|
|
5
|
-
* @param authController
|
|
6
|
-
* @param authentication
|
|
7
|
-
* @param storageSource
|
|
8
|
-
* @param data
|
|
9
|
-
*/
|
|
10
|
-
export declare function useValidateAuthenticator<USER extends User = any>({ disabled, authController, authenticator, storageSource, data }: {
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
authController: AuthController<USER>;
|
|
13
|
-
authenticator?: boolean | Authenticator<USER>;
|
|
14
|
-
data: RebaseData;
|
|
15
|
-
storageSource: StorageSource;
|
|
16
|
-
}): {
|
|
17
|
-
canAccessMainView: boolean;
|
|
18
|
-
authLoading: boolean;
|
|
19
|
-
notAllowedError: any;
|
|
20
|
-
authVerified: boolean;
|
|
21
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const iconSynonyms: Record<string, string>;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { useCallback, useEffect, useRef, useState, useMemo } from "react";
|
|
3
|
-
import { deepEqual as equal } from "fast-equals";
|
|
4
|
-
|
|
5
|
-
import { AuthController, Authenticator, RebaseData, StorageSource, User } from "@rebasepro/types";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* This hook is used internally for validating an authenticator.
|
|
9
|
-
*
|
|
10
|
-
* @param authController
|
|
11
|
-
* @param authentication
|
|
12
|
-
* @param storageSource
|
|
13
|
-
* @param data
|
|
14
|
-
*/
|
|
15
|
-
export function useValidateAuthenticator<USER extends User = any>
|
|
16
|
-
({
|
|
17
|
-
disabled,
|
|
18
|
-
authController,
|
|
19
|
-
authenticator,
|
|
20
|
-
storageSource,
|
|
21
|
-
data
|
|
22
|
-
}:
|
|
23
|
-
{
|
|
24
|
-
disabled?: boolean,
|
|
25
|
-
authController: AuthController<USER>,
|
|
26
|
-
authenticator?: boolean | Authenticator<USER>,
|
|
27
|
-
data: RebaseData;
|
|
28
|
-
storageSource: StorageSource;
|
|
29
|
-
}): {
|
|
30
|
-
canAccessMainView: boolean,
|
|
31
|
-
authLoading: boolean,
|
|
32
|
-
notAllowedError: any,
|
|
33
|
-
authVerified: boolean,
|
|
34
|
-
} {
|
|
35
|
-
|
|
36
|
-
const authenticationEnabled = Boolean(authenticator);
|
|
37
|
-
|
|
38
|
-
const [authLoading, setAuthLoading] = useState<boolean>(authenticationEnabled);
|
|
39
|
-
const [notAllowedError, setNotAllowedError] = useState<any>(false);
|
|
40
|
-
const [authVerified, setAuthVerified] = useState<boolean>(!authenticationEnabled || Boolean(authController.loginSkipped));
|
|
41
|
-
|
|
42
|
-
const canAccessMainView = (authVerified) &&
|
|
43
|
-
(!authenticationEnabled || Boolean(authController.user) || Boolean(authController.loginSkipped)) &&
|
|
44
|
-
!notAllowedError;
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (authController.loginSkipped)
|
|
48
|
-
setAuthVerified(true);
|
|
49
|
-
}, [authController.loginSkipped]);
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* We use this ref to check the authentication only if the user has
|
|
53
|
-
* changed.
|
|
54
|
-
*/
|
|
55
|
-
const checkedUserRef = useRef<User | undefined>(undefined);
|
|
56
|
-
|
|
57
|
-
const checkAuthentication = useCallback(async () => {
|
|
58
|
-
|
|
59
|
-
if (disabled) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (authController.initialLoading) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!authController.user && !authController.loginSkipped) {
|
|
68
|
-
checkedUserRef.current = undefined;
|
|
69
|
-
setAuthLoading(false);
|
|
70
|
-
setAuthVerified(false);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const delegateUser = authController.user;
|
|
75
|
-
|
|
76
|
-
if (authenticator instanceof Function && delegateUser && !equal(checkedUserRef.current?.uid, delegateUser.uid)) {
|
|
77
|
-
setAuthLoading(true);
|
|
78
|
-
try {
|
|
79
|
-
const allowed = await authenticator({
|
|
80
|
-
user: delegateUser,
|
|
81
|
-
authController,
|
|
82
|
-
data,
|
|
83
|
-
storageSource
|
|
84
|
-
});
|
|
85
|
-
if (!allowed) {
|
|
86
|
-
authController.signOut();
|
|
87
|
-
setNotAllowedError(true);
|
|
88
|
-
}
|
|
89
|
-
} catch (e) {
|
|
90
|
-
setNotAllowedError(e);
|
|
91
|
-
authController.signOut();
|
|
92
|
-
}
|
|
93
|
-
setAuthLoading(false);
|
|
94
|
-
setAuthVerified(true);
|
|
95
|
-
checkedUserRef.current = delegateUser;
|
|
96
|
-
} else {
|
|
97
|
-
setAuthLoading(false);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!authController.initialLoading && !delegateUser) {
|
|
101
|
-
setAuthVerified(true);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
}, [disabled, authController, authenticator, data, storageSource]);
|
|
105
|
-
|
|
106
|
-
useEffect(() => {
|
|
107
|
-
checkAuthentication();
|
|
108
|
-
}, [checkAuthentication]);
|
|
109
|
-
|
|
110
|
-
return useMemo(() => ({
|
|
111
|
-
canAccessMainView,
|
|
112
|
-
authLoading: authenticationEnabled && authLoading,
|
|
113
|
-
notAllowedError,
|
|
114
|
-
authVerified
|
|
115
|
-
}), [canAccessMainView, authenticationEnabled, authLoading, notAllowedError, authVerified]);
|
|
116
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const iconSynonyms: Record<string, string> = {};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from "react";
|
|
2
|
-
|
|
3
|
-
export function printChanged(props: any, prev: any, path: string | undefined = "", depth: number | undefined = 0, maxDepth: number | undefined = 10) {
|
|
4
|
-
if (depth > maxDepth) {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
if (props && prev && typeof props === "object" && typeof prev === "object") {
|
|
8
|
-
Object.keys(props).forEach((key) => {
|
|
9
|
-
printChanged(props[key], prev[key], path + "." + key, depth + 1, maxDepth);
|
|
10
|
-
});
|
|
11
|
-
} else if (props !== prev) {
|
|
12
|
-
console.log("Changed props:", path);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function useTraceUpdate(props: any, maxDepth = 3) {
|
|
18
|
-
const prev = useRef(props);
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
console.log("Changed props:");
|
|
21
|
-
printChanged(props, prev.current, "", 0, maxDepth);
|
|
22
|
-
prev.current = props;
|
|
23
|
-
});
|
|
24
|
-
}
|