@fayz-ai/plugin-admin 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Every SaaS/admin-template app already resolves a shell config — sidebar or top
11
11
 
12
12
  This is a **foundation pass, not a capability-complete plugin**. It ships a read-only view of `layout` / `moduleNav` / `mobileHeader` / `branding`; there is **no write path** yet. The data provider (mock + Supabase stub) both simply echo back the statically resolved config — there is no shell-config table, and this plugin does not make `FayzAppConfig.layout` (or any of its siblings) mutable at runtime.
13
13
 
14
- **Follow-up**: wire real read/write of these fields back into `FayzAppConfig` once a plugin-editable extension point exists for shell-level config. `docs/CUSTOMIZATION.md` already names the gap — the saas shell's slot contracts (named layout/menu slots, published like the storefront's) are `[planned FAY-1248/FAY-1196]`, the "persona/slots phase". `plugin-admin`'s write path is a consumer of that phase, not a substitute for it: it should land once shell slots have a published contract to write through, not by having this plugin reach around `defineSaas` and mutate config ad hoc.
14
+ **Follow-up**: wire real read/write of these fields back into `FayzAppConfig` once a plugin-editable extension point exists for shell-level config. `docs/saas/CUSTOMIZATION.md` already names the gap — the saas shell's slot contracts (named layout/menu slots, published like the storefront's) are `[planned FAY-1248/FAY-1196]`, the "persona/slots phase". `plugin-admin`'s write path is a consumer of that phase, not a substitute for it: it should land once shell slots have a published contract to write through, not by having this plugin reach around `defineSaas` and mutate config ad hoc.
15
15
 
16
16
  ## What's inside
17
17
  - An `/admin` page: read-only cards for layout, module navigation style, mobile header treatment, and branding visibility
@@ -23,11 +23,11 @@ This is a **foundation pass, not a capability-complete plugin**. It ships a read
23
23
  ```bash
24
24
  npm install @fayz-ai/plugin-admin
25
25
  ```
26
- Peer deps: `react`, `react-dom`. Runtime deps include `@fayz-ai/core`, `@fayz-ai/ui`, and `@fayz-ai/saas`.
26
+ Peer deps: `react`, `react-dom`. Runtime deps include `@fayz-ai/core`, `@fayz-ai/ui`, and `@fayz-ai/admin`.
27
27
 
28
28
  ## Usage
