import React, { useCallback } from "react"; import { AIIcon, EntityCollection, FireCMSPlugin, InternalUserManagement, useAuthController, useNavigationController, useTranslation } from "@firecms/core"; import { CollectionsConfigController, mergeCollections, useCollectionEditorController } from "@firecms/collection_editor"; import { AddIcon, ArticleIcon, Button, Card, cls, HistoryIcon, Typography } from "@firecms/ui"; import { ProjectConfig } from "./useBuildProjectConfig"; import { TextSearchInfoDialog } from "../components/subscriptions/TextSearchInfoDialog"; import { FireCMSAppConfig, FireCMSBackend } from "../types"; import { RootCollectionSuggestions } from "../components/RootCollectionSuggestions"; import { PermissionErrorView } from "../components/PermissionErrorView"; import { AutoSetUpCollectionsButton } from "../components/AutoSetUpCollectionsButton"; import { EnableEntityHistoryView } from "../components/EnableEntityHistoryView"; import { CollectionsSetupLoadingLabel } from "../components/CollectionsSetupLoadingLabel"; import { RootCollectionInfo } from "../api/projects"; export function useSaasPlugin({ projectConfig, collectionConfigController, appConfig, userManagement, introMode, fireCMSBackend, onAnalyticsEvent, historyDefaultEnabled, rootPathSuggestions }: { projectConfig: ProjectConfig; appConfig?: FireCMSAppConfig; userManagement: InternalUserManagement; collectionConfigController: CollectionsConfigController; introMode?: "new_project" | "existing_project"; fireCMSBackend: FireCMSBackend; onAnalyticsEvent?: (event: string, data?: object) => void; historyDefaultEnabled?: boolean; rootPathSuggestions?: RootCollectionInfo[]; }): FireCMSPlugin { const hasOwnTextSearchImplementation = Boolean(appConfig?.textSearchControllerBuilder); const additionalChildrenStart = <> ; const additionalChildrenEnd = <> ; const modifyCollection = useCallback((collection: EntityCollection) => { if (collection.history === false && !historyDefaultEnabled) { return { ...collection, entityViews: [ ...(collection.entityViews ?? []), { key: "__history", name: "History", tabComponent: , Builder: EnableEntityHistoryView, position: "start" } ], } satisfies EntityCollection; } return collection; }, []); const injectCollections = useCallback( (collections: EntityCollection[]) => mergeCollections( collections, (collectionConfigController.collections ?? []).map(modifyCollection), appConfig?.modifyCollection ), [collectionConfigController.collections]); return { key: "saas", homePage: { additionalChildrenStart, additionalChildrenEnd, }, userManagement, collection: { injectCollections: projectConfig.isTrialOver ? undefined : injectCollections, modifyCollection }, collectionView: { CollectionError: useCallback(({ path, collection, parentCollectionIds, error }: { path: string; collection: EntityCollection; parentCollectionIds?: string[]; error: Error; }) => { return ; }, [projectConfig.projectId, fireCMSBackend.projectsApi, onAnalyticsEvent]), blockSearch: ({ context, path, collection, parentCollectionIds }) => { return !(projectConfig.typesenseSearchConfig?.enabled || (projectConfig.localTextSearchEnabled && collection.textSearchEnabled)); }, showTextSearchBar: ({ context, path, collection }) => { if (collection.textSearchEnabled === false) { return false; } return true; }, onTextSearchClick: ({ context, path, collection, parentCollectionIds }) => { const canSearch = projectConfig.typesenseSearchConfig?.enabled || (projectConfig.localTextSearchEnabled && collection.textSearchEnabled); if (!canSearch) { if (parentCollectionIds === undefined) { console.warn("Enabling text search: Parent collection ids are undefined") } else { context.dialogsController.open({ key: "text_search_info", Component: (props) => }); } } return Promise.resolve(false); } } } } export function IntroWidget({ introMode, fireCMSBackend, projectConfig, onAnalyticsEvent }: { introMode?: "new_project" | "existing_project"; fireCMSBackend: FireCMSBackend; projectConfig: ProjectConfig; onAnalyticsEvent?: (event: string, data?: object) => void; }) { const navigation = useNavigationController(); const collectionEditorController = useCollectionEditorController(); const authController = useAuthController(); const { t } = useTranslation(); if (!navigation.topLevelNavigation) throw Error("Navigation not ready in FireCMSHomePage"); if (!navigation.initialised) { return null; } const hasCollections = navigation.initialised && (navigation.collections ?? []).length > 0; if (hasCollections) { return null; } const canCreateCollections = collectionEditorController.configPermissions ? collectionEditorController.configPermissions({ user: authController.user }).createCollections : true; const subtitle = introMode === "existing_project" ? t("admin_panel_ready_bring_data") : t("admin_panel_ready_get_started"); return (
{t("welcome_to_firecms")} {subtitle}
{introMode === "existing_project" && ( } title={t("auto_detect_collections")} description={t("auto_detect_collections_desc")} > onAnalyticsEvent?.("intro_cols_setup_click")} onSuccess={() => onAnalyticsEvent?.("intro_cols_setup_success")} onNoCollections={() => onAnalyticsEvent?.("intro_cols_setup_no_cols")} onError={() => onAnalyticsEvent?.("intro_cols_setup_error")} /> )} } title={t("create_a_collection")} description={t("create_collection_desc")} > } title={t("read_the_docs")} description={t("read_the_docs_desc")} >
{t("want_to_customize_with_code")}{" "} npx create-firecms-app {" "} {t("to_scaffold_a_local_project")}
); } function IntroCard({ icon, title, description, children }: { icon: React.ReactNode; title: string; description: string; children: React.ReactNode; }) { return (
{icon} {title}
{description}
{children}
); } // save locally that the alert was dismissed function saveHistoryAlertDismissed() { localStorage.setItem("firecms_saas_alert_history_dismissed", "true"); } function isHistoryAlertDismissed(): boolean { return localStorage.getItem("firecms_saas_alert_history_dismissed") === "true"; }