@rebasepro/client-firebase 0.7.0 → 0.9.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/dist/components/RebaseFirebaseAppProps.d.ts +2 -2
- package/dist/hooks/useBuildUserManagement.d.ts +1 -0
- package/dist/hooks/useFirestoreDriver.d.ts +3 -3
- package/dist/index.es.js +328 -313
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +326 -311
- package/dist/index.umd.js.map +1 -1
- package/dist/types/text_search.d.ts +3 -3
- package/dist/utils/collections_firestore.d.ts +3 -3
- package/package.json +19 -19
- package/src/components/RebaseFirebaseApp.tsx +10 -5
- package/src/components/RebaseFirebaseAppProps.tsx +2 -2
- package/src/hooks/useBuildUserManagement.tsx +27 -28
- package/src/hooks/useFirebaseRealTimeDBDelegate.ts +47 -52
- package/src/hooks/useFirebaseStorageSource.ts +2 -2
- package/src/hooks/useFirestoreDriver.ts +380 -355
- package/src/types/text_search.ts +3 -3
- package/src/utils/collections_firestore.ts +5 -5
- package/src/utils/database.ts +2 -2
- package/src/utils/local_text_search_controller.ts +6 -6
- package/src/utils/pinecone.ts +2 -2
- package/src/utils/rebase_search_controller.ts +3 -3
- package/src/utils/text_search_controller.ts +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { User as FirebaseUser } from "@firebase/auth";
|
|
2
2
|
import { FirebaseApp } from "@firebase/app";
|
|
3
|
-
import {
|
|
3
|
+
import { CollectionConfig } from "@rebasepro/types";
|
|
4
4
|
export type FirestoreTextSearchControllerBuilder = (props: {
|
|
5
5
|
firebaseApp: FirebaseApp;
|
|
6
6
|
}) => FirestoreTextSearchController;
|
|
@@ -23,7 +23,7 @@ export type FirestoreTextSearchController = {
|
|
|
23
23
|
init: (props: {
|
|
24
24
|
path: string;
|
|
25
25
|
databaseId?: string;
|
|
26
|
-
collection?:
|
|
26
|
+
collection?: CollectionConfig;
|
|
27
27
|
}) => Promise<boolean>;
|
|
28
28
|
/**
|
|
29
29
|
* Do the search and return a list of ids.
|
|
@@ -34,6 +34,6 @@ export type FirestoreTextSearchController = {
|
|
|
34
34
|
path: string;
|
|
35
35
|
currentUser?: FirebaseUser;
|
|
36
36
|
databaseId?: string;
|
|
37
|
-
collection?:
|
|
37
|
+
collection?: CollectionConfig;
|
|
38
38
|
}) => (Promise<readonly string[] | undefined>);
|
|
39
39
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DocumentSnapshot } from "@firebase/firestore";
|
|
2
|
-
import {
|
|
2
|
+
import { CollectionConfig } from "@rebasepro/types";
|
|
3
3
|
export declare function buildCollectionId(idOrPath: string, parentCollectionSlugs?: string[], parentEntityIds?: string[]): string;
|
|
4
|
-
export declare const docsToCollectionTree: (docs: DocumentSnapshot[]) =>
|
|
5
|
-
export declare const docToCollection: (doc: DocumentSnapshot) =>
|
|
4
|
+
export declare const docsToCollectionTree: (docs: DocumentSnapshot[]) => CollectionConfig[];
|
|
5
|
+
export declare const docToCollection: (doc: DocumentSnapshot) => CollectionConfig;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/client-firebase",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -10,16 +10,15 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"source": "src/index.ts",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@firebase/auth": "^1.13.2",
|
|
14
|
-
"@rebasepro/admin": "workspace:*",
|
|
15
|
-
"@rebasepro/common": "workspace:*",
|
|
16
|
-
"@rebasepro/core": "workspace:*",
|
|
17
|
-
"@rebasepro/types": "workspace:*",
|
|
18
|
-
"@rebasepro/ui": "workspace:*",
|
|
19
|
-
"@rebasepro/utils": "workspace:*",
|
|
20
13
|
"fast-equals": "6.0.0",
|
|
21
14
|
"fuse.js": "^7.4.2",
|
|
22
|
-
"react-router-dom": "^7.17.0"
|
|
15
|
+
"react-router-dom": "^7.17.0",
|
|
16
|
+
"@rebasepro/core": "0.9.0",
|
|
17
|
+
"@rebasepro/types": "0.9.0",
|
|
18
|
+
"@rebasepro/common": "0.9.0",
|
|
19
|
+
"@rebasepro/utils": "0.9.0",
|
|
20
|
+
"@rebasepro/ui": "0.9.0",
|
|
21
|
+
"@rebasepro/admin": "0.9.0"
|
|
23
22
|
},
|
|
24
23
|
"peerDependencies": {
|
|
25
24
|
"firebase": "^10.12.2 || ^11.0.0 || ^12.0.0",
|
|
@@ -42,10 +41,11 @@
|
|
|
42
41
|
"./package.json": "./package.json"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
|
-
"@firebase/app": "^0.
|
|
46
|
-
"@firebase/app-check": "^0.
|
|
44
|
+
"@firebase/app": "^0.15.0",
|
|
45
|
+
"@firebase/app-check": "^0.12.0",
|
|
46
|
+
"@firebase/auth": "^1.13.3",
|
|
47
47
|
"@firebase/database": "^1.1.3",
|
|
48
|
-
"@firebase/firestore": "^4.
|
|
48
|
+
"@firebase/firestore": "^4.16.0",
|
|
49
49
|
"@firebase/functions": "^0.13.5",
|
|
50
50
|
"@firebase/storage": "^0.14.3",
|
|
51
51
|
"@types/jest": "^30.0.0",
|
|
@@ -54,16 +54,11 @@
|
|
|
54
54
|
"@types/react-dom": "^19.2.3",
|
|
55
55
|
"@vitejs/plugin-react": "^6.0.2",
|
|
56
56
|
"babel-plugin-react-compiler": "19.0.0-beta-ebf51a3-20250411",
|
|
57
|
-
"firebase": "^12.
|
|
57
|
+
"firebase": "^12.15.0",
|
|
58
58
|
"typescript": "^6.0.3",
|
|
59
59
|
"typesense": "^3.0.6",
|
|
60
60
|
"vite": "^8.0.16"
|
|
61
61
|
},
|
|
62
|
-
"scripts": {
|
|
63
|
-
"dev": "vite",
|
|
64
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
65
|
-
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
66
|
-
},
|
|
67
62
|
"files": [
|
|
68
63
|
"dist",
|
|
69
64
|
"src"
|
|
@@ -73,5 +68,10 @@
|
|
|
73
68
|
"type": "git",
|
|
74
69
|
"url": "https://github.com/rebasepro/rebase.git",
|
|
75
70
|
"directory": "packages/client-firebase"
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"dev": "vite",
|
|
74
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
75
|
+
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
76
76
|
}
|
|
77
|
-
}
|
|
77
|
+
}
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
CollectionRegistryContext,
|
|
24
24
|
UrlContext,
|
|
25
25
|
NavigationStateContext,
|
|
26
|
-
|
|
26
|
+
SidePanelProvider,
|
|
27
27
|
RebaseRoute
|
|
28
28
|
} from "@rebasepro/admin";
|
|
29
|
-
import { Entity, PropertyConfig, RebaseContext } from "@rebasepro/types";
|
|
29
|
+
import { DEFAULT_DATA_SOURCE_KEY, Entity, PropertyConfig, RebaseContext } from "@rebasepro/types";
|
|
30
30
|
import { CenteredView, CircularProgressCenter } from "@rebasepro/ui";
|
|
31
31
|
import { buildRebaseData } from "@rebasepro/common";
|
|
32
32
|
import { Route, Outlet, Navigate } from "react-router-dom";
|
|
@@ -220,7 +220,12 @@ export function RebaseFirebaseApp({
|
|
|
220
220
|
authController={authController}
|
|
221
221
|
userConfigPersistence={userConfigPersistence}
|
|
222
222
|
dateTimeFormat={dateTimeFormat}
|
|
223
|
-
|
|
223
|
+
dataSources={[{
|
|
224
|
+
key: DEFAULT_DATA_SOURCE_KEY,
|
|
225
|
+
engine: "firestore",
|
|
226
|
+
transport: "direct",
|
|
227
|
+
driver: firestoreDelegate
|
|
228
|
+
}]}
|
|
224
229
|
storageSource={storageSource}
|
|
225
230
|
entityLinkBuilder={({ entity }: { entity: Entity<any> }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
|
|
226
231
|
locale={locale}
|
|
@@ -253,7 +258,7 @@ export function RebaseFirebaseApp({
|
|
|
253
258
|
const fallbackRoute = firstCollectionEntry ? <Navigate to={urlController.buildUrlCollectionPath(firstCollectionEntry.id)} replace /> : <CenteredView>No home page or collections provided.</CenteredView>;
|
|
254
259
|
|
|
255
260
|
component = (
|
|
256
|
-
<
|
|
261
|
+
<SidePanelProvider>
|
|
257
262
|
<RebaseRoutes>
|
|
258
263
|
<Route element={
|
|
259
264
|
<Scaffold
|
|
@@ -269,7 +274,7 @@ export function RebaseFirebaseApp({
|
|
|
269
274
|
<Route path="/c/*" element={<RebaseRoute/>}/>
|
|
270
275
|
</Route>
|
|
271
276
|
</RebaseRoutes>
|
|
272
|
-
</
|
|
277
|
+
</SidePanelProvider>
|
|
273
278
|
);
|
|
274
279
|
}
|
|
275
280
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { AnalyticsEvent, AppView, AppViewsBuilder,
|
|
3
|
+
import { AnalyticsEvent, AppView, AppViewsBuilder, CollectionConfig, CollectionConfigsBuilder, RebasePlugin, Locale, PropertyConfig } from "@rebasepro/types";
|
|
4
4
|
import { FirebaseAccessGate } from "../hooks/useFirebaseAccessGate";
|
|
5
5
|
|
|
6
6
|
import { FirebaseApp } from "@firebase/app";
|
|
@@ -42,7 +42,7 @@ export type RebaseFirebaseAppProps = {
|
|
|
42
42
|
* Each of the navigation entries in this field
|
|
43
43
|
* generates an entry in the main menu.
|
|
44
44
|
*/
|
|
45
|
-
collections?:
|
|
45
|
+
collections?: CollectionConfig[] | CollectionConfigsBuilder;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Custom additional views created by the developer, added to the main
|
|
@@ -107,11 +107,11 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
107
107
|
setRolesLoading(true);
|
|
108
108
|
return dataSourceDelegate.listenCollection?.({
|
|
109
109
|
path: rolesPath,
|
|
110
|
-
onUpdate(
|
|
110
|
+
onUpdate(rows: Record<string, unknown>[]): void {
|
|
111
111
|
setRolesError(undefined);
|
|
112
|
-
console.debug("Updating roles",
|
|
112
|
+
console.debug("Updating roles", rows);
|
|
113
113
|
try {
|
|
114
|
-
const newRoles =
|
|
114
|
+
const newRoles = rowsToRoles(rows);
|
|
115
115
|
if (!equal(newRoles, roles)) {
|
|
116
116
|
setRoles(newRoles);
|
|
117
117
|
}
|
|
@@ -144,11 +144,11 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
144
144
|
setUsersLoading(true);
|
|
145
145
|
return dataSourceDelegate.listenCollection?.({
|
|
146
146
|
path: usersPath,
|
|
147
|
-
onUpdate(
|
|
148
|
-
console.debug("Updating users",
|
|
147
|
+
onUpdate(rows: Record<string, unknown>[]): void {
|
|
148
|
+
console.debug("Updating users", rows);
|
|
149
149
|
setUsersError(undefined);
|
|
150
150
|
try {
|
|
151
|
-
const newUsers =
|
|
151
|
+
const newUsers = rowsToUsers(rows) as UserWithRoleIds<USER>[];
|
|
152
152
|
// if (!equal(newUsers, usersWithRoleIds))
|
|
153
153
|
setUsersWithRoleIds(newUsers);
|
|
154
154
|
} catch (e) {
|
|
@@ -186,12 +186,12 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
186
186
|
};
|
|
187
187
|
// delete the previous user entry if it exists and the uid has changed
|
|
188
188
|
if (userExists && userExists.uid !== user.uid) {
|
|
189
|
-
const
|
|
189
|
+
const row = {
|
|
190
190
|
values: {},
|
|
191
191
|
path: usersPath,
|
|
192
192
|
id: userExists.uid
|
|
193
193
|
}
|
|
194
|
-
await dataSourceDelegate.
|
|
194
|
+
await dataSourceDelegate.delete({ row })
|
|
195
195
|
.then(() => {
|
|
196
196
|
console.debug("Deleted previous user", userExists);
|
|
197
197
|
})
|
|
@@ -201,10 +201,10 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
201
201
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
return dataSourceDelegate.
|
|
204
|
+
return dataSourceDelegate.save({
|
|
205
205
|
status: "existing",
|
|
206
206
|
path: usersPath,
|
|
207
|
-
|
|
207
|
+
id: email,
|
|
208
208
|
values: removeUndefined(data) as Record<string, unknown>
|
|
209
209
|
}).then(() => user);
|
|
210
210
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
|
@@ -217,10 +217,10 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
217
217
|
id,
|
|
218
218
|
...roleData
|
|
219
219
|
} = role;
|
|
220
|
-
return dataSourceDelegate.
|
|
220
|
+
return dataSourceDelegate.save({
|
|
221
221
|
status: "existing",
|
|
222
222
|
path: rolesPath,
|
|
223
|
-
|
|
223
|
+
id: id,
|
|
224
224
|
values: removeUndefined(roleData) as Record<string, unknown>
|
|
225
225
|
}).then(() => {
|
|
226
226
|
return;
|
|
@@ -232,12 +232,12 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
232
232
|
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
|
233
233
|
console.debug("Deleting", user);
|
|
234
234
|
const { uid } = user;
|
|
235
|
-
const
|
|
235
|
+
const row = {
|
|
236
236
|
path: usersPath,
|
|
237
237
|
id: uid,
|
|
238
238
|
values: {}
|
|
239
239
|
};
|
|
240
|
-
await dataSourceDelegate.
|
|
240
|
+
await dataSourceDelegate.delete({ row })
|
|
241
241
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
|
242
242
|
|
|
243
243
|
const deleteRole = useCallback(async (role: Role): Promise<void> => {
|
|
@@ -245,12 +245,12 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
245
245
|
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
|
246
246
|
console.debug("Deleting", role);
|
|
247
247
|
const { id } = role;
|
|
248
|
-
const
|
|
248
|
+
const row = {
|
|
249
249
|
path: rolesPath,
|
|
250
250
|
id: id,
|
|
251
251
|
values: {}
|
|
252
252
|
};
|
|
253
|
-
await dataSourceDelegate.
|
|
253
|
+
await dataSourceDelegate.delete({ row })
|
|
254
254
|
}, [rolesPath, dataSourceDelegate?.initialised]);
|
|
255
255
|
|
|
256
256
|
|
|
@@ -345,23 +345,22 @@ export function useBuildUserManagement<CONTROLLER extends AuthController<User> =
|
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
const
|
|
349
|
-
return
|
|
350
|
-
const data =
|
|
351
|
-
const record = data as Record<string, unknown>;
|
|
348
|
+
const rowsToUsers = (rows: Record<string, unknown>[]): (UserWithRoleIds)[] => {
|
|
349
|
+
return rows.map((row) => {
|
|
350
|
+
const { id, ...data } = row;
|
|
352
351
|
const newVar = {
|
|
353
352
|
...data,
|
|
354
|
-
uid:
|
|
355
|
-
created_on:
|
|
356
|
-
updated_on:
|
|
353
|
+
uid: id,
|
|
354
|
+
created_on: data.created_on as Date | undefined,
|
|
355
|
+
updated_on: data.updated_on as Date | undefined
|
|
357
356
|
};
|
|
358
357
|
return newVar as unknown as UserWithRoleIds;
|
|
359
358
|
});
|
|
360
359
|
}
|
|
361
360
|
|
|
362
|
-
const
|
|
363
|
-
return
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
} as Role));
|
|
361
|
+
const rowsToRoles = (rows: Record<string, unknown>[]): Role[] => {
|
|
362
|
+
return rows.map((row) => ({
|
|
363
|
+
...row,
|
|
364
|
+
id: row.id
|
|
365
|
+
} as unknown as Role));
|
|
367
366
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
startAt
|
|
16
16
|
} from "@firebase/database";
|
|
17
17
|
import { useCallback } from "react";
|
|
18
|
-
import { DataDriver,
|
|
18
|
+
import { DataDriver, DeleteProps, FetchCollectionProps, FetchOneProps, FilterValues, ListenCollectionProps, ListenOneProps, SaveProps } from "@rebasepro/types";
|
|
19
19
|
|
|
20
20
|
export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: FirebaseApp }): DataDriver {
|
|
21
21
|
|
|
@@ -27,7 +27,7 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
27
27
|
orderBy,
|
|
28
28
|
order,
|
|
29
29
|
searchString
|
|
30
|
-
}: FetchCollectionProps<M>): Promise<
|
|
30
|
+
}: FetchCollectionProps<M>): Promise<Record<string, unknown>[]> => {
|
|
31
31
|
if (!firebaseApp) {
|
|
32
32
|
throw new Error("Firebase app not provided");
|
|
33
33
|
}
|
|
@@ -43,12 +43,11 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
43
43
|
dbQuery = query(dbQuery, limitToFirst(limit));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
return Object.entries(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
values: delegateToCMSModel(values) as M
|
|
46
|
+
const entity = await get(dbQuery);
|
|
47
|
+
if (entity.exists()) {
|
|
48
|
+
return Object.entries(entity.val()).map(([id, values]) => ({
|
|
49
|
+
...(delegateToCMSModel(values) as Record<string, unknown>),
|
|
50
|
+
id
|
|
52
51
|
}));
|
|
53
52
|
}
|
|
54
53
|
return [];
|
|
@@ -65,12 +64,11 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
65
64
|
const database = getDatabase(firebaseApp);
|
|
66
65
|
|
|
67
66
|
const dbRef = ref(database, path);
|
|
68
|
-
const unsubscribe = onValue(dbRef, (
|
|
69
|
-
if (
|
|
70
|
-
const result:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
values: delegateToCMSModel(values) as M
|
|
67
|
+
const unsubscribe = onValue(dbRef, (entity) => {
|
|
68
|
+
if (entity.exists()) {
|
|
69
|
+
const result: Record<string, unknown>[] = Object.entries(entity.val()).map(([id, values]) => ({
|
|
70
|
+
...(delegateToCMSModel(values) as Record<string, unknown>),
|
|
71
|
+
id
|
|
74
72
|
}));
|
|
75
73
|
onUpdate(result);
|
|
76
74
|
} else {
|
|
@@ -81,44 +79,42 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
81
79
|
return () => unsubscribe();
|
|
82
80
|
}, [firebaseApp]);
|
|
83
81
|
|
|
84
|
-
const
|
|
82
|
+
const fetchOne = useCallback(async <M extends Record<string, any>>({
|
|
85
83
|
path,
|
|
86
|
-
|
|
87
|
-
}:
|
|
84
|
+
id
|
|
85
|
+
}: FetchOneProps<M>): Promise<Record<string, unknown> | undefined> => {
|
|
88
86
|
if (!firebaseApp) {
|
|
89
87
|
throw new Error("Firebase app not provided");
|
|
90
88
|
}
|
|
91
89
|
const database = getDatabase(firebaseApp);
|
|
92
90
|
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
91
|
+
const entity = await get(ref(database, `${path}/${id}`));
|
|
92
|
+
if (entity.exists()) {
|
|
95
93
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
values: delegateToCMSModel(snapshot.val()) as M
|
|
94
|
+
...(delegateToCMSModel(entity.val()) as Record<string, unknown>),
|
|
95
|
+
id: id
|
|
99
96
|
};
|
|
100
97
|
}
|
|
101
98
|
return undefined;
|
|
102
99
|
}, [firebaseApp]);
|
|
103
100
|
|
|
104
|
-
const
|
|
101
|
+
const listenOne = useCallback(<M extends Record<string, any>>({
|
|
105
102
|
path,
|
|
106
|
-
|
|
103
|
+
id,
|
|
107
104
|
onUpdate,
|
|
108
105
|
onError
|
|
109
|
-
}:
|
|
106
|
+
}: ListenOneProps<M>): () => void => {
|
|
110
107
|
if (!firebaseApp) {
|
|
111
108
|
throw new Error("Firebase app not provided");
|
|
112
109
|
}
|
|
113
110
|
const database = getDatabase(firebaseApp);
|
|
114
111
|
|
|
115
|
-
const dbRef = ref(database, `${path}/${
|
|
116
|
-
const unsubscribe = onValue(dbRef, (
|
|
117
|
-
if (
|
|
112
|
+
const dbRef = ref(database, `${path}/${id}`);
|
|
113
|
+
const unsubscribe = onValue(dbRef, (entity) => {
|
|
114
|
+
if (entity.exists()) {
|
|
118
115
|
onUpdate({
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
values: delegateToCMSModel(snapshot.val()) as M
|
|
116
|
+
...(delegateToCMSModel(entity.val()) as Record<string, unknown>),
|
|
117
|
+
id: id
|
|
122
118
|
});
|
|
123
119
|
} else {
|
|
124
120
|
onError?.(new Error("Entity does not exist"));
|
|
@@ -128,18 +124,18 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
128
124
|
return () => unsubscribe();
|
|
129
125
|
}, [firebaseApp]);
|
|
130
126
|
|
|
131
|
-
const
|
|
127
|
+
const save = useCallback(async <M extends Record<string, any>>({
|
|
132
128
|
path,
|
|
133
|
-
|
|
129
|
+
id,
|
|
134
130
|
values
|
|
135
|
-
}:
|
|
131
|
+
}: SaveProps<M>): Promise<Record<string, unknown>> => {
|
|
136
132
|
if (!firebaseApp) {
|
|
137
133
|
throw new Error("Firebase app not provided");
|
|
138
134
|
}
|
|
139
135
|
const database = getDatabase(firebaseApp);
|
|
140
136
|
|
|
141
|
-
// If
|
|
142
|
-
const finalId =
|
|
137
|
+
// If id is not provided, a new entity will be created
|
|
138
|
+
const finalId = id ?? push(ref(database, path)).key;
|
|
143
139
|
if (!finalId) {
|
|
144
140
|
throw new Error("Could not generate a new id");
|
|
145
141
|
}
|
|
@@ -149,25 +145,24 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
149
145
|
await set(ref(database, `${path}/${finalId}`), transformedValues);
|
|
150
146
|
|
|
151
147
|
return {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
values: values as M
|
|
148
|
+
...values,
|
|
149
|
+
id: finalId
|
|
155
150
|
};
|
|
156
151
|
}, [firebaseApp]);
|
|
157
152
|
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
}:
|
|
153
|
+
const deleteOne = useCallback(async <M extends Record<string, any>>({
|
|
154
|
+
row
|
|
155
|
+
}: DeleteProps<M>): Promise<void> => {
|
|
161
156
|
if (!firebaseApp) {
|
|
162
157
|
throw new Error("Firebase app not provided");
|
|
163
158
|
}
|
|
164
159
|
const database = getDatabase(firebaseApp);
|
|
165
160
|
|
|
166
|
-
await remove(ref(database, `${
|
|
161
|
+
await remove(ref(database, `${row.path}/${row.id}`));
|
|
167
162
|
}, [firebaseApp]);
|
|
168
163
|
|
|
169
164
|
// Implementing additional methods required by DataDriver
|
|
170
|
-
const checkUniqueField = useCallback(async (slug: string, name: string, value: unknown,
|
|
165
|
+
const checkUniqueField = useCallback(async (slug: string, name: string, value: unknown, id?: string | number): Promise<boolean> => {
|
|
171
166
|
if (!firebaseApp) {
|
|
172
167
|
throw new Error("Firebase app not provided");
|
|
173
168
|
}
|
|
@@ -175,15 +170,15 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
175
170
|
|
|
176
171
|
// Simplified example; the Realtime Database does not support querying with "not equal" conditions
|
|
177
172
|
const dbRef = query(ref(database, slug), orderByChild(name), startAt(value as string | number | boolean | null), limitToFirst(1));
|
|
178
|
-
const
|
|
173
|
+
const entity = await get(dbRef);
|
|
179
174
|
|
|
180
|
-
if (!
|
|
175
|
+
if (!entity.exists()) {
|
|
181
176
|
return true;
|
|
182
177
|
}
|
|
183
178
|
|
|
184
179
|
// Check if the found entity is the same as the one being checked
|
|
185
|
-
const [key, entityValue] = Object.entries(
|
|
186
|
-
if (entityValue && typeof entityValue === "object" && (entityValue as Record<string, unknown>)[name] === value && key ===
|
|
180
|
+
const [key, entityValue] = Object.entries(entity.val())[0];
|
|
181
|
+
if (entityValue && typeof entityValue === "object" && (entityValue as Record<string, unknown>)[name] === value && key === id) {
|
|
187
182
|
return true;
|
|
188
183
|
}
|
|
189
184
|
|
|
@@ -206,10 +201,10 @@ export function useFirebaseRTDBDelegate({ firebaseApp }: { firebaseApp?: Firebas
|
|
|
206
201
|
key: "firebase_rtdb",
|
|
207
202
|
fetchCollection,
|
|
208
203
|
listenCollection,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
204
|
+
fetchOne,
|
|
205
|
+
listenOne,
|
|
206
|
+
save,
|
|
207
|
+
delete: deleteOne,
|
|
213
208
|
checkUniqueField,
|
|
214
209
|
isFilterCombinationValid,
|
|
215
210
|
currentTime: () => new Date()
|
|
@@ -69,8 +69,8 @@ export function useFirebaseStorageSource({
|
|
|
69
69
|
setProgressTimeout();
|
|
70
70
|
|
|
71
71
|
uploadTask.on("state_changed",
|
|
72
|
-
(
|
|
73
|
-
const progress = (
|
|
72
|
+
(entity) => {
|
|
73
|
+
const progress = (entity.bytesTransferred / entity.totalBytes) * 100;
|
|
74
74
|
|
|
75
75
|
if (progress > lastProgress) {
|
|
76
76
|
lastProgress = progress;
|