import { IconAlertHexagon } from "@tabler/icons-react"; import type { ModuleConfigs, ModuleSchemas } from "modules"; import { getDefaultConfig, getDefaultSchema } from "modules/ModuleManager"; import { createContext, startTransition, useContext, useEffect, useRef, useState } from "react"; import { useApi } from "ui/client"; import { Button } from "ui/components/buttons/Button"; import { Alert } from "ui/components/display/Alert"; import { type TSchemaActions, getSchemaActions } from "./schema/actions"; import { AppReduced } from "./utils/AppReduced"; type BkndContext = { version: number; schema: ModuleSchemas; config: ModuleConfigs; permissions: string[]; hasSecrets: boolean; requireSecrets: () => Promise; actions: ReturnType; app: AppReduced; adminOverride?: ModuleConfigs["server"]["admin"]; }; const BkndContext = createContext(undefined!); export type { TSchemaActions }; export function BkndProvider({ includeSecrets = false, adminOverride, children, fallback = null }: { includeSecrets?: boolean; children: any; fallback?: React.ReactNode } & Pick< BkndContext, "adminOverride" >) { const [withSecrets, setWithSecrets] = useState(includeSecrets); const [schema, setSchema] = useState>(); const [fetched, setFetched] = useState(false); const [error, setError] = useState(); const errorShown = useRef(); const [local_version, set_local_version] = useState(0); const api = useApi(); async function reloadSchema() { await fetchSchema(includeSecrets, true); } async function fetchSchema(_includeSecrets: boolean = false, force?: boolean) { if (withSecrets && !force) return; const res = await api.system.readSchema({ config: true, secrets: _includeSecrets }); if (!res.ok) { if (errorShown.current) return; errorShown.current = true; setError(true); //return; } else if (error) { setError(false); } const schema = res.ok ? res.body : ({ version: 0, schema: getDefaultSchema(), config: getDefaultConfig(), permissions: [] } as any); if (adminOverride) { schema.config.server.admin = { ...schema.config.server.admin, ...adminOverride }; } startTransition(() => { setSchema(schema); setWithSecrets(_includeSecrets); setFetched(true); set_local_version((v) => v + 1); }); } async function requireSecrets() { if (withSecrets) return; await fetchSchema(true); } useEffect(() => { if (schema?.schema) return; fetchSchema(includeSecrets); }, []); if (!fetched || !schema) return fallback; const app = new AppReduced(schema?.config as any); const actions = getSchemaActions({ api, setSchema, reloadSchema }); const hasSecrets = withSecrets && !error; return ( {/*{error && ( You attempted to load system configuration with secrets without having proper permission. )}*/} {children} ); } export function useBknd({ withSecrets }: { withSecrets?: boolean } = {}): BkndContext { const ctx = useContext(BkndContext); if (withSecrets) ctx.requireSecrets(); return ctx; }