29
29
  ```tsx
30
- import { defineSaas } from '@fayz-ai/saas'
30
+ import { defineSaas } from '@fayz-ai/admin'
31
31
  import { createAdminPlugin } from '@fayz-ai/plugin-admin'
32
32
 
33
33
  export const app = defineSaas({
@@ -50,4 +50,4 @@ Pass the same values you already give `defineSaas` — the plugin doesn't derive
50
50
  Targets the saas/admin-template scaffold only (`scaffolds: ['saas']`) — this is Panel-side shell config, not a storefront concern. Pairs with whatever settings surface the app already exposes; it adds visibility, not a new settings system.
51
51
 
52
52
  ## Roadmap & contributing
53
- Built and evolving in the open. See the [Fayz SDK roadmap](../../docs/ROADMAP.md) and `docs/CUSTOMIZATION.md` (persona/slots phase) for the write-path this is scaffolding toward.
53
+ Built and evolving in the open. See the [Fayz SDK roadmap](../../docs/platform/ROADMAP.md) and `docs/saas/CUSTOMIZATION.md` (persona/slots phase) for the write-path this is scaffolding toward.
@@ -17,4 +17,4 @@ export declare const AdminContextProvider: import("react").FC<{
17
17
  export declare const useAdminConfig: () => ResolvedAdminConfig;
18
18
  export declare const useAdminProvider: () => AdminDataProvider;
19
19
  export declare const useAdminStore: <T>(selector: (state: AdminUIState) => T) => T;
20
- //# sourceMappingURL=AdminContext.d.ts.map
20
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAM3C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAID,eAAO,MAAM,oBAAoB;;;;;EAAsB,CAAA;AACvD,eAAO,MAAM,cAAc,2BAAgB,CAAA;AAC3C,eAAO,MAAM,gBAAgB,yBAAkB,CAAA;AAC/C,eAAO,MAAM,aAAa,gDAAe,CAAA"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,6 @@ import type { PluginManifest } from '@fayz-ai/core';
2
2
  import type { AdminPluginOptions } from './types';
3
3
  export declare function createAdminPlugin(options?: AdminPluginOptions): PluginManifest;
4
4
  export type { AdminDataProvider, AdminSettingsSnapshot } from './data/types';
5
- export type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext';
5
+ export type { ResolvedAdminConfig, AdminPluginLabels } from './context';
6
6
  export type { AdminPluginOptions } from './types';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAyCjD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,cAAc,CA8E9E;AAMD,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAyCjD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,cAAc,CA8E9E;AAMD,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AACvE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { registerTranslations, createSafeDataProvider, useTranslation } from '@fayz-ai/core';
3
3
  import { createStore } from 'zustand/vanilla';
4
- import { createPluginContext, dedup } from '@fayz-ai/saas';
4
+ import { createPluginContext, dedup } from '@fayz-ai/admin';
5
5
  import { PanelTop, LayoutTemplate, Settings2, Smartphone, Palette } from 'lucide-react';
6
6
  import { ModulePage } from '@fayz-ai/ui';
7
7
  import { jsx, jsxs } from 'react/jsx-runtime';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/AdminContext.tsx","../src/AdminPage.tsx","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Mock provider — returns the statically resolved shell-config snapshot\n * (from plugin options / FayzAppConfig defaults). No in-memory mutation:\n * this plugin doesn't write settings yet.\n */\nexport function createMockAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Supabase provider — foundation stub. There is no shell-config table yet:\n * layout/moduleNav/mobileHeader/branding are still owned by FayzAppConfig at\n * build time, not a runtime-editable record. This provider exists so the\n * plugin follows the standard createSafeDataProvider(supabase, mock) seam\n * from day one; it returns the same static snapshot the mock provider does\n * until a real read/write path is wired (see README.md).\n */\nexport function createSupabaseAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { dedup } from '@fayz-ai/saas'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\n\nexport interface AdminUIState {\n settings: AdminSettingsSnapshot | null\n settingsLoading: boolean\n\n fetchSettings(): Promise<void>\n}\n\nexport function createAdminStore(provider: AdminDataProvider): StoreApi<AdminUIState> {\n return createStore<AdminUIState>((set) => ({\n settings: null,\n settingsLoading: false,\n\n async fetchSettings() {\n return dedup('admin:settings', async () => {\n set({ settingsLoading: true })\n try {\n const settings = await provider.getSettings()\n set({ settings, settingsLoading: false })\n } catch {\n set({ settingsLoading: false })\n }\n })\n },\n }))\n}\n","export const en: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Sidebar',\n 'admin.layout.topbar': 'Topbar',\n 'admin.layout.minimal': 'Minimal',\n 'admin.moduleNav.title': 'Module navigation',\n 'admin.moduleNav.rail': 'Side rail for the installed modules',\n 'admin.moduleNav.tabs': 'Tabs for the installed modules',\n 'admin.mobileHeader.title': 'Mobile header',\n 'admin.mobileHeader.minimal': 'Minimal header bar',\n 'admin.mobileHeader.transparent': 'Transparent, edge-to-edge content',\n 'admin.mobileHeader.hidden': 'Hidden',\n 'admin.branding.title': 'Branding',\n 'admin.branding.on': 'Org branding settings are visible to operators',\n 'admin.branding.off': 'Org branding settings are hidden',\n 'admin.readOnlyNotice': 'Read-only preview. Editing these settings here is coming soon — for now they are set in your app config.',\n}\n","export const ptBR: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Barra lateral',\n 'admin.layout.topbar': 'Barra superior',\n 'admin.layout.minimal': 'Minimalista',\n 'admin.moduleNav.title': 'Navegação dos módulos',\n 'admin.moduleNav.rail': 'Barra lateral para os módulos instalados',\n 'admin.moduleNav.tabs': 'Abas para os módulos instalados',\n 'admin.mobileHeader.title': 'Cabeçalho mobile',\n 'admin.mobileHeader.minimal': 'Cabeçalho minimalista',\n 'admin.mobileHeader.transparent': 'Transparente, conteúdo de ponta a ponta',\n 'admin.mobileHeader.hidden': 'Oculto',\n 'admin.branding.title': 'Identidade visual',\n 'admin.branding.on': 'As configurações de marca estão visíveis para operadores',\n 'admin.branding.off': 'As configurações de marca estão ocultas',\n 'admin.readOnlyNotice': 'Pré-visualização somente leitura. A edição por aqui chega em breve — por enquanto essas opções são definidas na configuração do app.',\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const adminLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","import { createPluginContext } from '@fayz-ai/saas'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminUIState } from './store'\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nexport interface AdminPluginLabels {\n pageTitle: string\n pageSubtitle: string\n}\n\n/** Resolved shell config + labels, handed to AdminPage. Mirrors AdminSettingsSnapshot. */\nexport interface ResolvedAdminConfig extends AdminSettingsSnapshot {\n labels: AdminPluginLabels\n}\n\nconst ctx = createPluginContext<ResolvedAdminConfig, AdminDataProvider, AdminUIState>('AdminPage')\n\nexport const AdminContextProvider = ctx.ContextProvider\nexport const useAdminConfig = ctx.useConfig\nexport const useAdminProvider = ctx.useProvider\nexport const useAdminStore = ctx.useStore\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { LayoutTemplate, PanelTop, Settings2, Smartphone, Palette } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { ModulePage } from '@fayz-ai/ui'\nimport { AdminContextProvider, type ResolvedAdminConfig } from './AdminContext'\nimport type { AdminDataProvider } from './data/types'\nimport type { AdminUIState } from './store'\n\nconst LAYOUT_VARIANTS = ['sidebar', 'topbar', 'minimal'] as const\n\nfunction SettingCard({ icon: Icon, title, children }: {\n icon: typeof LayoutTemplate\n title: string\n children: React.ReactNode\n}) {\n return (\n <div className=\"rounded-xl border border-border bg-background/60 p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"h-8 w-8 rounded-lg bg-foreground/[0.04] flex items-center justify-center shrink-0\">\n <Icon className=\"h-4 w-4 text-muted-foreground\" />\n </div>\n <div className=\"text-sm font-medium\">{title}</div>\n </div>\n {children}\n </div>\n )\n}\n\n/**\n * Read-only foundation view. Renders the shell config this app already\n * resolved (layout, module nav, mobile header, branding) so an operator can\n * see it at a glance — it does not yet let them change it. See README.md for\n * the write-path this is scaffolding toward.\n */\nexport function AdminPage({ config, provider, store }: {\n config: ResolvedAdminConfig\n provider: AdminDataProvider\n store: StoreApi<AdminUIState>\n}) {\n const t = useTranslation()\n\n return (\n <AdminContextProvider config={config} provider={provider} store={store}>\n <ModulePage title={config.labels.pageTitle} subtitle={config.labels.pageSubtitle} nav={[]}>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <SettingCard icon={config.layout === 'topbar' ? PanelTop : LayoutTemplate} title={t('admin.layout.title')}>\n <div className=\"flex flex-wrap gap-2 text-sm\">\n {LAYOUT_VARIANTS.map((variant) => (\n <span\n key={variant}\n className={\n 'rounded-md border px-2.5 py-1.5 ' +\n (config.layout === variant\n ? 'border-primary/40 bg-primary/5 text-foreground'\n : 'border-border text-muted-foreground')\n }\n >\n {t(`admin.layout.${variant}`)}\n </span>\n ))}\n </div>\n </SettingCard>\n\n <SettingCard icon={Settings2} title={t('admin.moduleNav.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.moduleNav.${config.moduleNav}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Smartphone} title={t('admin.mobileHeader.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.mobileHeader.${config.mobileHeader}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Palette} title={t('admin.branding.title')}>\n <p className=\"text-xs text-muted-foreground\">\n {config.branding ? t('admin.branding.on') : t('admin.branding.off')}\n </p>\n </SettingCard>\n </div>\n\n <p className=\"mt-6 text-xs text-muted-foreground\">{t('admin.readOnlyNotice')}</p>\n </ModulePage>\n </AdminContextProvider>\n )\n}\n","import React from 'react'\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'\nimport type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminPluginOptions } from './types'\nimport { createMockAdminProvider } from './data/mock'\nimport { createSupabaseAdminProvider } from './data/supabase'\nimport { createAdminStore } from './store'\nimport { adminLocales } from './locales'\nimport { AdminPage } from './AdminPage'\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: AdminPluginLabels = {\n pageTitle: 'Admin',\n pageSubtitle: \"Your app's layout, navigation, and branding.\",\n}\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(options?: AdminPluginOptions): ResolvedAdminConfig {\n return {\n labels: DEFAULT_LABELS,\n layout: options?.layout ?? 'sidebar',\n moduleNav: options?.moduleNav ?? 'tabs',\n mobileHeader: options?.mobileHeader ?? 'minimal',\n navTransition: options?.navTransition ?? 'slide',\n orgSettings: options?.orgSettings ?? true,\n branding: options?.branding ?? true,\n }\n}\n\nfunction toSnapshot(config: ResolvedAdminConfig): AdminSettingsSnapshot {\n const { labels: _labels, ...snapshot } = config\n return snapshot\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAdminPlugin(options?: AdminPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n // Register locales globally so the plugin's translations resolve even when the\n // host shell does not mount @fayz-ai/core's I18nProvider (incremental de-bridge).\n registerTranslations(adminLocales)\n const snapshot = toSnapshot(config)\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseAdminProvider(snapshot),\n () => createMockAdminProvider(snapshot),\n )\n const store = createAdminStore(provider)\n\n const PageComponent: React.FC<unknown> = () =>\n React.createElement(AdminPage, { config, provider, store })\n\n return {\n id: 'admin',\n name: config.labels.pageTitle,\n icon: 'LayoutTemplate',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n // Shell/admin-config is a Panel-side concept (layout, module nav, branding\n // for an admin app) — targets the saas/admin-template world, not the\n // ecommerce storefront. Same declaration plugin-crm uses for its\n // business-ops surface.\n scaffolds: ['saas'],\n defaultEnabled: true,\n dependencies: [],\n declaredFeatures: [\n { id: 'admin', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ],\n\n navigation: [\n {\n section: 'secondary',\n position: 90,\n label: config.labels.pageTitle,\n route: '/admin',\n icon: 'LayoutTemplate',\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/admin',\n component: PageComponent as unknown as React.ComponentType<unknown>,\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n widgets: [],\n\n aiTools: [\n {\n id: 'admin.get-shell-settings',\n name: 'getShellSettings',\n description: 'Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown.',\n icon: 'LayoutTemplate',\n mode: 'read' as const,\n category: 'Admin',\n parameters: {\n type: 'object' as const,\n properties: {},\n },\n suggestions: [\n { label: 'What layout is this app using?' },\n { label: 'Is branding customization on?' },\n ],\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n settings: [],\n\n locales: adminLocales,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nexport type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'\nexport type { AdminPluginOptions } from './types'\n"]}
1
+ {"version":3,"sources":["../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/context.tsx","../src/views/AdminPage.tsx","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Mock provider — returns the statically resolved shell-config snapshot\n * (from plugin options / FayzAppConfig defaults). No in-memory mutation:\n * this plugin doesn't write settings yet.\n */\nexport function createMockAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import type { AdminDataProvider, AdminSettingsSnapshot } from './types'\n\n/**\n * Supabase provider — foundation stub. There is no shell-config table yet:\n * layout/moduleNav/mobileHeader/branding are still owned by FayzAppConfig at\n * build time, not a runtime-editable record. This provider exists so the\n * plugin follows the standard createSafeDataProvider(supabase, mock) seam\n * from day one; it returns the same static snapshot the mock provider does\n * until a real read/write path is wired (see README.md).\n */\nexport function createSupabaseAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {\n return {\n async getSettings() {\n return snapshot\n },\n }\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport { dedup } from '@fayz-ai/admin'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\n\nexport interface AdminUIState {\n settings: AdminSettingsSnapshot | null\n settingsLoading: boolean\n\n fetchSettings(): Promise<void>\n}\n\nexport function createAdminStore(provider: AdminDataProvider): StoreApi<AdminUIState> {\n return createStore<AdminUIState>((set) => ({\n settings: null,\n settingsLoading: false,\n\n async fetchSettings() {\n return dedup('admin:settings', async () => {\n set({ settingsLoading: true })\n try {\n const settings = await provider.getSettings()\n set({ settings, settingsLoading: false })\n } catch {\n set({ settingsLoading: false })\n }\n })\n },\n }))\n}\n","export const en: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Sidebar',\n 'admin.layout.topbar': 'Topbar',\n 'admin.layout.minimal': 'Minimal',\n 'admin.moduleNav.title': 'Module navigation',\n 'admin.moduleNav.rail': 'Side rail for the installed modules',\n 'admin.moduleNav.tabs': 'Tabs for the installed modules',\n 'admin.mobileHeader.title': 'Mobile header',\n 'admin.mobileHeader.minimal': 'Minimal header bar',\n 'admin.mobileHeader.transparent': 'Transparent, edge-to-edge content',\n 'admin.mobileHeader.hidden': 'Hidden',\n 'admin.branding.title': 'Branding',\n 'admin.branding.on': 'Org branding settings are visible to operators',\n 'admin.branding.off': 'Org branding settings are hidden',\n 'admin.readOnlyNotice': 'Read-only preview. Editing these settings here is coming soon — for now they are set in your app config.',\n}\n","export const ptBR: Record<string, string> = {\n 'admin.layout.title': 'Layout',\n 'admin.layout.sidebar': 'Barra lateral',\n 'admin.layout.topbar': 'Barra superior',\n 'admin.layout.minimal': 'Minimalista',\n 'admin.moduleNav.title': 'Navegação dos módulos',\n 'admin.moduleNav.rail': 'Barra lateral para os módulos instalados',\n 'admin.moduleNav.tabs': 'Abas para os módulos instalados',\n 'admin.mobileHeader.title': 'Cabeçalho mobile',\n 'admin.mobileHeader.minimal': 'Cabeçalho minimalista',\n 'admin.mobileHeader.transparent': 'Transparente, conteúdo de ponta a ponta',\n 'admin.mobileHeader.hidden': 'Oculto',\n 'admin.branding.title': 'Identidade visual',\n 'admin.branding.on': 'As configurações de marca estão visíveis para operadores',\n 'admin.branding.off': 'As configurações de marca estão ocultas',\n 'admin.readOnlyNotice': 'Pré-visualização somente leitura. A edição por aqui chega em breve — por enquanto essas opções são definidas na configuração do app.',\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const adminLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","import { createPluginContext } from '@fayz-ai/admin'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminUIState } from './store'\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nexport interface AdminPluginLabels {\n pageTitle: string\n pageSubtitle: string\n}\n\n/** Resolved shell config + labels, handed to AdminPage. Mirrors AdminSettingsSnapshot. */\nexport interface ResolvedAdminConfig extends AdminSettingsSnapshot {\n labels: AdminPluginLabels\n}\n\nconst ctx = createPluginContext<ResolvedAdminConfig, AdminDataProvider, AdminUIState>('AdminPage')\n\nexport const AdminContextProvider = ctx.ContextProvider\nexport const useAdminConfig = ctx.useConfig\nexport const useAdminProvider = ctx.useProvider\nexport const useAdminStore = ctx.useStore\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { LayoutTemplate, PanelTop, Settings2, Smartphone, Palette } from 'lucide-react'\nimport { useTranslation } from '@fayz-ai/core'\nimport { ModulePage } from '@fayz-ai/ui'\nimport { AdminContextProvider, type ResolvedAdminConfig } from '../context'\nimport type { AdminDataProvider } from '../data/types'\nimport type { AdminUIState } from '../store'\n\nconst LAYOUT_VARIANTS = ['sidebar', 'topbar', 'minimal'] as const\n\nfunction SettingCard({ icon: Icon, title, children }: {\n icon: typeof LayoutTemplate\n title: string\n children: React.ReactNode\n}) {\n return (\n <div className=\"rounded-xl border border-border bg-background/60 p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <div className=\"h-8 w-8 rounded-lg bg-foreground/[0.04] flex items-center justify-center shrink-0\">\n <Icon className=\"h-4 w-4 text-muted-foreground\" />\n </div>\n <div className=\"text-sm font-medium\">{title}</div>\n </div>\n {children}\n </div>\n )\n}\n\n/**\n * Read-only foundation view. Renders the shell config this app already\n * resolved (layout, module nav, mobile header, branding) so an operator can\n * see it at a glance — it does not yet let them change it. See README.md for\n * the write-path this is scaffolding toward.\n */\nexport function AdminPage({ config, provider, store }: {\n config: ResolvedAdminConfig\n provider: AdminDataProvider\n store: StoreApi<AdminUIState>\n}) {\n const t = useTranslation()\n\n return (\n <AdminContextProvider config={config} provider={provider} store={store}>\n <ModulePage title={config.labels.pageTitle} subtitle={config.labels.pageSubtitle} nav={[]}>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <SettingCard icon={config.layout === 'topbar' ? PanelTop : LayoutTemplate} title={t('admin.layout.title')}>\n <div className=\"flex flex-wrap gap-2 text-sm\">\n {LAYOUT_VARIANTS.map((variant) => (\n <span\n key={variant}\n className={\n 'rounded-md border px-2.5 py-1.5 ' +\n (config.layout === variant\n ? 'border-primary/40 bg-primary/5 text-foreground'\n : 'border-border text-muted-foreground')\n }\n >\n {t(`admin.layout.${variant}`)}\n </span>\n ))}\n </div>\n </SettingCard>\n\n <SettingCard icon={Settings2} title={t('admin.moduleNav.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.moduleNav.${config.moduleNav}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Smartphone} title={t('admin.mobileHeader.title')}>\n <p className=\"text-xs text-muted-foreground\">{t(`admin.mobileHeader.${config.mobileHeader}`)}</p>\n </SettingCard>\n\n <SettingCard icon={Palette} title={t('admin.branding.title')}>\n <p className=\"text-xs text-muted-foreground\">\n {config.branding ? t('admin.branding.on') : t('admin.branding.off')}\n </p>\n </SettingCard>\n </div>\n\n <p className=\"mt-6 text-xs text-muted-foreground\">{t('admin.readOnlyNotice')}</p>\n </ModulePage>\n </AdminContextProvider>\n )\n}\n","import React from 'react'\nimport type { PluginManifest } from '@fayz-ai/core'\nimport { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'\nimport type { ResolvedAdminConfig, AdminPluginLabels } from './context'\nimport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nimport type { AdminPluginOptions } from './types'\nimport { createMockAdminProvider } from './data/mock'\nimport { createSupabaseAdminProvider } from './data/supabase'\nimport { createAdminStore } from './store'\nimport { adminLocales } from './locales'\nimport { AdminPage } from './views/AdminPage'\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_LABELS: AdminPluginLabels = {\n pageTitle: 'Admin',\n pageSubtitle: \"Your app's layout, navigation, and branding.\",\n}\n\n// ---------------------------------------------------------------------------\n// Config resolver\n// ---------------------------------------------------------------------------\n\nfunction resolveConfig(options?: AdminPluginOptions): ResolvedAdminConfig {\n return {\n labels: DEFAULT_LABELS,\n layout: options?.layout ?? 'sidebar',\n moduleNav: options?.moduleNav ?? 'tabs',\n mobileHeader: options?.mobileHeader ?? 'minimal',\n navTransition: options?.navTransition ?? 'slide',\n orgSettings: options?.orgSettings ?? true,\n branding: options?.branding ?? true,\n }\n}\n\nfunction toSnapshot(config: ResolvedAdminConfig): AdminSettingsSnapshot {\n const { labels: _labels, ...snapshot } = config\n return snapshot\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAdminPlugin(options?: AdminPluginOptions): PluginManifest {\n const config = resolveConfig(options)\n // Register locales globally so the plugin's translations resolve even when the\n // host shell does not mount @fayz-ai/core's I18nProvider (incremental de-bridge).\n registerTranslations(adminLocales)\n const snapshot = toSnapshot(config)\n const provider = options?.dataProvider ?? createSafeDataProvider(\n () => createSupabaseAdminProvider(snapshot),\n () => createMockAdminProvider(snapshot),\n )\n const store = createAdminStore(provider)\n\n const PageComponent: React.FC<unknown> = () =>\n React.createElement(AdminPage, { config, provider, store })\n\n return {\n id: 'admin',\n name: config.labels.pageTitle,\n icon: 'LayoutTemplate',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n // Shell/admin-config is a Panel-side concept (layout, module nav, branding\n // for an admin app) — targets the saas/admin-template world, not the\n // ecommerce storefront. Same declaration plugin-crm uses for its\n // business-ops surface.\n scaffolds: ['saas'],\n defaultEnabled: true,\n dependencies: [],\n declaredFeatures: [\n { id: 'admin', label: config.labels.pageTitle, group: config.labels.pageTitle },\n ],\n\n navigation: [\n {\n section: 'secondary',\n position: 90,\n label: config.labels.pageTitle,\n route: '/admin',\n icon: 'LayoutTemplate',\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n routes: [\n {\n path: '/admin',\n component: PageComponent as unknown as React.ComponentType<unknown>,\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n widgets: [],\n\n aiTools: [\n {\n id: 'admin.get-shell-settings',\n name: 'getShellSettings',\n description: 'Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown.',\n icon: 'LayoutTemplate',\n mode: 'read' as const,\n category: 'Admin',\n parameters: {\n type: 'object' as const,\n properties: {},\n },\n suggestions: [\n { label: 'What layout is this app using?' },\n { label: 'Is branding customization on?' },\n ],\n permission: { feature: 'admin', action: 'read' as const },\n },\n ],\n\n settings: [],\n\n locales: adminLocales,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'\nexport type { ResolvedAdminConfig, AdminPluginLabels } from './context'\nexport type { AdminPluginOptions } from './types'\n"]}
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  import type { StoreApi } from 'zustand/vanilla';
3
- import { type ResolvedAdminConfig } from './AdminContext';
4
- import type { AdminDataProvider } from './data/types';
5
- import type { AdminUIState } from './store';
3
+ import { type ResolvedAdminConfig } from '../context';
4
+ import type { AdminDataProvider } from '../data/types';
5
+ import type { AdminUIState } from '../store';
6
6
  /**
7
7
  * Read-only foundation view. Renders the shell config this app already
8
8
  * resolved (layout, module nav, mobile header, branding) so an operator can
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminPage.d.ts","sourceRoot":"","sources":["../../src/views/AdminPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI/C,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAC3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAsB5C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACrD,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;CAC9B,qBA4CA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fayz-ai/plugin-admin",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "[experimental] Fayz SDK — admin shell settings plugin (read-only foundation)",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -9,34 +9,32 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "exports": {
11
11
  ".": {
12
- "source": "./src/index.ts",
13
12
  "types": "./dist/index.d.ts",
14
13
  "import": "./dist/index.js"
15
14
  }
16
15
  },
17
16
  "files": [
18
- "dist",
19
- "src"
17
+ "dist"
20
18
  ],
21
19
  "peerDependencies": {
20
+ "lucide-react": ">=0.400.0 <1.0.0",
22
21
  "react": "^18.0.0 || ^19.0.0",
23
22
  "react-dom": "^18.0.0 || ^19.0.0",
24
- "zustand": "^4.5.0 || ^5.0.0",
25
- "lucide-react": ">=0.400.0 <1.0.0"
23
+ "zustand": "^4.5.0 || ^5.0.0"
26
24
  },
27
25
  "dependencies": {
28
- "@fayz-ai/saas": "^0.9.0",
29
- "@fayz-ai/ui": "^0.9.0",
30
- "@fayz-ai/core": "^0.9.0"
26
+ "@fayz-ai/admin": "^0.11.0",
27
+ "@fayz-ai/core": "^0.11.0",
28
+ "@fayz-ai/ui": "^0.11.0"
31
29
  },
32
30
  "devDependencies": {
33
31
  "@types/react": "^18.3.0",
32
+ "lucide-react": "^0.400.0",
34
33
  "react": "^18.3.0",
35
34
  "tsup": "^8.2.0",
36
35
  "typescript": "^5.5.0",
37
36
  "vitest": "^4.1.5",
38
- "zustand": "^4.5.0",
39
- "lucide-react": "^0.400.0"
37
+ "zustand": "^4.5.0"
40
38
  },
41
39
  "license": "MIT",
42
40
  "keywords": [
@@ -47,7 +45,7 @@
47
45
  "scripts": {
48
46
  "build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap --noEmit false",
49
47
  "dev": "tsup --watch",
50
- "typecheck": "tsc --noEmit",
48
+ "typecheck": "tsc --noEmit -p tsconfig.test.json",
51
49
  "test": "vitest run",
52
50
  "clean": "rm -rf dist"
53
51
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"AdminContext.d.ts","sourceRoot":"","sources":["../src/AdminContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAM3C,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,0FAA0F;AAC1F,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAID,eAAO,MAAM,oBAAoB;;;;;EAAsB,CAAA;AACvD,eAAO,MAAM,cAAc,2BAAgB,CAAA;AAC3C,eAAO,MAAM,gBAAgB,yBAAkB,CAAA;AAC/C,eAAO,MAAM,aAAa,gDAAe,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"AdminPage.d.ts","sourceRoot":"","sources":["../src/AdminPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAI/C,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAsB3C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACrD,MAAM,EAAE,mBAAmB,CAAA;IAC3B,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAA;CAC9B,qBA4CA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=contract.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract.test.d.ts","sourceRoot":"","sources":["../src/contract.test.ts"],"names":[],"mappings":""}
@@ -1,24 +0,0 @@
1
- import { createPluginContext } from '@fayz-ai/saas'
2
- import type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'
3
- import type { AdminUIState } from './store'
4
-
5
- // ---------------------------------------------------------------------------
6
- // Config
7
- // ---------------------------------------------------------------------------
8
-
9
- export interface AdminPluginLabels {
10
- pageTitle: string
11
- pageSubtitle: string
12
- }
13
-
14
- /** Resolved shell config + labels, handed to AdminPage. Mirrors AdminSettingsSnapshot. */
15
- export interface ResolvedAdminConfig extends AdminSettingsSnapshot {
16
- labels: AdminPluginLabels
17
- }
18
-
19
- const ctx = createPluginContext<ResolvedAdminConfig, AdminDataProvider, AdminUIState>('AdminPage')
20
-
21
- export const AdminContextProvider = ctx.ContextProvider
22
- export const useAdminConfig = ctx.useConfig
23
- export const useAdminProvider = ctx.useProvider
24
- export const useAdminStore = ctx.useStore
package/src/AdminPage.tsx DELETED
@@ -1,84 +0,0 @@
1
- import React from 'react'
2
- import type { StoreApi } from 'zustand/vanilla'
3
- import { LayoutTemplate, PanelTop, Settings2, Smartphone, Palette } from 'lucide-react'
4
- import { useTranslation } from '@fayz-ai/core'
5
- import { ModulePage } from '@fayz-ai/ui'
6
- import { AdminContextProvider, type ResolvedAdminConfig } from './AdminContext'
7
- import type { AdminDataProvider } from './data/types'
8
- import type { AdminUIState } from './store'
9
-
10
- const LAYOUT_VARIANTS = ['sidebar', 'topbar', 'minimal'] as const
11
-
12
- function SettingCard({ icon: Icon, title, children }: {
13
- icon: typeof LayoutTemplate
14
- title: string
15
- children: React.ReactNode
16
- }) {
17
- return (
18
- <div className="rounded-xl border border-border bg-background/60 p-4">
19
- <div className="flex items-center gap-2 mb-2">
20
- <div className="h-8 w-8 rounded-lg bg-foreground/[0.04] flex items-center justify-center shrink-0">
21
- <Icon className="h-4 w-4 text-muted-foreground" />
22
- </div>
23
- <div className="text-sm font-medium">{title}</div>
24
- </div>
25
- {children}
26
- </div>
27
- )
28
- }
29
-
30
- /**
31
- * Read-only foundation view. Renders the shell config this app already
32
- * resolved (layout, module nav, mobile header, branding) so an operator can
33
- * see it at a glance — it does not yet let them change it. See README.md for
34
- * the write-path this is scaffolding toward.
35
- */
36
- export function AdminPage({ config, provider, store }: {
37
- config: ResolvedAdminConfig
38
- provider: AdminDataProvider
39
- store: StoreApi<AdminUIState>
40
- }) {
41
- const t = useTranslation()
42
-
43
- return (
44
- <AdminContextProvider config={config} provider={provider} store={store}>
45
- <ModulePage title={config.labels.pageTitle} subtitle={config.labels.pageSubtitle} nav={[]}>
46
- <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
47
- <SettingCard icon={config.layout === 'topbar' ? PanelTop : LayoutTemplate} title={t('admin.layout.title')}>
48
- <div className="flex flex-wrap gap-2 text-sm">
49
- {LAYOUT_VARIANTS.map((variant) => (
50
- <span
51
- key={variant}
52
- className={
53
- 'rounded-md border px-2.5 py-1.5 ' +
54
- (config.layout === variant
55
- ? 'border-primary/40 bg-primary/5 text-foreground'
56
- : 'border-border text-muted-foreground')
57
- }
58
- >
59
- {t(`admin.layout.${variant}`)}
60
- </span>
61
- ))}
62
- </div>
63
- </SettingCard>
64
-
65
- <SettingCard icon={Settings2} title={t('admin.moduleNav.title')}>
66
- <p className="text-xs text-muted-foreground">{t(`admin.moduleNav.${config.moduleNav}`)}</p>
67
- </SettingCard>
68
-
69
- <SettingCard icon={Smartphone} title={t('admin.mobileHeader.title')}>
70
- <p className="text-xs text-muted-foreground">{t(`admin.mobileHeader.${config.mobileHeader}`)}</p>
71
- </SettingCard>
72
-
73
- <SettingCard icon={Palette} title={t('admin.branding.title')}>
74
- <p className="text-xs text-muted-foreground">
75
- {config.branding ? t('admin.branding.on') : t('admin.branding.off')}
76
- </p>
77
- </SettingCard>
78
- </div>
79
-
80
- <p className="mt-6 text-xs text-muted-foreground">{t('admin.readOnlyNotice')}</p>
81
- </ModulePage>
82
- </AdminContextProvider>
83
- )
84
- }
@@ -1,40 +0,0 @@
1
- // Integrity test for plugin-admin's manifest shape, using the shared assertion
2
- // from @fayz-ai/core/testing (no UI import — pure, inline manifest, per
3
- // docs/PLUGIN-PATTERNS.md → integrity). Mirrors plugin-financial/src/contract.test.ts.
4
- import { describe, it, expect } from 'vitest'
5
- import { assertPluginManifestContract, PluginContractError } from '@fayz-ai/core/testing'
6
- import type { PluginManifest } from '@fayz-ai/core'
7
-
8
- const Dummy = () => null
9
-
10
- function manifest(overrides: Partial<PluginManifest> = {}): PluginManifest {
11
- return {
12
- id: 'admin',
13
- name: 'Admin',
14
- icon: 'LayoutTemplate',
15
- version: '1.0.0',
16
- navigation: [{ section: 'secondary', position: 90, label: 'Admin', route: '/admin', icon: 'LayoutTemplate' } as any],
17
- routes: [{ path: '/admin', component: Dummy } as any],
18
- ...overrides,
19
- }
20
- }
21
-
22
- describe('plugin-admin · assertPluginManifestContract', () => {
23
- it('passes the real manifest shape (nav route matches declared route)', () => {
24
- expect(() => assertPluginManifestContract(manifest())).not.toThrow()
25
- })
26
-
27
- it('rejects a missing id', () => {
28
- expect(() => assertPluginManifestContract(manifest({ id: '' }))).toThrow(PluginContractError)
29
- })
30
-
31
- it('rejects a nav entry pointing at an undeclared route', () => {
32
- expect(() => assertPluginManifestContract(manifest({
33
- navigation: [{ section: 'secondary', position: 90, label: 'Admin', route: '/nowhere', icon: 'LayoutTemplate' } as any],
34
- }))).toThrow(/no matching route/)
35
- })
36
-
37
- it('rejects a plugin that contributes nothing mountable', () => {
38
- expect(() => assertPluginManifestContract(manifest({ navigation: [], routes: [], settings: [] }))).toThrow(/nothing/)
39
- })
40
- })
@@ -1,30 +0,0 @@
1
- // Capability test — proves the data slice end-to-end against the mock
2
- // provider, per docs/PLUGIN-PATTERNS.md → capability anatomy. plugin-admin is
3
- // a read-only foundation (no writes yet): the slice to prove is that the
4
- // resolved shell-config snapshot round-trips through the provider unchanged,
5
- // and that both mock and supabase stubs honor the same contract.
6
- import { describe, it, expect } from 'vitest'
7
- import { createMockAdminProvider } from './mock'
8
- import { createSupabaseAdminProvider } from './supabase'
9
- import type { AdminSettingsSnapshot } from './types'
10
-
11
- const SNAPSHOT: AdminSettingsSnapshot = {
12
- layout: 'topbar',
13
- moduleNav: 'rail',
14
- mobileHeader: 'transparent',
15
- navTransition: 'fade',
16
- orgSettings: false,
17
- branding: true,
18
- }
19
-
20
- describe('plugin-admin capability · data slice', () => {
21
- it('mock provider surfaces the resolved snapshot as-is', async () => {
22
- const provider = createMockAdminProvider(SNAPSHOT)
23
- expect(await provider.getSettings()).toEqual(SNAPSHOT)
24
- })
25
-
26
- it('supabase stub provider honors the same contract (no backend table yet)', async () => {
27
- const provider = createSupabaseAdminProvider(SNAPSHOT)
28
- expect(await provider.getSettings()).toEqual(SNAPSHOT)
29
- })
30
- })
package/src/data/mock.ts DELETED
@@ -1,14 +0,0 @@
1
- import type { AdminDataProvider, AdminSettingsSnapshot } from './types'
2
-
3
- /**
4
- * Mock provider — returns the statically resolved shell-config snapshot
5
- * (from plugin options / FayzAppConfig defaults). No in-memory mutation:
6
- * this plugin doesn't write settings yet.
7
- */
8
- export function createMockAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {
9
- return {
10
- async getSettings() {
11
- return snapshot
12
- },
13
- }
14
- }
@@ -1,17 +0,0 @@
1
- import type { AdminDataProvider, AdminSettingsSnapshot } from './types'
2
-
3
- /**
4
- * Supabase provider — foundation stub. There is no shell-config table yet:
5
- * layout/moduleNav/mobileHeader/branding are still owned by FayzAppConfig at
6
- * build time, not a runtime-editable record. This provider exists so the
7
- * plugin follows the standard createSafeDataProvider(supabase, mock) seam
8
- * from day one; it returns the same static snapshot the mock provider does
9
- * until a real read/write path is wired (see README.md).
10
- */
11
- export function createSupabaseAdminProvider(snapshot: AdminSettingsSnapshot): AdminDataProvider {
12
- return {
13
- async getSettings() {
14
- return snapshot
15
- },
16
- }
17
- }
package/src/data/types.ts DELETED
@@ -1,20 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Admin Plugin — Data Provider
3
- // ---------------------------------------------------------------------------
4
- // A snapshot of the app's shell config, resolved once at plugin creation. This
5
- // is a read-only reflection today, not a persisted, editable record — see the
6
- // module doc comment in ../types.ts.
7
- // ---------------------------------------------------------------------------
8
-
9
- export interface AdminSettingsSnapshot {
10
- layout: 'sidebar' | 'topbar' | 'minimal'
11
- moduleNav: 'rail' | 'tabs'
12
- mobileHeader: 'minimal' | 'transparent' | 'hidden'
13
- navTransition: 'slide' | 'fade' | 'none'
14
- orgSettings: boolean
15
- branding: boolean
16
- }
17
-
18
- export interface AdminDataProvider {
19
- getSettings(): Promise<AdminSettingsSnapshot>
20
- }
package/src/index.ts DELETED
@@ -1,133 +0,0 @@
1
- import React from 'react'
2
- import type { PluginManifest } from '@fayz-ai/core'
3
- import { createSafeDataProvider, registerTranslations } from '@fayz-ai/core'
4
- import type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'
5
- import type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'
6
- import type { AdminPluginOptions } from './types'
7
- import { createMockAdminProvider } from './data/mock'
8
- import { createSupabaseAdminProvider } from './data/supabase'
9
- import { createAdminStore } from './store'
10
- import { adminLocales } from './locales'
11
- import { AdminPage } from './AdminPage'
12
-
13
- // ---------------------------------------------------------------------------
14
- // Defaults
15
- // ---------------------------------------------------------------------------
16
-
17
- const DEFAULT_LABELS: AdminPluginLabels = {
18
- pageTitle: 'Admin',
19
- pageSubtitle: "Your app's layout, navigation, and branding.",
20
- }
21
-
22
- // ---------------------------------------------------------------------------
23
- // Config resolver
24
- // ---------------------------------------------------------------------------
25
-
26
- function resolveConfig(options?: AdminPluginOptions): ResolvedAdminConfig {
27
- return {
28
- labels: DEFAULT_LABELS,
29
- layout: options?.layout ?? 'sidebar',
30
- moduleNav: options?.moduleNav ?? 'tabs',
31
- mobileHeader: options?.mobileHeader ?? 'minimal',
32
- navTransition: options?.navTransition ?? 'slide',
33
- orgSettings: options?.orgSettings ?? true,
34
- branding: options?.branding ?? true,
35
- }
36
- }
37
-
38
- function toSnapshot(config: ResolvedAdminConfig): AdminSettingsSnapshot {
39
- const { labels: _labels, ...snapshot } = config
40
- return snapshot
41
- }
42
-
43
- // ---------------------------------------------------------------------------
44
- // Factory
45
- // ---------------------------------------------------------------------------
46
-
47
- export function createAdminPlugin(options?: AdminPluginOptions): PluginManifest {
48
- const config = resolveConfig(options)
49
- // Register locales globally so the plugin's translations resolve even when the
50
- // host shell does not mount @fayz-ai/core's I18nProvider (incremental de-bridge).
51
- registerTranslations(adminLocales)
52
- const snapshot = toSnapshot(config)
53
- const provider = options?.dataProvider ?? createSafeDataProvider(
54
- () => createSupabaseAdminProvider(snapshot),
55
- () => createMockAdminProvider(snapshot),
56
- )
57
- const store = createAdminStore(provider)
58
-
59
- const PageComponent: React.FC<unknown> = () =>
60
- React.createElement(AdminPage, { config, provider, store })
61
-
62
- return {
63
- id: 'admin',
64
- name: config.labels.pageTitle,
65
- icon: 'LayoutTemplate',
66
- version: '1.0.0',
67
- scope: options?.scope ?? 'universal',
68
- verticalId: options?.verticalId,
69
- // Shell/admin-config is a Panel-side concept (layout, module nav, branding
70
- // for an admin app) — targets the saas/admin-template world, not the
71
- // ecommerce storefront. Same declaration plugin-crm uses for its
72
- // business-ops surface.
73
- scaffolds: ['saas'],
74
- defaultEnabled: true,
75
- dependencies: [],
76
- declaredFeatures: [
77
- { id: 'admin', label: config.labels.pageTitle, group: config.labels.pageTitle },
78
- ],
79
-
80
- navigation: [
81
- {
82
- section: 'secondary',
83
- position: 90,
84
- label: config.labels.pageTitle,
85
- route: '/admin',
86
- icon: 'LayoutTemplate',
87
- permission: { feature: 'admin', action: 'read' as const },
88
- },
89
- ],
90
-
91
- routes: [
92
- {
93
- path: '/admin',
94
- component: PageComponent as unknown as React.ComponentType<unknown>,
95
- permission: { feature: 'admin', action: 'read' as const },
96
- },
97
- ],
98
-
99
- widgets: [],
100
-
101
- aiTools: [
102
- {
103
- id: 'admin.get-shell-settings',
104
- name: 'getShellSettings',
105
- description: 'Returns the app shell configuration: layout variant, module nav style, mobile header treatment, and whether org/branding settings are shown.',
106
- icon: 'LayoutTemplate',
107
- mode: 'read' as const,
108
- category: 'Admin',
109
- parameters: {
110
- type: 'object' as const,
111
- properties: {},
112
- },
113
- suggestions: [
114
- { label: 'What layout is this app using?' },
115
- { label: 'Is branding customization on?' },
116
- ],
117
- permission: { feature: 'admin', action: 'read' as const },
118
- },
119
- ],
120
-
121
- settings: [],
122
-
123
- locales: adminLocales,
124
- }
125
- }
126
-
127
- // ---------------------------------------------------------------------------
128
- // Re-exports
129
- // ---------------------------------------------------------------------------
130
-
131
- export type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'
132
- export type { ResolvedAdminConfig, AdminPluginLabels } from './AdminContext'
133
- export type { AdminPluginOptions } from './types'
package/src/locales/en.ts DELETED
@@ -1,17 +0,0 @@
1
- export const en: Record<string, string> = {
2
- 'admin.layout.title': 'Layout',
3
- 'admin.layout.sidebar': 'Sidebar',
4
- 'admin.layout.topbar': 'Topbar',
5
- 'admin.layout.minimal': 'Minimal',
6
- 'admin.moduleNav.title': 'Module navigation',
7
- 'admin.moduleNav.rail': 'Side rail for the installed modules',
8
- 'admin.moduleNav.tabs': 'Tabs for the installed modules',
9
- 'admin.mobileHeader.title': 'Mobile header',
10
- 'admin.mobileHeader.minimal': 'Minimal header bar',
11
- 'admin.mobileHeader.transparent': 'Transparent, edge-to-edge content',
12
- 'admin.mobileHeader.hidden': 'Hidden',
13
- 'admin.branding.title': 'Branding',
14
- 'admin.branding.on': 'Org branding settings are visible to operators',
15
- 'admin.branding.off': 'Org branding settings are hidden',
16
- 'admin.readOnlyNotice': 'Read-only preview. Editing these settings here is coming soon — for now they are set in your app config.',
17
- }
@@ -1,7 +0,0 @@
1
- import { en } from './en'
2
- import { ptBR } from './pt-BR'
3
-
4
- export const adminLocales: Record<string, Record<string, string>> = {
5
- en,
6
- 'pt-BR': ptBR,
7
- }
@@ -1,17 +0,0 @@
1
- export const ptBR: Record<string, string> = {
2
- 'admin.layout.title': 'Layout',
3
- 'admin.layout.sidebar': 'Barra lateral',
4
- 'admin.layout.topbar': 'Barra superior',
5
- 'admin.layout.minimal': 'Minimalista',
6
- 'admin.moduleNav.title': 'Navegação dos módulos',
7
- 'admin.moduleNav.rail': 'Barra lateral para os módulos instalados',
8
- 'admin.moduleNav.tabs': 'Abas para os módulos instalados',
9
- 'admin.mobileHeader.title': 'Cabeçalho mobile',
10
- 'admin.mobileHeader.minimal': 'Cabeçalho minimalista',
11
- 'admin.mobileHeader.transparent': 'Transparente, conteúdo de ponta a ponta',
12
- 'admin.mobileHeader.hidden': 'Oculto',
13
- 'admin.branding.title': 'Identidade visual',
14
- 'admin.branding.on': 'As configurações de marca estão visíveis para operadores',
15
- 'admin.branding.off': 'As configurações de marca estão ocultas',
16
- 'admin.readOnlyNotice': 'Pré-visualização somente leitura. A edição por aqui chega em breve — por enquanto essas opções são definidas na configuração do app.',
17
- }
package/src/store.ts DELETED
@@ -1,29 +0,0 @@
1
- import { createStore, type StoreApi } from 'zustand/vanilla'
2
- import { dedup } from '@fayz-ai/saas'
3
- import type { AdminDataProvider, AdminSettingsSnapshot } from './data/types'
4
-
5
- export interface AdminUIState {
6
- settings: AdminSettingsSnapshot | null
7
- settingsLoading: boolean
8
-
9
- fetchSettings(): Promise<void>
10
- }
11
-
12
- export function createAdminStore(provider: AdminDataProvider): StoreApi<AdminUIState> {
13
- return createStore<AdminUIState>((set) => ({
14
- settings: null,
15
- settingsLoading: false,
16
-
17
- async fetchSettings() {
18
- return dedup('admin:settings', async () => {
19
- set({ settingsLoading: true })
20
- try {
21
- const settings = await provider.getSettings()
22
- set({ settings, settingsLoading: false })
23
- } catch {
24
- set({ settingsLoading: false })
25
- }
26
- })
27
- },
28
- }))
29
- }
package/src/types.ts DELETED
@@ -1,35 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Admin Plugin — Options
3
- // ---------------------------------------------------------------------------
4
- // These fields surface the app's existing shell config (FayzAppConfig in
5
- // @fayz-ai/saas — see packages/saas/src/app/config.ts): layout, moduleNav,
6
- // mobileHeader, navTransition, orgSettings, and branding. They do not
7
- // introduce a new config shape — this plugin only reflects what's already
8
- // resolved at `defineSaas` time. There is no runtime write path yet: see
9
- // README.md for the follow-up.
10
- // ---------------------------------------------------------------------------
11
-
12
- import type { PluginScope, VerticalId } from '@fayz-ai/core'
13
- import type { AdminDataProvider } from './data/types'
14
-
15
- export interface AdminPluginOptions {
16
- /** Shell layout variant (mirrors FayzAppConfig.layout). Default: 'sidebar'. */
17
- layout?: 'sidebar' | 'topbar' | 'minimal'
18
- /** How module-internal navigation renders (mirrors FayzAppConfig.moduleNav). Default: 'tabs'. */
19
- moduleNav?: 'rail' | 'tabs'
20
- /** Mobile header treatment (mirrors FayzAppConfig.mobileHeader). Default: 'minimal'. */
21
- mobileHeader?: 'minimal' | 'transparent' | 'hidden'
22
- /** Page navigation animation (mirrors FayzAppConfig.navTransition). Default: 'slide'. */
23
- navTransition?: 'slide' | 'fade' | 'none'
24
- /** Show org-level settings tabs (mirrors FayzAppConfig.orgSettings). Default: true. */
25
- orgSettings?: boolean
26
- /** Show branding/company settings tabs (mirrors FayzAppConfig.branding). Default: true. */
27
- branding?: boolean
28
-
29
- /** Plugin scope */
30
- scope?: PluginScope
31
- /** Vertical ID */
32
- verticalId?: VerticalId
33
- /** Data provider override (defaults to safe auto-selection) */
34
- dataProvider?: AdminDataProvider
35
- }