diff --git a/example/src/SimpleAppWithProvider.tsx b/example/src/SimpleAppWithProvider.tsx
index dadd8ff..b8ead03 100644
--- a/example/src/SimpleAppWithProvider.tsx
+++ b/example/src/SimpleAppWithProvider.tsx
@@ -2,7 +2,7 @@ import React from "react";
import { FirebaseApp } from "firebase/app";
import { GoogleAuthProvider } from "firebase/auth";
-import { ThemeProvider, CssBaseline } from "@mui/material";
+import { CssBaseline, ThemeProvider } from "@mui/material";
import { BrowserRouter as Router } from "react-router-dom";
import "typeface-rubik";
@@ -15,16 +15,17 @@ import {
buildSchema,
CircularProgressCenter,
CMSAppProvider,
- CMSMainView,
+ CMSRoutes,
+ CMSScaffold,
createCMSDefaultTheme,
EntityLinkBuilder,
FirebaseLoginView,
- initialiseFirebase,
NavigationBuilder,
NavigationBuilderProps,
useFirebaseAuthHandler,
useFirebaseStorageSource,
- useFirestoreDataSource
+ useFirestoreDataSource,
+ useInitialiseFirebase
} from "@camberi/firecms";
import { firebaseConfig } from "./firebase_config";
@@ -95,7 +96,7 @@ export function SimpleAppWithProvider() {
firebaseConfigLoading,
configError,
firebaseConfigError
- } = initialiseFirebase({ firebaseConfig });
+ } = useInitialiseFirebase({ firebaseConfig });
if (configError) {
return
{configError}
;
@@ -139,7 +140,7 @@ export function SimpleAppWithProvider() {
storageSource={storageSource}>
{({ context }) => {
- if (context.authController.authLoading) {
+ if (context.authController.authLoading || !context.navigation) {
return ;
}
@@ -152,11 +153,14 @@ export function SimpleAppWithProvider() {
);
}
- return ;
+ return (
+
+
+ );
}}
- );
+);
}
diff --git a/package.json b/package.json
index 9dc87c6..29f28d6 100644
--- a/package.json
+++ b/package.json
@@ -35,15 +35,11 @@
},
"dependencies": {
"@date-io/date-fns": "^1.3.11",
- "@types/deep-equal": "^1.0.1",
- "@types/react-measure": "^2.0.6",
"@uiw/react-md-editor": "^3.4.10",
"date-fns": "^2.21.3",
"deep-equal": "^2.0.5",
"firebaseui": "~0.600",
"formik": "^2.2.6",
- "history": "^5.0.0",
- "material-ui-popup-state": "^1.8.3",
"object-hash": "^2.1.1",
"react-base-table": "^1.12.0",
"react-csv": "^2.0.3",
@@ -51,8 +47,8 @@
"react-dnd-html5-backend": "^14.0.0",
"react-dropzone": "^11.3.2",
"react-measure": "^2.5.2",
- "react-router": "^6.0.0-beta.0",
- "react-router-dom": "^6.0.0-beta.0",
+ "react-router": "^6.0.0-beta.4",
+ "react-router-dom": "^6.0.0-beta.4",
"react-transition-group": "^4.4.1",
"typeface-roboto": "^1.1.13",
"typeface-rubik": "^1.1.13",
@@ -63,10 +59,10 @@
"peerDependencies": {
"@emotion/react": "latest",
"@emotion/styled": "latest",
- "@mui/material": "next",
- "@mui/styles": "next",
"@mui/icons-material": "next",
"@mui/lab": "next",
+ "@mui/material": "next",
+ "@mui/styles": "next",
"algoliasearch": "^4.9.1",
"firebase": "^9.0.0",
"react": "^17.0.2",
@@ -82,11 +78,13 @@
"devDependencies": {
"@emotion/react": "latest",
"@emotion/styled": "latest",
- "@mui/material": "next",
- "@mui/styles": "next",
"@mui/icons-material": "next",
"@mui/lab": "next",
+ "@mui/material": "next",
+ "@mui/styles": "next",
"@rollup/plugin-typescript": "^8.2.1",
+ "@types/deep-equal": "^1.0.1",
+ "@types/react-measure": "^2.0.6",
"@types/jest": "^26.0.23",
"@types/node": "^15.0.2",
"@types/object-hash": "^2.1.0",
diff --git a/src/contexts/SideEntityController.tsx b/src/contexts/SideEntityController.tsx
index 6d1c4f1..4190de7 100644
--- a/src/contexts/SideEntityController.tsx
+++ b/src/contexts/SideEntityController.tsx
@@ -95,7 +95,7 @@ export const SideEntityProvider: React.FC = ({
const schemasRegistry = useSchemasRegistry();
- const basePathname = location.state && location.state["base_pathname"] ? location.state["base_pathname"] : location.pathname;
+ const baseLocation = location.state && location.state["base_location"] ? location.state["base_location"] : location;
useEffect(() => {
if (schemasRegistry.initialised) {
@@ -194,7 +194,7 @@ export const SideEntityProvider: React.FC = ({
{
replace: true,
state: {
- base_pathname: basePathname,
+ base_location: baseLocation,
panels: [...sidePanels.slice(0, -1), updatedPanel]
}
}
@@ -212,7 +212,7 @@ export const SideEntityProvider: React.FC = ({
newPath,
{
state: {
- base_pathname: basePathname,
+ base_location: baseLocation,
panels: [...sidePanels, newPanel]
}
}
diff --git a/src/core/CMSRouterSwitch.tsx b/src/core/CMSRouterSwitch.tsx
deleted file mode 100644
index 3e85240..0000000
--- a/src/core/CMSRouterSwitch.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from "react";
-
-import { useLocation } from "react-router-dom";
-import { Navigation } from "../models";
-import { addInitialSlash, buildCollectionUrlPath } from "./navigation";
-
-import CollectionRoute from "./internal/CollectionRoute";
-import CMSViewRoute from "./internal/CMSViewRoute";
-import HomeRoute from "./internal/HomeRoute";
-
-export function CMSRouterSwitch({ navigation }: {
- navigation: Navigation
-}) {
-
- const location = useLocation();
- const basePathname = location.state && location.state["base_pathname"] ? location.state["base_pathname"] : location.pathname;
-
- if (addInitialSlash(basePathname) === "/")
- return ;
-
-
- const matchedCollection = [...navigation.collections]
- // we reorder collections so that nested paths are included first
- .sort((a, b) => b.relativePath.length - a.relativePath.length)
- .find(entityCollection => {
- return addInitialSlash(buildCollectionUrlPath(entityCollection)) === addInitialSlash(basePathname);
- });
-
- if (matchedCollection) {
- return ;
- }
- if (navigation.views) {
- const matchedView = [...navigation.views].find(view => {
- if (Array.isArray(view.path)) {
- const matchedPath = view.path.find((p) => addInitialSlash(p) === addInitialSlash(basePathname));
- return matchedPath !== undefined;
- } else {
- return addInitialSlash(view.path) === addInitialSlash(basePathname);
- }
- });
- if (matchedView) {
- return ;
- }
- }
- return <>>;
-
- // TODO: the following implementation relies on being able to override the location
- // TODO: in react-router
- // const buildCMSViewRoute = (path: string, cmsView: CMSView) => {
- // return
- //
- // ;
- // };
- //
- // let customRoutes: JSX.Element[] = [];
- // if (navigation.views) {
- // navigation.views.forEach((cmsView) => {
- // if (Array.isArray(cmsView.path))
- // customRoutes.push(...cmsView.path.map(path => buildCMSViewRoute(path, cmsView)));
- // else
- // customRoutes.push(buildCMSViewRoute(cmsView.path, cmsView));
- // });
- // }
- // const collectionRoutes = [...collections]
- // // we reorder collections so that nested paths are included first
- // .sort((a, b) => b.relativePath.length - a.relativePath.length)
- // .map(entityCollection => (
- //
- //
- //
- // )
- // );
- // return (
- //
- //
- // {collectionRoutes}
- //
- // {customRoutes}
- //
- //
- //
- //
- //
- //
- // );
-}
diff --git a/src/core/CMSRoutes.tsx b/src/core/CMSRoutes.tsx
new file mode 100644
index 0000000..d4e1489
--- /dev/null
+++ b/src/core/CMSRoutes.tsx
@@ -0,0 +1,97 @@
+import React from "react";
+
+import { Route, Routes, useLocation } from "react-router-dom";
+import { CMSView, Navigation } from "../models";
+import { addInitialSlash, buildCollectionUrlPath } from "./navigation";
+import { EntityCollectionTable } from "./components/EntityCollectionTable";
+import BreadcrumbUpdater from "./components/BreadcrumbUpdater";
+import CMSHome from "./components/CMSHome";
+
+/**
+ * This component is in charge of taking a {@link Navigation} and rendering
+ * all the related routes (entity collection root views, custom views
+ * or the home route).
+ *
+ * @param navigation
+ * @constructor
+ */
+export function CMSRoutes({ navigation }: {
+ navigation: Navigation
+}) {
+
+ const location = useLocation();
+ /**
+ * The location can be overridden if `base_location` is set in the
+ * state field of the current location. This can happen if you open
+ * a side entity, like `products`, from a different one, like `users`
+ */
+ const baseLocation = location.state && location.state["base_location"] ? location.state["base_location"] : location;
+
+ const customRoutes: JSX.Element[] = [];
+ if (navigation.views) {
+ const buildCMSViewRoute = (path: string, cmsView: CMSView) => {
+ return
+ {cmsView.view}
+ }
+ />;
+ };
+
+ navigation.views.forEach((cmsView) => {
+ if (Array.isArray(cmsView.path))
+ customRoutes.push(...cmsView.path.map(path => buildCMSViewRoute(path, cmsView)));
+ else
+ customRoutes.push(buildCMSViewRoute(cmsView.path, cmsView));
+ });
+ }
+
+ const collectionRoutes = [...navigation.collections]
+ // we reorder collections so that nested paths are included first
+ .sort((a, b) => b.relativePath.length - a.relativePath.length)
+ .map(entityCollection => {
+ const urlPath = buildCollectionUrlPath(entityCollection);
+ return (
+
+
+
+ }/>
+ );
+ }
+ );
+
+ const homeRoute =
+
+
+
+ }/>;
+
+ return (
+
+
+ {collectionRoutes}
+
+ {customRoutes}
+
+ {homeRoute}
+
+
+ );
+}
diff --git a/src/core/CMSMainView.tsx b/src/core/CMSScaffold.tsx
similarity index 93%
rename from src/core/CMSMainView.tsx
rename to src/core/CMSScaffold.tsx
index 5444aae..d77ba27 100644
--- a/src/core/CMSMainView.tsx
+++ b/src/core/CMSScaffold.tsx
@@ -20,7 +20,7 @@ import * as locales from "date-fns/locale";
/**
* @category Core
*/
-export interface CMSMainViewProps {
+export interface CMSScaffoldProps {
/**
* Name of the app, displayed as the main title and in the tab title
@@ -32,12 +32,6 @@ export interface CMSMainViewProps {
*/
logo?: string;
- /**
- * If authentication is enabled, allow the user to access the content
- * without login.
- */
- allowSkipLogin?: boolean;
-
/**
* A component that gets rendered on the upper side of the main toolbar
*/
@@ -92,7 +86,7 @@ const useStyles = makeStyles((theme: Theme) =>
* @constructor
* @category Core
*/
-export function CMSMainView(props: PropsWithChildren) {
+export function CMSScaffold(props: PropsWithChildren) {
const {
children,
diff --git a/src/core/components/BreadcrumbUpdater.tsx b/src/core/components/BreadcrumbUpdater.tsx
new file mode 100644
index 0000000..e52a5ca
--- /dev/null
+++ b/src/core/components/BreadcrumbUpdater.tsx
@@ -0,0 +1,37 @@
+import React, { PropsWithChildren } from "react";
+import { useBreadcrumbsContext } from "../../contexts";
+import { EntityCollectionTable } from "./EntityCollectionTable";
+
+export type BreadcrumbRouteProps = {
+ title: string;
+ path: string;
+};
+
+/**
+ * This component updates the breadcrumb in the app bar when rendered
+ * @param children
+ * @param title
+ * @param path
+ * @constructor
+ */
+function BreadcrumbUpdater({
+ children,
+ title,
+ path
+ }
+ : PropsWithChildren) {
+
+ const breadcrumbsContext = useBreadcrumbsContext();
+ React.useEffect(() => {
+ breadcrumbsContext.set({
+ breadcrumbs: [{
+ title: title,
+ url: path
+ }]
+ });
+ }, [path]);
+
+ return <> {children}>;
+}
+
+export default BreadcrumbUpdater;
diff --git a/src/core/internal/HomeRoute.tsx b/src/core/components/CMSHome.tsx
similarity index 84%
rename from src/core/internal/HomeRoute.tsx
rename to src/core/components/CMSHome.tsx
index 5785520..dd9fb12 100644
--- a/src/core/internal/HomeRoute.tsx
+++ b/src/core/components/CMSHome.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import React from "react";
import {
Box,
Card,
@@ -16,14 +16,9 @@ import createStyles from "@mui/styles/createStyles";
import makeStyles from "@mui/styles/makeStyles";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import PlaylistPlayIcon from "@mui/icons-material/PlaylistPlay";
-import { Link as ReactLink, useLocation } from "react-router-dom";
+import { Link as ReactLink } from "react-router-dom";
-import {
- BreadcrumbEntry,
- computeNavigation,
- NavigationEntry
-} from "../navigation";
-import { useBreadcrumbsContext } from "../../contexts";
+import { computeNavigation, NavigationEntry } from "../navigation";
import { Navigation } from "../../models";
import { Markdown } from "../../preview";
@@ -41,30 +36,21 @@ export const useStyles = makeStyles((theme: Theme) =>
})
);
-
-interface HomeRouteProps {
+export interface CMSHomeProps {
navigation: Navigation;
}
-function HomeRoute({
+/**
+ * Default main view and entry point for the CMS
+ * This components takes navigation as an input and renders
+ * @param navigation
+ * @constructor
+ */
+function CMSHome({
navigation
- }: HomeRouteProps) {
+ }: CMSHomeProps) {
const classes = useStyles();
- const { pathname } = useLocation();
-
- const breadcrumb: BreadcrumbEntry = {
- title: "Home",
- url: pathname
- };
-
- const breadcrumbsContext = useBreadcrumbsContext();
-
- useEffect(() => {
- breadcrumbsContext.set({
- breadcrumbs: [breadcrumb]
- });
- }, [pathname]);
const {
navigationEntries,
@@ -114,7 +100,6 @@ function HomeRoute({
);
}
-
return (
{allGroups.map((group, index) => (
@@ -145,4 +130,4 @@ function HomeRoute({
);
}
-export default HomeRoute;
+export default CMSHome;
diff --git a/src/core/components/index.tsx b/src/core/components/index.tsx
index f57ed26..fbc0b78 100644
--- a/src/core/components/index.tsx
+++ b/src/core/components/index.tsx
@@ -1,3 +1,5 @@
+import { CMSHomeProps } from "./CMSHome";
+
export type { ErrorViewProps } from "./ErrorView";
export {
default as ErrorView
@@ -22,8 +24,12 @@ export {
default as CircularProgressCenter
} from "./CircularProgressCenter";
-export type { FirebaseLoginViewProps } from "./FirebaseLoginView";
+export type { CMSHomeProps } from "./CMSHome";
export {
- default as FirebaseLoginView
-} from "./FirebaseLoginView";
+ default as CMSHome
+} from "./CMSHome";
+export {
+ default as BreadcrumbUpdater
+} from "./BreadcrumbUpdater";
+
diff --git a/src/core/index.tsx b/src/core/index.tsx
index f6865a5..bd09dcc 100644
--- a/src/core/index.tsx
+++ b/src/core/index.tsx
@@ -1,17 +1,17 @@
-
export { CMSAppProvider } from "./CMSAppProvider";
export type {
CMSAppProviderProps
} from "./CMSAppProvider";
-export { CMSMainView } from "./CMSMainView";
+export { CMSRoutes } from "./CMSRoutes";
+
+export { CMSScaffold } from "./CMSScaffold";
export type {
- CMSMainViewProps
-} from "./CMSMainView";
+ CMSScaffoldProps
+} from "./CMSScaffold";
export * from "./components";
-export { initialiseFirebase } from "./initialiseFirebase";
export { createCMSDefaultTheme } from "./theme";
diff --git a/src/core/internal/CMSViewRoute.tsx b/src/core/internal/CMSViewRoute.tsx
deleted file mode 100644
index fbc7dd2..0000000
--- a/src/core/internal/CMSViewRoute.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, { useEffect } from "react";
-import { useLocation } from "react-router-dom";
-import { BreadcrumbEntry } from "../navigation";
-import { useBreadcrumbsContext } from "../../contexts";
-import { CMSView } from "../../models";
-
-
-interface CMSViewRouteProps {
- cmsView: CMSView;
-}
-
-function CMSViewRoute({
- cmsView
- }: CMSViewRouteProps) {
-
- const { pathname } = useLocation();
-
- const breadcrumb: BreadcrumbEntry = {
- title: cmsView.name,
- url: pathname
- };
-
- const breadcrumbsContext = useBreadcrumbsContext();
-
- useEffect(() => {
- breadcrumbsContext.set({
- breadcrumbs: [breadcrumb]
- });
- }, [pathname]);
-
- return
- {cmsView.view}
- ;
-}
-
-export default CMSViewRoute;
diff --git a/src/core/internal/CollectionRoute.tsx b/src/core/internal/CollectionRoute.tsx
deleted file mode 100644
index 553ab9b..0000000
--- a/src/core/internal/CollectionRoute.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from "react";
-import { EntityCollection } from "../../models";
-import createStyles from "@mui/styles/createStyles";
-import makeStyles from "@mui/styles/makeStyles";
-import { useLocation } from "react-router-dom";
-import { useBreadcrumbsContext } from "../../contexts";
-import { EntityCollectionTable } from "../components/EntityCollectionTable";
-
-export const useStyles = makeStyles(() =>
- createStyles({
- root: {
- height: "100%",
- display: "flex",
- flexDirection: "column"
- }
- })
-);
-
-interface CollectionRouteProps {
- collectionConfig: EntityCollection;
- path: string
-}
-
-function CollectionRoute({
- collectionConfig,
- path
- }
- : CollectionRouteProps) {
-
- const { pathname } = useLocation();
- const breadcrumbsContext = useBreadcrumbsContext();
- React.useEffect(() => {
- breadcrumbsContext.set({
- breadcrumbs: [{
- title: collectionConfig.name,
- url: pathname
- }]
- });
- }, [pathname]);
-
- const classes = useStyles();
-
- return (
-
-
-
-
-
- );
-}
-
-export default CollectionRoute;
diff --git a/src/core/navigation.ts b/src/core/navigation.ts
index d7930b4..a184467 100644
--- a/src/core/navigation.ts
+++ b/src/core/navigation.ts
@@ -38,10 +38,6 @@ export function buildCollectionUrlPath(view: EntityCollection) {
return `${DATA_PATH}/${removeInitialAndTrailingSlashes(view.relativePath)}`;
}
-export function buildCollectionPath(view: EntityCollection) {
- return `${DATA_PATH}/${removeInitialAndTrailingSlashes(view.relativePath)}`;
-}
-
export function removeInitialAndTrailingSlashes(s: string) {
return removeInitialSlash(removeTrailingSlash(s));
}
@@ -243,6 +239,7 @@ export function computeNavigation(navigation:Navigation, includeHiddenViews: boo
...navigation.collections.map(collection => ({
url: buildCollectionUrlPath(collection),
name: collection.name,
+ description: collection.description,
group: collection.group
})),
...(navigation.views ?? []).map(view =>
diff --git a/src/firebase_app/CMSApp.tsx b/src/firebase_app/CMSApp.tsx
index 4687784..99ad40b 100644
--- a/src/firebase_app/CMSApp.tsx
+++ b/src/firebase_app/CMSApp.tsx
@@ -2,28 +2,29 @@ import React from "react";
import { GoogleAuthProvider } from "firebase/auth";
import { CssBaseline, ThemeProvider } from "@mui/material";
-import { BrowserRouter as Router } from "react-router-dom";
+import { BrowserRouter } from "react-router-dom";
+
+import {
+ CircularProgressCenter,
+ CMSAppProvider,
+ CMSScaffold,
+ CMSRoutes,
+ createCMSDefaultTheme
+} from "../core";
+import { AuthController } from "../contexts";
+import { EntityLinkBuilder } from "../models";
import { CMSAppProps } from "./CMSAppProps";
-import {
- CMSAppProvider,
- CMSMainView,
- createCMSDefaultTheme,
- initialiseFirebase
-} from "../core";
-import { CMSRouterSwitch } from "../core/CMSRouterSwitch";
-import { CircularProgressCenter, FirebaseLoginView } from "../core/components";
-import { AuthController } from "../contexts";
import { useFirebaseAuthHandler } from "./useFirebaseAuthHandler";
-import { EntityLinkBuilder } from "../models";
import { useFirestoreDataSource } from "./useFirestoreDataSource";
import { useFirebaseStorageSource } from "./useFirebaseStorageSource";
+import { useInitialiseFirebase } from "./useInitialiseFirebase";
+import FirebaseLoginView from "./FirebaseLoginView";
const DEFAULT_SIGN_IN_OPTIONS = [
GoogleAuthProvider.PROVIDER_ID
];
-
/**
* Main entry point for FireCMS. You can use this component as a full app,
* by specifying collections and entity schemas.
@@ -32,7 +33,7 @@ const DEFAULT_SIGN_IN_OPTIONS = [
* configuration object.
*
* If you are building a larger app and need finer control, you can use
- * {@link CMSAppProvider} and {@link CMSMainView} instead.
+ * {@link CMSAppProvider} and {@link CMSScaffold} instead.
*
* @param props
* @constructor
@@ -62,7 +63,7 @@ export function CMSApp({
firebaseConfigLoading,
configError,
firebaseConfigError
- } = initialiseFirebase({ onFirebaseInit, firebaseConfig });
+ } = useInitialiseFirebase({ onFirebaseInit, firebaseConfig });
const authController: AuthController = useFirebaseAuthHandler({
firebaseApp,
@@ -86,7 +87,10 @@ export function CMSApp({
return ;
}
- const dataSource = useFirestoreDataSource({ firebaseApp: firebaseApp! , textSearchDelegateResolver});
+ const dataSource = useFirestoreDataSource({
+ firebaseApp: firebaseApp!,
+ textSearchDelegateResolver
+ });
const storageSource = useFirebaseStorageSource({ firebaseApp: firebaseApp! });
const mode: "light" | "dark" = "light";
@@ -100,9 +104,11 @@ export function CMSApp({
const entityLinkBuilder: EntityLinkBuilder = ({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`;
return (
-
-
-
+
+
+
+
+
-
- ;
+ return (
+
+
+
+ );
}}
-
-
-);
+
+
+ );
}
diff --git a/src/firebase_app/CMSAppProps.tsx b/src/firebase_app/CMSAppProps.tsx
index 72904bf..88215a2 100644
--- a/src/firebase_app/CMSAppProps.tsx
+++ b/src/firebase_app/CMSAppProps.tsx
@@ -7,7 +7,7 @@ import {
NavigationBuilder,
SchemaResolver
} from "../models";
-import { TextSearchDelegateResolver } from "./text_search_delegate";
+import { TextSearchDelegateResolver } from "./text_search";
/**
* Main entry point that defines the CMS configuration
diff --git a/src/core/components/FirebaseLoginView.tsx b/src/firebase_app/FirebaseLoginView.tsx
similarity index 98%
rename from src/core/components/FirebaseLoginView.tsx
rename to src/firebase_app/FirebaseLoginView.tsx
index 1714790..efd01f6 100644
--- a/src/core/components/FirebaseLoginView.tsx
+++ b/src/firebase_app/FirebaseLoginView.tsx
@@ -6,7 +6,7 @@ import makeStyles from "@mui/styles/makeStyles";
import firebase from "firebase/compat/app";
-import { useAuthController } from "../../contexts";
+import { useAuthController } from "../contexts";
import * as firebaseui from "firebaseui";
import "firebaseui/dist/firebaseui.css";
diff --git a/src/firebase_app/index.ts b/src/firebase_app/index.ts
index 9377a17..cbd6054 100644
--- a/src/firebase_app/index.ts
+++ b/src/firebase_app/index.ts
@@ -1,3 +1,4 @@
+import { InitialiseFirebaseResult } from "./useInitialiseFirebase";
export { CMSApp } from "./CMSApp";
export type {
@@ -20,3 +21,11 @@ export {
export type { TextSearchDelegateResolver } from "./text_search";
export { performAlgoliaTextSearch } from "./text_search";
+export type { FirebaseLoginViewProps } from "./FirebaseLoginView";
+export {
+ default as FirebaseLoginView
+} from "./FirebaseLoginView";
+
+export type { InitialiseFirebaseResult } from "./useInitialiseFirebase";
+export { useInitialiseFirebase } from "./useInitialiseFirebase";
+
diff --git a/src/firebase_app/useFirestoreDataSource.ts b/src/firebase_app/useFirestoreDataSource.ts
index 674b93f..61d4a18 100644
--- a/src/firebase_app/useFirestoreDataSource.ts
+++ b/src/firebase_app/useFirestoreDataSource.ts
@@ -45,7 +45,8 @@ import {
where as whereClause
} from "firebase/firestore";
import { FirebaseApp } from "firebase/app";
-import { TextSearchDelegateResolver } from "./text_search_delegate";
+import { TextSearchDelegateResolver } from "./text_search";
+import firebase from "firebase/compat/app";
export type FirestoreDataSourceProps = {
firebaseApp: FirebaseApp,
@@ -365,15 +366,8 @@ export function useFirestoreDataSource({
}: SaveEntityProps): Promise {
const properties: Properties = computeSchemaProperties(schema, path, entityId);
- let updatedValues: EntityValues = updateAutoValues(
- {
- inputValues: values,
- properties,
- status,
- timestampNowValue: serverTimestamp(),
- referenceConverter: (value: EntityReference) => doc(db, value.path, value.id),
- geopointConverter: (value: GeoPoint) => new GeoPoint(value.latitude, value.longitude)
- });
+
+ let updatedValues: EntityValues;
if (schema.onPreSave) {
try {
@@ -381,7 +375,7 @@ export function useFirestoreDataSource({
schema,
path,
entityId,
- values: updatedValues,
+ values,
status,
context
});
@@ -393,6 +387,17 @@ export function useFirestoreDataSource({
}
}
+ updatedValues = updateAutoValues(
+ {
+ inputValues: values,
+ properties,
+ status,
+ timestampNowValue: serverTimestamp(),
+ referenceConverter: (value: EntityReference) => doc(db, value.path, value.id),
+ geopointConverter: (value: GeoPoint) => new firebase.firestore.GeoPoint(value.latitude, value.longitude)
+ });
+
+
console.debug("Saving entity", path, entityId, updatedValues);
let documentReference: DocumentReference;
diff --git a/src/core/initialiseFirebase.ts b/src/firebase_app/useInitialiseFirebase.ts
similarity index 95%
rename from src/core/initialiseFirebase.ts
rename to src/firebase_app/useInitialiseFirebase.ts
index e9ae501..0014f7f 100644
--- a/src/core/initialiseFirebase.ts
+++ b/src/firebase_app/useInitialiseFirebase.ts
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { FirebaseApp, initializeApp } from "firebase/app";
-export interface CMSFirebaseInitResult {
+export interface InitialiseFirebaseResult {
firebaseConfigLoading: boolean,
firebaseApp?: FirebaseApp;
configError?: string,
@@ -24,10 +24,10 @@ export interface CMSFirebaseInitResult {
* @param firebaseConfig
* @category Hooks and utilities Functions
*/
-export function initialiseFirebase({ firebaseConfig, onFirebaseInit }: {
+export function useInitialiseFirebase({ firebaseConfig, onFirebaseInit }: {
onFirebaseInit?: ((config: object) => void) | undefined,
firebaseConfig: Object | undefined
-}): CMSFirebaseInitResult {
+}): InitialiseFirebaseResult {
const [firebaseApp, setFirebaseApp] = React.useState();
const [firebaseConfigLoading, setFirebaseConfigLoading] = React.useState(false);
diff --git a/src/models/entities.ts b/src/models/entities.ts
index d0b6bc8..8532ddf 100644
--- a/src/models/entities.ts
+++ b/src/models/entities.ts
@@ -210,7 +210,7 @@ export interface EntityOnSaveProps {
/**
* Values being saved
*/
- values: EntityValues;
+ values: Partial>;
/**
* New or existing entity
diff --git a/src/test/algolia.test.ts b/src/test/algolia.test.ts
index b3daf27..a335c98 100644
--- a/src/test/algolia.test.ts
+++ b/src/test/algolia.test.ts
@@ -6,10 +6,8 @@ it("Test Algolia search", async () => {
const client = algoliasearch(
"Y6FR1MDSVW",
"f084e6dcc154c04295c8124dbb797ff1");
+ const usersIndex = client.initIndex("users");
- await performAlgoliaTextSearch(
- client,
- "users",
- "john").then(console.log);
+ await performAlgoliaTextSearch(usersIndex, "john").then(console.log);
console.log("done");
});
diff --git a/yarn.lock b/yarn.lock
index f89bf7c..de7da5a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1991,7 +1991,7 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8", "@babel/runtime@^7.7.6":
+"@babel/runtime@^7.13.10", "@babel/runtime@^7.14.8":
version "7.15.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
@@ -2893,11 +2893,6 @@
refractor "^3.3.1"
unist-util-visit "^2.0.3"
-"@material-ui/types@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-6.0.1.tgz#bfcdcd3bb5091e5feac2b191db516543d84e26af"
- integrity sha512-t53C2BZE59e8ao38EDIZdM2smPDSEo5Xx9XxQ/MNM9Ph63Mu4vj5pmECiXkYp0y2OrvFiiZhcqRWV34SBOA18g==
-
"@mui/core@5.0.0-alpha.46":
version "5.0.0-alpha.46"
resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.46.tgz#f4c0e5b2ad346e31e74bb96b684f6734b55cc9e6"
@@ -5383,7 +5378,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
-classnames@^2.2.5, classnames@^2.2.6:
+classnames@^2.2.5:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@@ -8320,13 +8315,6 @@ hex-color-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
-history@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08"
- integrity sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==
- dependencies:
- "@babel/runtime" "^7.7.6"
-
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -10370,16 +10358,6 @@ material-design-lite@^1.2.0:
resolved "https://registry.yarnpkg.com/material-design-lite/-/material-design-lite-1.3.0.tgz#d004ce3fee99a1eeb74a78b8a325134a5f1171d3"
integrity sha1-0ATOP+6Zoe63Sni4oyUTSl8RcdM=
-material-ui-popup-state@^1.8.3:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/material-ui-popup-state/-/material-ui-popup-state-1.9.0.tgz#569d173c941c41ba32791ea759ff21b1a84d70fd"
- integrity sha512-a0OqcXgicrYYKMoBXuajjT94uARgl7ozt1gs735Xb+UmEtanBxjavtoOVo+C4pfVRCHOVamJg+1H48zhOrGd/w==
- dependencies:
- "@babel/runtime" "^7.12.5"
- "@material-ui/types" "^6.0.1"
- classnames "^2.2.6"
- prop-types "^15.7.2"
-
maxmin@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/maxmin/-/maxmin-2.1.0.tgz#4d3b220903d95eee7eb7ac7fa864e72dc09a3166"
@@ -12982,20 +12960,17 @@ react-refresh@^0.8.3:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==
-react-router-dom@^6.0.0-beta.0:
- version "6.0.0-beta.0"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.0.0-beta.0.tgz#9dcc8555365f22f7fbd09f26b6b82543f3eb97d6"
- integrity sha512-36yNNGMT8RB9FRPL9nKJi6HKDkgOakU+o/2hHpSzR6e37gN70MpOU6QQlmif4oAWWBwjyGc3ZNOMFCsFuHUY5w==
+react-router-dom@^6.0.0-beta.4:
+ version "6.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.0.0-beta.4.tgz#9cc9fb57bca3d5548b297ae8101efcdcc68dd903"
+ integrity sha512-yppoRR8S7FxNMG6OGFn9DPJBPLsjeIuQa7GYnkRlgOSTBSPhAQpD6z7rvRzZnesQ9r6W+ibD9RvnqTcna4w/Pg==
dependencies:
- prop-types "^15.7.2"
- react-router "6.0.0-beta.0"
+ react-router "6.0.0-beta.4"
-react-router@6.0.0-beta.0, react-router@^6.0.0-beta.0:
- version "6.0.0-beta.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.0.0-beta.0.tgz#3e11f39b6ded4412c2fed9e4f989dd4c8156724d"
- integrity sha512-VgMdfpVcmFQki/LZuLh8E/MNACekDetz4xqft+a6fBZvvJnVqKbLqebF7hyoawGrV1HcO5tVaUang2Og4W2j1Q==
- dependencies:
- prop-types "^15.7.2"
+react-router@6.0.0-beta.4, react-router@^6.0.0-beta.4:
+ version "6.0.0-beta.4"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.0.0-beta.4.tgz#e35a440b36fd07a2ac854e1f1f176b56a777793a"
+ integrity sha512-48JRRZJOwmfOKM12Tv3WjmNkVb2NpSEgDTWC4+MEJaud0+eyLJxqy62CKzOydMlk7hrfRFpC/elUYSZAuyx3qA==
react-scripts@^4.0.3:
version "4.0.3"