Skip to content

Commit

Permalink
Fixes for default Firebase instance used by clients.
Browse files Browse the repository at this point in the history
Pinecone search controller.
Added web blog entry for beta
  • Loading branch information
fgatti675 committed Jan 31, 2024
1 parent 23a8352 commit 52d996e
Show file tree
Hide file tree
Showing 36 changed files with 479 additions and 180 deletions.
4 changes: 2 additions & 2 deletions examples/example_pro/src/SampleApp/SampleApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { localeCollectionGroup, productsCollection } from "./collections/product
import { blogCollection } from "./collections/blog_collection";
import { showcaseCollection } from "./collections/showcase_collection";

import { textSearchControllerBuilder } from "./text_search";
import { algoliaSearchControllerBuilder, pineconeSearchControllerBuilder } from "./text_search";

import { CustomLoginView } from "./CustomLoginView";
import { cryptoCollection } from "./collections/crypto_collection";
Expand Down Expand Up @@ -162,7 +162,7 @@ function SampleApp() {
// 'microsoft.com',
// 'apple.com'
]}
textSearchControllerBuilder={textSearchControllerBuilder}
textSearchControllerBuilder={pineconeSearchControllerBuilder}
firestoreIndexesBuilder={firestoreIndexesBuilder}
logo={logo}
collections={(params) => collections}
Expand Down
29 changes: 27 additions & 2 deletions examples/example_pro/src/SampleApp/text_search.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import algoliasearch, { SearchClient } from "algoliasearch";

import { buildAlgoliaSearchController, performAlgoliaTextSearch } from "@firecms/firebase_pro";
import {
buildAlgoliaSearchController,
buildPineconeSearchController,
performAlgoliaTextSearch,
performPineconeTextSearch
} from "@firecms/firebase_pro";

let client: SearchClient | undefined;
// process is defined for react-scripts builds
Expand All @@ -24,7 +29,7 @@ const usersIndex = client && client.initIndex("users");
const blogIndex = client && client.initIndex("blog");
const booksIndex = client && client.initIndex("books");

