import React, { useCallback, useState } from "react"; import { Alert, Button, CheckIcon, CircularProgress, cls, ContentCopyIcon, IconButton, OpenInNewIcon, Tooltip, Typography, } from "@firecms/ui"; import { EntityCollection, useTranslation } from "@firecms/core"; import { ProjectsApi } from "../api/projects"; const FIRECMS_RULE_SNIPPET = `match /{document=**} { allow read, write: if request.auth.token.fireCMSUser; }`; export type PermissionErrorViewProps = { path: string; collection: EntityCollection; parentCollectionIds?: string[]; error: Error; projectId: string; projectsApi: ProjectsApi; onAnalyticsEvent?: (event: string, data?: object) => void; }; /** * Custom error view for the SaaS plugin that detects "Missing or insufficient permissions" * and provides actionable CTAs to fix it. * * For non-permission errors, returns null to fall back to the default error view. */ export function PermissionErrorView({ path, collection, error, projectId, projectsApi, onAnalyticsEvent, }: PermissionErrorViewProps) { const { t } = useTranslation(); const isPermissionError = error.message?.toLowerCase().includes("permission") || error.message?.toLowerCase().includes("insufficient"); const [fixing, setFixing] = useState(false); const [fixed, setFixed] = useState(false); const [fixError, setFixError] = useState(null); const [copied, setCopied] = useState(false); const handleFixAutomatically = useCallback(async () => { onAnalyticsEvent?.("permission_error_fix_click", { path, projectId }); setFixing(true); setFixError(null); try { await projectsApi.addSecurityRules(projectId); setFixed(true); onAnalyticsEvent?.("permission_error_fix_success", { path, projectId }); } catch (e: any) { console.error("Failed to add security rules:", e); setFixError(e?.message || "Failed to add security rules. Please try manually."); onAnalyticsEvent?.("permission_error_fix_error", { path, projectId }); } finally { setFixing(false); } }, [projectsApi, projectId, path, onAnalyticsEvent]); const handleCopyRule = useCallback(async () => { try { await navigator.clipboard.writeText(FIRECMS_RULE_SNIPPET); setCopied(true); setTimeout(() => setCopied(false), 2000); } catch { // fallback - ignore } }, []); const rulesConsoleUrl = `https://console.firebase.google.com/project/${projectId}/firestore/rules`; if (!isPermissionError) { // Not a permission error — fall back to default error rendering return null; } return (
{t("missing_firestore_security_rules")} {t("firecms_cloud_requires_security_rule")} {path} {t("cannot_be_accessed_without_it")}
{/* Rule snippet */}
{t("required_security_rule")} {copied ? : }
                        {FIRECMS_RULE_SNIPPET}
                    
{/* Status messages */} {fixed && ( {t("security_rules_updated_successfully")} )} {fixError && ( {fixError} )} {/* CTAs */}
); }