@rebasepro/client-firebase 0.8.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 +141 -137
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +139 -135
- 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 +7 -7
- 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 +113 -95
- 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,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { AnalyticsEvent, AppView, AppViewsBuilder,
|
|
2
|
+
import { AnalyticsEvent, AppView, AppViewsBuilder, CollectionConfig, CollectionConfigsBuilder, RebasePlugin, Locale, PropertyConfig } from "@rebasepro/types";
|
|
3
3
|
import { FirebaseAccessGate } from "../hooks/useFirebaseAccessGate";
|
|
4
4
|
import { FirebaseApp } from "@firebase/app";
|
|
5
5
|
import { FirebaseLoginViewProps } from "./FirebaseLoginView";
|
|
@@ -29,7 +29,7 @@ export type RebaseFirebaseAppProps = {
|
|
|
29
29
|
* Each of the navigation entries in this field
|
|
30
30
|
* generates an entry in the main menu.
|
|
31
31
|
*/
|
|
32
|
-
collections?:
|
|
32
|
+
collections?: CollectionConfig[] | CollectionConfigsBuilder;
|
|
33
33
|
/**
|
|
34
34
|
* Custom additional views created by the developer, added to the main
|
|
35
35
|
* navigation
|
|
@@ -70,6 +70,7 @@ export declare function useBuildUserManagement<CONTROLLER extends AuthController
|
|
|
70
70
|
photoURL: string | null;
|
|
71
71
|
providerId: string;
|
|
72
72
|
isAnonymous: boolean;
|
|
73
|
+
emailVerified?: boolean;
|
|
73
74
|
createdAt?: Date | string | null;
|
|
74
75
|
metadata?: Record<string, any>;
|
|
75
76
|
getIdToken?: (forceRefresh?: boolean) => Promise<string>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataDriver,
|
|
1
|
+
import { DataDriver, CollectionConfig, FilterCombination } from "@rebasepro/types";
|
|
2
2
|
import { Firestore } from "@firebase/firestore";
|
|
3
3
|
import { FirebaseApp } from "@firebase/app";
|
|
4
4
|
import { FirestoreTextSearchControllerBuilder } from "../types/text_search";
|
|
@@ -26,13 +26,13 @@ export interface FirestoreDataDriverProps {
|
|
|
26
26
|
}
|
|
27
27
|
export type FirestoreIndexesBuilder = (params: {
|
|
28
28
|
path: string;
|
|
29
|
-
collection:
|
|
29
|
+
collection: CollectionConfig<any>;
|
|
30
30
|
}) => FilterCombination<string>[] | undefined;
|
|
31
31
|
export type FirestoreDataDriver = DataDriver & {
|
|
32
32
|
initTextSearch: (props: {
|
|
33
33
|
path: string;
|
|
34
34
|
databaseId?: string;
|
|
35
|
-
collection?:
|
|
35
|
+
collection?: CollectionConfig;
|
|
36
36
|
}) => Promise<boolean>;
|
|
37
37
|
};
|
|
38
38
|
/**
|
package/dist/index.es.js
CHANGED
|
@@ -4,7 +4,7 @@ import { FacebookAuthProvider, GithubAuthProvider, GoogleAuthProvider, OAuthProv
|
|
|
4
4
|
import { deleteObject, getDownloadURL, getMetadata, getStorage, list, ref, uploadBytesResumable } from "@firebase/storage";
|
|
5
5
|
import { deleteApp, getApps, initializeApp } from "@firebase/app";
|
|
6
6
|
import { getToken, initializeAppCheck } from "@firebase/app-check";
|
|
7
|
-
import { EntityReference, GeoPoint } from "@rebasepro/types";
|
|
7
|
+
import { DEFAULT_DATA_SOURCE_KEY, EntityReference, GeoPoint } from "@rebasepro/types";
|
|
8
8
|
import { DocumentReference, GeoPoint as GeoPoint$1, Timestamp, VectorValue, collection, deleteDoc, deleteField, doc, getCountFromServer, getDoc, getDocs, getFirestore, limit, onSnapshot, orderBy, query, serverTimestamp, setDoc, startAfter, vector, where } from "@firebase/firestore";
|
|
9
9
|
import { COLLECTION_PATH_SEPARATOR, buildRebaseData, sortProperties, stripCollectionPath } from "@rebasepro/common";
|
|
10
10
|
import Fuse from "fuse.js";
|
|
@@ -12,7 +12,7 @@ import { getFunctions, httpsCallable } from "@firebase/functions";
|
|
|
12
12
|
import { get, getDatabase, limitToFirst, onValue, orderByChild, orderByKey, push, query as query$1, ref as ref$1, remove, set, startAt } from "@firebase/database";
|
|
13
13
|
import { removeUndefined } from "@rebasepro/utils";
|
|
14
14
|
import { AdminModeControllerProvider, ErrorView, ModeControllerProvider, Rebase, RebaseLogo, RebaseRoutes, SnackbarProvider, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildLocalConfigurationPersistence, useBuildModeController, useModeController, useSnackbarController } from "@rebasepro/core";
|
|
15
|
-
import { AppBar, CollectionRegistryContext, Drawer, NavigationStateContext, RebaseRoute, Scaffold, SideDialogs,
|
|
15
|
+
import { AppBar, CollectionRegistryContext, Drawer, NavigationStateContext, RebaseRoute, Scaffold, SideDialogs, SidePanelProvider, UrlContext, useBuildCollectionRegistryController, useBuildNavigationStateController, useBuildUrlController } from "@rebasepro/admin";
|
|
16
16
|
import { ArrowLeftIcon, Button, CenteredView, CircularProgress, CircularProgressCenter, IconButton, LoadingButton, MailIcon, PhoneIcon, TextField, Typography, UserIcon, cls, iconSize } from "@rebasepro/ui";
|
|
17
17
|
import { Navigate, Outlet, Route } from "react-router-dom";
|
|
18
18
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -262,8 +262,8 @@ function useFirebaseStorageSource({ firebaseApp, bucketUrl }) {
|
|
|
262
262
|
}, 5e3);
|
|
263
263
|
};
|
|
264
264
|
setProgressTimeout();
|
|
265
|
-
uploadTask.on("state_changed", (
|
|
266
|
-
const progress =
|
|
265
|
+
uploadTask.on("state_changed", (entity) => {
|
|
266
|
+
const progress = entity.bytesTransferred / entity.totalBytes * 100;
|
|
267
267
|
if (progress > lastProgress) {
|
|
268
268
|
lastProgress = progress;
|
|
269
269
|
setProgressTimeout();
|
|
@@ -586,8 +586,8 @@ function normalizePropertiesEnumValues(properties, sortObjectFormat = false) {
|
|
|
586
586
|
//#region src/utils/database.ts
|
|
587
587
|
async function getFirestoreDataInPath(firebaseApp, path, parentPaths, limit$2) {
|
|
588
588
|
const firestore = getFirestore(firebaseApp);
|
|
589
|
-
if (!parentPaths || parentPaths.length === 0) return getDocs(query(collection(firestore, path), limit(limit$2))).then((
|
|
590
|
-
return
|
|
589
|
+
if (!parentPaths || parentPaths.length === 0) return getDocs(query(collection(firestore, path), limit(limit$2))).then((queryEntity) => {
|
|
590
|
+
return queryEntity.docs.map((doc) => doc.data());
|
|
591
591
|
});
|
|
592
592
|
else {
|
|
593
593
|
let currentDocs = void 0;
|
|
@@ -699,9 +699,9 @@ var localSearchControllerBuilder = ({ firebaseApp }) => {
|
|
|
699
699
|
if (collectionProp) {
|
|
700
700
|
console.debug("Init local search controller", path);
|
|
701
701
|
listeners[path] = onSnapshot(query(collection(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path)), {
|
|
702
|
-
next: (
|
|
703
|
-
if (
|
|
704
|
-
const docs =
|
|
702
|
+
next: (entity) => {
|
|
703
|
+
if (entity.metadata.fromCache && entity.metadata.hasPendingWrites) return;
|
|
704
|
+
const docs = entity.docs.map((doc) => ({
|
|
705
705
|
id: doc.id,
|
|
706
706
|
...doc.data()
|
|
707
707
|
}));
|
|
@@ -968,6 +968,15 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
968
968
|
const queryParams = [];
|
|
969
969
|
if (filter) Object.entries(filter).filter(([_, entry]) => !!entry).forEach(([key, filterParameter]) => {
|
|
970
970
|
const [op, value] = filterParameter;
|
|
971
|
+
if (op === "is-null") {
|
|
972
|
+
queryParams.push(where(key, "==", null));
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
if (op === "is-not-null") {
|
|
976
|
+
queryParams.push(where(key, "!=", null));
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
if (op === "like" || op === "ilike" || op === "not-like" || op === "not-ilike") throw new Error(`Firestore does not support the "${op}" operator (SQL pattern matching). Use a full-text search index or the collection's searchString instead.`);
|
|
971
980
|
queryParams.push(where(key, op, cmsToFirestoreModel(value, firestore)));
|
|
972
981
|
});
|
|
973
982
|
if (orderBy$1 && order) queryParams.push(orderBy(orderBy$1, order));
|
|
@@ -975,19 +984,19 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
975
984
|
if (limit$1) queryParams.push(limit(limit$1));
|
|
976
985
|
return query(collectionReference, ...queryParams);
|
|
977
986
|
}, [firebaseApp]);
|
|
978
|
-
const getAndBuildEntity = useCallback((path,
|
|
987
|
+
const getAndBuildEntity = useCallback((path, id, databaseId) => {
|
|
979
988
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
980
|
-
return getDoc(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path, String(
|
|
981
|
-
if (!
|
|
982
|
-
return
|
|
989
|
+
return getDoc(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path, String(id))).then((docEntity) => {
|
|
990
|
+
if (!docEntity.exists()) return;
|
|
991
|
+
return createRowFromDocument(docEntity);
|
|
983
992
|
});
|
|
984
993
|
}, [firebaseApp]);
|
|
985
|
-
const
|
|
994
|
+
const listenOne = useCallback(({ path, id, collection, onUpdate, onError }) => {
|
|
986
995
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
987
996
|
const databaseId = collection?.databaseId;
|
|
988
|
-
return onSnapshot(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path, String(
|
|
989
|
-
next: (
|
|
990
|
-
onUpdate(
|
|
997
|
+
return onSnapshot(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path, String(id)), {
|
|
998
|
+
next: (docEntity) => {
|
|
999
|
+
onUpdate(docEntity.exists() ? createRowFromDocument(docEntity) : null);
|
|
991
1000
|
},
|
|
992
1001
|
error: onError
|
|
993
1002
|
});
|
|
@@ -1010,22 +1019,23 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1010
1019
|
subscriptions = [];
|
|
1011
1020
|
onUpdate([]);
|
|
1012
1021
|
}
|
|
1013
|
-
const
|
|
1022
|
+
const rows = [];
|
|
1014
1023
|
const addedEntitiesSet = /* @__PURE__ */ new Set();
|
|
1015
|
-
subscriptions = (ids ?? []).map((
|
|
1016
|
-
return
|
|
1024
|
+
subscriptions = (ids ?? []).map((id) => {
|
|
1025
|
+
return listenOne({
|
|
1017
1026
|
path,
|
|
1018
|
-
|
|
1019
|
-
onUpdate: (
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1027
|
+
id,
|
|
1028
|
+
onUpdate: (row) => {
|
|
1029
|
+
const incomingId = row?.id;
|
|
1030
|
+
if (row && incomingId !== void 0) {
|
|
1031
|
+
if (!addedEntitiesSet.has(incomingId)) {
|
|
1032
|
+
addedEntitiesSet.add(incomingId);
|
|
1033
|
+
rows.push(row);
|
|
1034
|
+
onUpdate(rows);
|
|
1025
1035
|
}
|
|
1026
|
-
} else
|
|
1027
|
-
addedEntitiesSet.delete(
|
|
1028
|
-
onUpdate([...
|
|
1036
|
+
} else {
|
|
1037
|
+
addedEntitiesSet.delete(id);
|
|
1038
|
+
onUpdate([...rows.filter((r) => r.id !== id)]);
|
|
1029
1039
|
}
|
|
1030
1040
|
}
|
|
1031
1041
|
});
|
|
@@ -1034,7 +1044,7 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1034
1044
|
return () => {
|
|
1035
1045
|
subscriptions.forEach((p) => p());
|
|
1036
1046
|
};
|
|
1037
|
-
}, [firebaseApp,
|
|
1047
|
+
}, [firebaseApp, listenOne]);
|
|
1038
1048
|
const initTextSearch = useCallback(async (props) => {
|
|
1039
1049
|
console.debug("Init text search controller", searchControllerRef.current, props.path);
|
|
1040
1050
|
if (!searchControllerRef.current) {
|
|
@@ -1059,7 +1069,7 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1059
1069
|
* @param orderBy
|
|
1060
1070
|
* @param order
|
|
1061
1071
|
* @return Function to cancel subscription
|
|
1062
|
-
* @see
|
|
1072
|
+
* @see useCollection if you need this functionality implemented as a hook
|
|
1063
1073
|
* @group Firestore
|
|
1064
1074
|
*/
|
|
1065
1075
|
const fetchCollection = useCallback(async ({ path, filter, limit, startAfter, searchString, orderBy, order, collection }) => {
|
|
@@ -1073,7 +1083,7 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1073
1083
|
orderBy,
|
|
1074
1084
|
order
|
|
1075
1085
|
});
|
|
1076
|
-
return (await getDocs(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId))).docs.map((doc) =>
|
|
1086
|
+
return (await getDocs(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId))).docs.map((doc) => createRowFromDocument(doc));
|
|
1077
1087
|
}, [buildQuery]);
|
|
1078
1088
|
/**
|
|
1079
1089
|
* Listen to a entities in a given path
|
|
@@ -1088,7 +1098,7 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1088
1098
|
* @param order
|
|
1089
1099
|
* @param onUpdate
|
|
1090
1100
|
* @return Function to cancel subscription
|
|
1091
|
-
* @see
|
|
1101
|
+
* @see useCollection if you need this functionality implemented as a hook
|
|
1092
1102
|
* @group Firestore
|
|
1093
1103
|
*/
|
|
1094
1104
|
const listenCollection = useCallback(({ path, filter, limit, startAfter, searchString, orderBy, order, onUpdate, onError, collection }) => {
|
|
@@ -1116,8 +1126,8 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1116
1126
|
resolvedPath
|
|
1117
1127
|
});
|
|
1118
1128
|
return onSnapshot(buildQuery(resolvedPath, filter, orderBy, order, startAfter, limit, databaseId), {
|
|
1119
|
-
next: (
|
|
1120
|
-
if (!searchString) onUpdate(
|
|
1129
|
+
next: (entity) => {
|
|
1130
|
+
if (!searchString) onUpdate(entity.docs.map((doc) => createRowFromDocument(doc)));
|
|
1121
1131
|
},
|
|
1122
1132
|
error: onError
|
|
1123
1133
|
});
|
|
@@ -1127,38 +1137,38 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1127
1137
|
performTextSearch
|
|
1128
1138
|
]);
|
|
1129
1139
|
/**
|
|
1130
|
-
* Retrieve
|
|
1140
|
+
* Retrieve a entity given a path and a collection
|
|
1131
1141
|
* @param path
|
|
1132
|
-
* @param
|
|
1142
|
+
* @param id
|
|
1133
1143
|
* @param collection
|
|
1134
1144
|
* @group Firestore
|
|
1135
1145
|
*/
|
|
1136
|
-
const
|
|
1137
|
-
return getAndBuildEntity(path,
|
|
1146
|
+
const fetchOne = useCallback(({ path, id, collection }) => {
|
|
1147
|
+
return getAndBuildEntity(path, id, collection?.databaseId);
|
|
1138
1148
|
}, [getAndBuildEntity]);
|
|
1139
1149
|
/**
|
|
1140
1150
|
* Save entity to the specified path. Note that Firestore does not allow
|
|
1141
1151
|
* undefined values.
|
|
1142
1152
|
* @param path
|
|
1143
|
-
* @param
|
|
1153
|
+
* @param id
|
|
1144
1154
|
* @param values
|
|
1145
1155
|
* @param schemaId
|
|
1146
1156
|
* @param collection
|
|
1147
1157
|
* @param status
|
|
1148
1158
|
* @group Firestore
|
|
1149
1159
|
*/
|
|
1150
|
-
const
|
|
1160
|
+
const save = useCallback(({ path, id, values: valuesProp, collection: collection$1, status }) => {
|
|
1151
1161
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
1152
1162
|
console.debug("1", {
|
|
1153
1163
|
path,
|
|
1154
|
-
|
|
1164
|
+
id,
|
|
1155
1165
|
values: valuesProp,
|
|
1156
1166
|
collection: collection$1
|
|
1157
1167
|
});
|
|
1158
1168
|
const values = cmsToFirestoreModel(valuesProp, getFirestore(firebaseApp));
|
|
1159
1169
|
console.debug("2", {
|
|
1160
1170
|
path,
|
|
1161
|
-
|
|
1171
|
+
id,
|
|
1162
1172
|
values: valuesProp,
|
|
1163
1173
|
collection: collection$1
|
|
1164
1174
|
});
|
|
@@ -1166,18 +1176,17 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1166
1176
|
const collectionReference = collection(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), path);
|
|
1167
1177
|
console.debug("Saving entity", {
|
|
1168
1178
|
path,
|
|
1169
|
-
|
|
1179
|
+
id,
|
|
1170
1180
|
values,
|
|
1171
1181
|
databaseId
|
|
1172
1182
|
});
|
|
1173
1183
|
let documentReference;
|
|
1174
|
-
if (
|
|
1184
|
+
if (id) documentReference = doc(collectionReference, String(id));
|
|
1175
1185
|
else documentReference = doc(collectionReference);
|
|
1176
1186
|
return setDoc(documentReference, values, { merge: true }).then(() => {
|
|
1177
1187
|
return {
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
values: firestoreToCMSModel(values)
|
|
1188
|
+
...firestoreToCMSModel(values),
|
|
1189
|
+
id: documentReference.id
|
|
1181
1190
|
};
|
|
1182
1191
|
}).catch((error) => {
|
|
1183
1192
|
console.error("Error saving entity", error);
|
|
@@ -1185,15 +1194,15 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1185
1194
|
});
|
|
1186
1195
|
}, [firebaseApp]);
|
|
1187
1196
|
/**
|
|
1188
|
-
* Delete
|
|
1197
|
+
* Delete a entity
|
|
1189
1198
|
* @param entity
|
|
1190
1199
|
* @param collection
|
|
1191
1200
|
* @group Firestore
|
|
1192
1201
|
*/
|
|
1193
|
-
const
|
|
1202
|
+
const deleteOne = useCallback(({ row, collection }) => {
|
|
1194
1203
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
1195
|
-
const databaseId =
|
|
1196
|
-
return deleteDoc(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp),
|
|
1204
|
+
const databaseId = collection?.databaseId;
|
|
1205
|
+
return deleteDoc(doc(databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp), row.path, String(row.id)));
|
|
1197
1206
|
}, [firebaseApp]);
|
|
1198
1207
|
/**
|
|
1199
1208
|
* Check if the given property is unique in the given collection
|
|
@@ -1201,18 +1210,18 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1201
1210
|
* @param name of the property
|
|
1202
1211
|
* @param value
|
|
1203
1212
|
* @param property
|
|
1204
|
-
* @param
|
|
1213
|
+
* @param id
|
|
1205
1214
|
* @return `true` if there are no other fields besides the given entity
|
|
1206
1215
|
* @group Firestore
|
|
1207
1216
|
*/
|
|
1208
|
-
const checkUniqueField = useCallback(async (path, name, value,
|
|
1217
|
+
const checkUniqueField = useCallback(async (path, name, value, id, collection$2) => {
|
|
1209
1218
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
1210
1219
|
const databaseId = collection$2?.databaseId;
|
|
1211
1220
|
const firestore = databaseId ? getFirestore(firebaseApp, databaseId) : getFirestore(firebaseApp);
|
|
1212
1221
|
if (value === void 0 || value === null) return Promise.resolve(true);
|
|
1213
|
-
return (await getDocs(query(collection(firestore, path), where(name, "==", cmsToFirestoreModel(value, firestore))))).docs.filter((doc) => doc.id !==
|
|
1222
|
+
return (await getDocs(query(collection(firestore, path), where(name, "==", cmsToFirestoreModel(value, firestore))))).docs.filter((doc) => doc.id !== id).length === 0;
|
|
1214
1223
|
}, [firebaseApp]);
|
|
1215
|
-
const
|
|
1224
|
+
const count = useCallback(async ({ path, filter, order, orderBy, collection }) => {
|
|
1216
1225
|
if (!firebaseApp) throw Error("useFirestoreDriver Firebase not initialised");
|
|
1217
1226
|
const databaseId = collection?.databaseId;
|
|
1218
1227
|
return (await getCountFromServer(buildQuery(path, filter, orderBy, order, void 0, void 0, databaseId))).data().count;
|
|
@@ -1241,35 +1250,31 @@ function useFirestoreDriver({ firebaseApp, textSearchControllerBuilder, firestor
|
|
|
1241
1250
|
initTextSearch,
|
|
1242
1251
|
fetchCollection,
|
|
1243
1252
|
listenCollection,
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1253
|
+
fetchOne,
|
|
1254
|
+
listenOne,
|
|
1255
|
+
save,
|
|
1256
|
+
delete: deleteOne,
|
|
1248
1257
|
checkUniqueField,
|
|
1249
|
-
|
|
1258
|
+
count,
|
|
1250
1259
|
isFilterCombinationValid
|
|
1251
1260
|
}), [
|
|
1252
1261
|
firebaseApp,
|
|
1253
1262
|
initTextSearch,
|
|
1254
1263
|
fetchCollection,
|
|
1255
1264
|
listenCollection,
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1265
|
+
fetchOne,
|
|
1266
|
+
listenOne,
|
|
1267
|
+
save,
|
|
1268
|
+
deleteOne,
|
|
1260
1269
|
checkUniqueField,
|
|
1261
|
-
|
|
1270
|
+
count,
|
|
1262
1271
|
isFilterCombinationValid
|
|
1263
1272
|
]);
|
|
1264
1273
|
}
|
|
1265
|
-
var
|
|
1266
|
-
const values = firestoreToCMSModel(docSnap.data());
|
|
1267
|
-
const path = getCMSPathFromFirestorePath(docSnap.ref.path);
|
|
1274
|
+
var createRowFromDocument = (docSnap) => {
|
|
1268
1275
|
return {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
values,
|
|
1272
|
-
databaseId
|
|
1276
|
+
...firestoreToCMSModel(docSnap.data()),
|
|
1277
|
+
id: docSnap.id
|
|
1273
1278
|
};
|
|
1274
1279
|
};
|
|
1275
1280
|
/**
|
|
@@ -1384,70 +1389,65 @@ function useFirebaseRTDBDelegate({ firebaseApp }) {
|
|
|
1384
1389
|
let dbQuery = query$1(ref$1(getDatabase(firebaseApp), path));
|
|
1385
1390
|
if (startAfter !== void 0) dbQuery = query$1(dbQuery, orderByKey(), startAt(String(startAfter)));
|
|
1386
1391
|
if (limit !== void 0) dbQuery = query$1(dbQuery, limitToFirst(limit));
|
|
1387
|
-
const
|
|
1388
|
-
if (
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
values: delegateToCMSModel(values)
|
|
1392
|
+
const entity = await get(dbQuery);
|
|
1393
|
+
if (entity.exists()) return Object.entries(entity.val()).map(([id, values]) => ({
|
|
1394
|
+
...delegateToCMSModel(values),
|
|
1395
|
+
id
|
|
1392
1396
|
}));
|
|
1393
1397
|
return [];
|
|
1394
1398
|
}, [firebaseApp]),
|
|
1395
1399
|
listenCollection: useCallback(({ path, onUpdate }) => {
|
|
1396
1400
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1397
|
-
const unsubscribe = onValue(ref$1(getDatabase(firebaseApp), path), (
|
|
1398
|
-
if (
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
values: delegateToCMSModel(values)
|
|
1401
|
+
const unsubscribe = onValue(ref$1(getDatabase(firebaseApp), path), (entity) => {
|
|
1402
|
+
if (entity.exists()) onUpdate(Object.entries(entity.val()).map(([id, values]) => ({
|
|
1403
|
+
...delegateToCMSModel(values),
|
|
1404
|
+
id
|
|
1402
1405
|
})));
|
|
1403
1406
|
else onUpdate([]);
|
|
1404
1407
|
});
|
|
1405
1408
|
return () => unsubscribe();
|
|
1406
1409
|
}, [firebaseApp]),
|
|
1407
|
-
|
|
1410
|
+
fetchOne: useCallback(async ({ path, id }) => {
|
|
1408
1411
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1409
|
-
const
|
|
1410
|
-
if (
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
values: delegateToCMSModel(snapshot.val())
|
|
1412
|
+
const entity = await get(ref$1(getDatabase(firebaseApp), `${path}/${id}`));
|
|
1413
|
+
if (entity.exists()) return {
|
|
1414
|
+
...delegateToCMSModel(entity.val()),
|
|
1415
|
+
id
|
|
1414
1416
|
};
|
|
1415
1417
|
}, [firebaseApp]),
|
|
1416
|
-
|
|
1418
|
+
listenOne: useCallback(({ path, id, onUpdate, onError }) => {
|
|
1417
1419
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1418
|
-
const unsubscribe = onValue(ref$1(getDatabase(firebaseApp), `${path}/${
|
|
1419
|
-
if (
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
values: delegateToCMSModel(snapshot.val())
|
|
1420
|
+
const unsubscribe = onValue(ref$1(getDatabase(firebaseApp), `${path}/${id}`), (entity) => {
|
|
1421
|
+
if (entity.exists()) onUpdate({
|
|
1422
|
+
...delegateToCMSModel(entity.val()),
|
|
1423
|
+
id
|
|
1423
1424
|
});
|
|
1424
1425
|
else onError?.(/* @__PURE__ */ new Error("Entity does not exist"));
|
|
1425
1426
|
});
|
|
1426
1427
|
return () => unsubscribe();
|
|
1427
1428
|
}, [firebaseApp]),
|
|
1428
|
-
|
|
1429
|
+
save: useCallback(async ({ path, id, values }) => {
|
|
1429
1430
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1430
1431
|
const database = getDatabase(firebaseApp);
|
|
1431
|
-
const finalId =
|
|
1432
|
+
const finalId = id ?? push(ref$1(database, path)).key;
|
|
1432
1433
|
if (!finalId) throw new Error("Could not generate a new id");
|
|
1433
1434
|
const transformedValues = cmsToRTDBModel(values, database);
|
|
1434
1435
|
await set(ref$1(database, `${path}/${finalId}`), transformedValues);
|
|
1435
1436
|
return {
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
values
|
|
1437
|
+
...values,
|
|
1438
|
+
id: finalId
|
|
1439
1439
|
};
|
|
1440
1440
|
}, [firebaseApp]),
|
|
1441
|
-
|
|
1441
|
+
delete: useCallback(async ({ row }) => {
|
|
1442
1442
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1443
|
-
await remove(ref$1(getDatabase(firebaseApp), `${
|
|
1443
|
+
await remove(ref$1(getDatabase(firebaseApp), `${row.path}/${row.id}`));
|
|
1444
1444
|
}, [firebaseApp]),
|
|
1445
|
-
checkUniqueField: useCallback(async (slug, name, value,
|
|
1445
|
+
checkUniqueField: useCallback(async (slug, name, value, id) => {
|
|
1446
1446
|
if (!firebaseApp) throw new Error("Firebase app not provided");
|
|
1447
|
-
const
|
|
1448
|
-
if (!
|
|
1449
|
-
const [key, entityValue] = Object.entries(
|
|
1450
|
-
if (entityValue && typeof entityValue === "object" && entityValue[name] === value && key ===
|
|
1447
|
+
const entity = await get(query$1(ref$1(getDatabase(firebaseApp), slug), orderByChild(name), startAt(value), limitToFirst(1)));
|
|
1448
|
+
if (!entity.exists()) return true;
|
|
1449
|
+
const [key, entityValue] = Object.entries(entity.val())[0];
|
|
1450
|
+
if (entityValue && typeof entityValue === "object" && entityValue[name] === value && key === id) return true;
|
|
1451
1451
|
return false;
|
|
1452
1452
|
}, [firebaseApp]),
|
|
1453
1453
|
isFilterCombinationValid: useCallback(({ path, filter, sortBy }) => {
|
|
@@ -1537,11 +1537,11 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1537
1537
|
setRolesLoading(true);
|
|
1538
1538
|
return dataSourceDelegate.listenCollection?.({
|
|
1539
1539
|
path: rolesPath,
|
|
1540
|
-
onUpdate(
|
|
1540
|
+
onUpdate(rows) {
|
|
1541
1541
|
setRolesError(void 0);
|
|
1542
|
-
console.debug("Updating roles",
|
|
1542
|
+
console.debug("Updating roles", rows);
|
|
1543
1543
|
try {
|
|
1544
|
-
const newRoles =
|
|
1544
|
+
const newRoles = rowsToRoles(rows);
|
|
1545
1545
|
if (!deepEqual(newRoles, roles)) setRoles(newRoles);
|
|
1546
1546
|
} catch (e) {
|
|
1547
1547
|
setRoles([]);
|
|
@@ -1571,11 +1571,11 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1571
1571
|
setUsersLoading(true);
|
|
1572
1572
|
return dataSourceDelegate.listenCollection?.({
|
|
1573
1573
|
path: usersPath,
|
|
1574
|
-
onUpdate(
|
|
1575
|
-
console.debug("Updating users",
|
|
1574
|
+
onUpdate(rows) {
|
|
1575
|
+
console.debug("Updating users", rows);
|
|
1576
1576
|
setUsersError(void 0);
|
|
1577
1577
|
try {
|
|
1578
|
-
setUsersWithRoleIds(
|
|
1578
|
+
setUsersWithRoleIds(rowsToUsers(rows));
|
|
1579
1579
|
} catch (e) {
|
|
1580
1580
|
setUsersWithRoleIds([]);
|
|
1581
1581
|
console.error("Error loading users", e);
|
|
@@ -1610,21 +1610,21 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1610
1610
|
...userExists ? {} : { created_on: /* @__PURE__ */ new Date() }
|
|
1611
1611
|
};
|
|
1612
1612
|
if (userExists && userExists.uid !== user.uid) {
|
|
1613
|
-
const
|
|
1613
|
+
const row = {
|
|
1614
1614
|
values: {},
|
|
1615
1615
|
path: usersPath,
|
|
1616
1616
|
id: userExists.uid
|
|
1617
1617
|
};
|
|
1618
|
-
await dataSourceDelegate.
|
|
1618
|
+
await dataSourceDelegate.delete({ row }).then(() => {
|
|
1619
1619
|
console.debug("Deleted previous user", userExists);
|
|
1620
1620
|
}).catch((e) => {
|
|
1621
1621
|
console.error("Error deleting user", e);
|
|
1622
1622
|
});
|
|
1623
1623
|
}
|
|
1624
|
-
return dataSourceDelegate.
|
|
1624
|
+
return dataSourceDelegate.save({
|
|
1625
1625
|
status: "existing",
|
|
1626
1626
|
path: usersPath,
|
|
1627
|
-
|
|
1627
|
+
id: email,
|
|
1628
1628
|
values: removeUndefined(data)
|
|
1629
1629
|
}).then(() => user);
|
|
1630
1630
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
|
@@ -1633,10 +1633,10 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1633
1633
|
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
|
1634
1634
|
console.debug("Persisting role", role);
|
|
1635
1635
|
const { id, ...roleData } = role;
|
|
1636
|
-
return dataSourceDelegate.
|
|
1636
|
+
return dataSourceDelegate.save({
|
|
1637
1637
|
status: "existing",
|
|
1638
1638
|
path: rolesPath,
|
|
1639
|
-
|
|
1639
|
+
id,
|
|
1640
1640
|
values: removeUndefined(roleData)
|
|
1641
1641
|
}).then(() => {});
|
|
1642
1642
|
}, [rolesPath, dataSourceDelegate?.initialised]);
|
|
@@ -1645,24 +1645,24 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1645
1645
|
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
|
1646
1646
|
console.debug("Deleting", user);
|
|
1647
1647
|
const { uid } = user;
|
|
1648
|
-
const
|
|
1648
|
+
const row = {
|
|
1649
1649
|
path: usersPath,
|
|
1650
1650
|
id: uid,
|
|
1651
1651
|
values: {}
|
|
1652
1652
|
};
|
|
1653
|
-
await dataSourceDelegate.
|
|
1653
|
+
await dataSourceDelegate.delete({ row });
|
|
1654
1654
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
|
1655
1655
|
const deleteRole = useCallback(async (role) => {
|
|
1656
1656
|
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
|
1657
1657
|
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
|
1658
1658
|
console.debug("Deleting", role);
|
|
1659
1659
|
const { id } = role;
|
|
1660
|
-
const
|
|
1660
|
+
const row = {
|
|
1661
1661
|
path: rolesPath,
|
|
1662
1662
|
id,
|
|
1663
1663
|
values: {}
|
|
1664
1664
|
};
|
|
1665
|
-
await dataSourceDelegate.
|
|
1665
|
+
await dataSourceDelegate.delete({ row });
|
|
1666
1666
|
}, [rolesPath, dataSourceDelegate?.initialised]);
|
|
1667
1667
|
const defineRolesFor = useCallback((user) => {
|
|
1668
1668
|
if (!usersWithRoleIds) throw Error("Users not loaded");
|
|
@@ -1738,22 +1738,21 @@ function useBuildUserManagement({ authController, dataSourceDelegate, roles: rol
|
|
|
1738
1738
|
} : null
|
|
1739
1739
|
};
|
|
1740
1740
|
}
|
|
1741
|
-
var
|
|
1742
|
-
return
|
|
1743
|
-
const data =
|
|
1744
|
-
const record = data;
|
|
1741
|
+
var rowsToUsers = (rows) => {
|
|
1742
|
+
return rows.map((row) => {
|
|
1743
|
+
const { id, ...data } = row;
|
|
1745
1744
|
return {
|
|
1746
1745
|
...data,
|
|
1747
|
-
uid:
|
|
1748
|
-
created_on:
|
|
1749
|
-
updated_on:
|
|
1746
|
+
uid: id,
|
|
1747
|
+
created_on: data.created_on,
|
|
1748
|
+
updated_on: data.updated_on
|
|
1750
1749
|
};
|
|
1751
1750
|
});
|
|
1752
1751
|
};
|
|
1753
|
-
var
|
|
1754
|
-
return
|
|
1755
|
-
|
|
1756
|
-
|
|
1752
|
+
var rowsToRoles = (rows) => {
|
|
1753
|
+
return rows.map((row) => ({
|
|
1754
|
+
...row,
|
|
1755
|
+
id: row.id
|
|
1757
1756
|
}));
|
|
1758
1757
|
};
|
|
1759
1758
|
//#endregion
|
|
@@ -2581,7 +2580,12 @@ function RebaseFirebaseApp({ name, logo, logoDark, accessGate, collections, view
|
|
|
2581
2580
|
authController,
|
|
2582
2581
|
userConfigPersistence,
|
|
2583
2582
|
dateTimeFormat,
|
|
2584
|
-
|
|
2583
|
+
dataSources: [{
|
|
2584
|
+
key: DEFAULT_DATA_SOURCE_KEY,
|
|
2585
|
+
engine: "firestore",
|
|
2586
|
+
transport: "direct",
|
|
2587
|
+
driver: firestoreDelegate
|
|
2588
|
+
}],
|
|
2585
2589
|
storageSource,
|
|
2586
2590
|
entityLinkBuilder: ({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`,
|
|
2587
2591
|
locale,
|
|
@@ -2607,7 +2611,7 @@ function RebaseFirebaseApp({ name, logo, logoDark, accessGate, collections, view
|
|
|
2607
2611
|
to: urlController.buildUrlCollectionPath(firstCollectionEntry.id),
|
|
2608
2612
|
replace: true
|
|
2609
2613
|
}) : /* @__PURE__ */ jsx(CenteredView, { children: "No home page or collections provided." });
|
|
2610
|
-
component = /* @__PURE__ */ jsx(
|
|
2614
|
+
component = /* @__PURE__ */ jsx(SidePanelProvider, { children: /* @__PURE__ */ jsx(RebaseRoutes, { children: /* @__PURE__ */ jsxs(Route, {
|
|
2611
2615
|
element: /* @__PURE__ */ jsxs(Scaffold, {
|
|
2612
2616
|
logo: usedLogo,
|
|
2613
2617
|
autoOpenDrawer,
|