export const textSearchControllerBuilder = buildAlgoliaSearchController({
export const algoliaSearchControllerBuilder = buildAlgoliaSearchController({
isPathSupported: (path) => {
return ["products", "users", "blog", "books"].includes(path);
},
Expand All @@ -43,3 +48,23 @@ export const textSearchControllerBuilder = buildAlgoliaSearchController({
return undefined;
}
});

export const pineconeSearchControllerBuilder = buildPineconeSearchController({
isPathSupported: (path) => {
return ["products"].includes(path);
},
search: async ({
path,
searchString,
currentUser
}) => {
if (path === "products")
return performPineconeTextSearch({
firebaseToken: await currentUser.getIdToken(),
projectId: "firecms-backend",
collectionPath: "products",
query: searchString
});
throw new Error("Path not supported");
}
});
4 changes: 2 additions & 2 deletions examples/example_v3/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react"
import { FireCMS3App } from "firecms";
import { FireCMSApp } from "firecms";
import appConfig from "./index";

function App(): React.ReactElement {
return <FireCMS3App
return <FireCMSApp
// backendApiHost={"http://127.0.0.1:5001/firecms-dev-2da42/europe-west3/api"}
backendApiHost={"https://api-kdoe6pj3qq-ey.a.run.app"}
projectId={"firecms-demo-27150"}
Expand Down
21 changes: 21 additions & 0 deletions examples/example_v3/src/search.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { buildPineconeSearchController, performPineconeTextSearch } from "@firecms/firebase";

export const pineconeSearchControllerBuilder = buildPineconeSearchController({
isPathSupported: (path) => {
return ["products"].includes(path);
},
search: async ({
path,
searchString,
currentUser
}) => {
if (path === "products")
return performPineconeTextSearch({
firebaseToken: await currentUser.getIdToken(),
projectId: "firecms-demo-27150",
collectionPath: "products",
query: searchString
});
throw new Error("Path not supported");
}
});
41 changes: 27 additions & 14 deletions packages/firebase_firecms/src/hooks/useFirebaseAuthController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";

import {
ApplicationVerifier,
Expand Down Expand Up @@ -47,11 +47,13 @@ export const useFirebaseAuthController = ({
const [confirmationResult, setConfirmationResult] = useState<undefined | ConfirmationResult>();

const [userRoles, setUserRoles] = useState<Role[] | null>(null);
const authRef = useRef(firebaseApp ? getAuth(firebaseApp) : null);

useEffect(() => {
if (!firebaseApp) return;
try {
const auth = getAuth(firebaseApp);
authRef.current = auth;
setAuthError(undefined);
setLoggedUser(auth.currentUser)
return onAuthStateChanged(
Expand Down Expand Up @@ -82,7 +84,8 @@ export const useFirebaseAuthController = ({
options.scopes.forEach((scope) => provider.addScope(scope));
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth(firebaseApp);
const auth = authRef.current;
if(!auth) throw Error("No auth");
signInWithPopup(auth, provider).catch(setAuthProviderError);
}, [getProviderOptions]);

Expand All @@ -93,23 +96,26 @@ export const useFirebaseAuthController = ({
}, [loggedUser]);

const emailPasswordLogin = useCallback((email: string, password: string) => {
const auth = getAuth(firebaseApp);
const auth = authRef.current;
if(!auth) throw Error("No auth");
setAuthLoading(true);
signInWithEmailAndPassword(auth, email, password)
.catch(setAuthProviderError)
.then(() => setAuthLoading(false));
}, []);

const createUserWithEmailAndPassword = useCallback((email: string, password: string) => {
const auth = getAuth(firebaseApp);
const auth = authRef.current;
if(!auth) throw Error("No auth");
setAuthLoading(true);
createUserWithEmailAndPasswordFirebase(auth, email, password)
.catch(setAuthProviderError)
.then(() => setAuthLoading(false));
}, []);

const fetchSignInMethodsForEmail = useCallback((email: string): Promise<string[]> => {
const auth = getAuth(firebaseApp);
const auth = authRef.current;
if(!auth) throw Error("No auth");
setAuthLoading(true);
return fetchSignInMethodsForEmailFirebase(auth, email)
.then((res) => {
Expand All @@ -119,7 +125,8 @@ export const useFirebaseAuthController = ({
}, []);

const onSignOut = useCallback(() => {
const auth = getAuth(firebaseApp);
const auth = authRef.current;
if(!auth) throw Error("No auth");
signOut(auth)
.then(_ => {
setLoggedUser(null);
Expand All @@ -141,15 +148,17 @@ export const useFirebaseAuthController = ({
}, []);

const anonymousLogin = useCallback(() => {
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
setAuthLoading(true);
signInAnonymously(auth)
.catch(setAuthProviderError)
.then(() => setAuthLoading(false));
}, []);

const phoneLogin = useCallback((phone: string, applicationVerifier: ApplicationVerifier) => {
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
setAuthLoading(true);
return signInWithPhoneNumber(auth, phone, applicationVerifier)
.catch(setAuthProviderError)
Expand All @@ -166,7 +175,8 @@ export const useFirebaseAuthController = ({
options.scopes.forEach((scope) => provider.addScope(scope));
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
doOauthLogin(auth, provider);
}, [doOauthLogin, getProviderOptions]);

Expand All @@ -177,7 +187,8 @@ export const useFirebaseAuthController = ({
options.scopes.forEach((scope) => provider.addScope(scope));
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
doOauthLogin(auth, provider);
}, [doOauthLogin, getProviderOptions]);

Expand All @@ -188,7 +199,8 @@ export const useFirebaseAuthController = ({
options.scopes.forEach((scope) => provider.addScope(scope));
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
doOauthLogin(auth, provider);
}, [doOauthLogin, getProviderOptions]);

Expand All @@ -199,7 +211,8 @@ export const useFirebaseAuthController = ({
options.scopes.forEach((scope) => provider.addScope(scope));
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
doOauthLogin(auth, provider);
}, [doOauthLogin, getProviderOptions]);

Expand All @@ -208,11 +221,11 @@ export const useFirebaseAuthController = ({
const options = getProviderOptions("twitter.com");
if (options?.customParameters)
provider.setCustomParameters(options.customParameters);
const auth = getAuth();
const auth = authRef.current;
if(!auth) throw Error("No auth");
doOauthLogin(auth, provider);
}, [doOauthLogin, getProviderOptions]);


const skipLogin = useCallback(() => {
setLoginSkipped(true);
setLoggedUser(null);
Expand Down
20 changes: 14 additions & 6 deletions packages/firebase_firecms/src/hooks/useFirestoreDelegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { FirebaseApp } from "firebase/app";
import { FirestoreTextSearchController, FirestoreTextSearchControllerBuilder } from "../types/text_search";
import { useCallback, useEffect, useRef } from "react";
import { localSearchControllerBuilder } from "../utils";
import { getAuth } from "firebase/auth";

/**
* @group Firebase
Expand Down Expand Up @@ -192,10 +193,10 @@ export function useFirestoreDelegate({
}, [firebaseApp]);

const performTextSearch = useCallback(<M extends Record<string, any>>({
path,
searchString,
onUpdate
}: {
path,
searchString,
onUpdate
}: {
path: string,
searchString: string;
onUpdate: (entities: Entity<M>[]) => void
Expand All @@ -208,9 +209,15 @@ export function useFirestoreDelegate({
throw Error("Trying to make text search without specifying a FirestoreTextSearchController");

let subscriptions: (() => void)[] = [];

const auth = getAuth(firebaseApp);
const currentUser = auth.currentUser;
if (!currentUser) throw Error("No current user");

const search = textSearchController.search({
path,
searchString
searchString,
currentUser
});

if (!search) {
Expand Down Expand Up @@ -768,7 +775,8 @@ function buildTextSearchControllerWithLocalSearch({
},
search: (props: {
searchString: string,
path: string
path: string,
currentUser: any
}) => {
return textSearchController.search(props) ?? localSearchController.search(props);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const hostingError = "It seems like the provided Firebase config is not correct.
* configuration.
*
* You most likely only need to use this if you are developing a custom app
* that is not using {@link FireCMS3App}. You can also not use this component
* that is not using {@link FireCMSApp}. You can also not use this component
* and initialise Firebase yourself.
*
* @param onFirebaseInit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface InitializeAppCheckResult {
* It works as a hook that gives you back an object holding the Firebase App.
*
* You most likely only need to use this if you are developing a custom app
* that is not using {@link FireCMS3App}. You can also not use this component
* that is not using {@link FireCMSApp}. You can also not use this component
* and initialise App Check yourself.
*
* @param firebaseApp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Authenticator } from "../types/auth";

/**
* This hook is used internally for validating an authenticator.
* You may want to use it if you are not using {@link FireCMS3App}, but
* You may want to use it if you are not using {@link FireCMSApp}, but
* building your own custom {@link FireCMS} instance.
* @param authController
* @param authentication
Expand Down
18 changes: 10 additions & 8 deletions packages/firebase_firecms/src/types/text_search.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@

import { User as FirebaseUser } from "firebase/auth";
import { FirebaseApp } from "firebase/app";
import { EntityCollection, ResolvedEntityCollection } from "@firecms/core";

export type FirestoreTextSearchControllerBuilder = (props: {
firebaseApp: FirebaseApp;
}) => FirestoreTextSearchController;

/**
* Use this controller to return a list of ids from a search index, given a
* `path` and a `searchString`.
Expand All @@ -8,13 +17,6 @@
* @see performAlgoliaTextSearch
* @group Firebase
*/
import { FirebaseApp } from "firebase/app";
import { EntityCollection, ResolvedEntityCollection } from "@firecms/core";

export type FirestoreTextSearchControllerBuilder = (props: {
firebaseApp: FirebaseApp;
}) => FirestoreTextSearchController;

export type FirestoreTextSearchController = {
/**
* This method is called when a search delegate is ready to be used.
Expand All @@ -29,5 +31,5 @@ export type FirestoreTextSearchController = {
* Do the search and return a list of ids.
* @param props
*/
search: (props: { searchString: string, path: string }) => (Promise<readonly string[]> | undefined),
search: (props: { searchString: string, path: string, currentUser: FirebaseUser }) => (Promise<readonly string[]> | undefined),
};
1 change: 1 addition & 0 deletions packages/firebase_firecms/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./collections_firestore";
export * from "./database";
export * from "./algolia";
export * from "./pinecone";
export * from "./local_text_search_controller";
Loading

0 comments on commit 52d996e

Please sign in to comment.