@fayz-ai/plugin-admin 0.1.0

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/AdminContext.d.ts +20 -0
  4. package/dist/AdminContext.d.ts.map +1 -0
  5. package/dist/AdminPage.d.ts +17 -0
  6. package/dist/AdminPage.d.ts.map +1 -0
  7. package/dist/contract.test.d.ts +2 -0
  8. package/dist/contract.test.d.ts.map +1 -0
  9. package/dist/data/capability.test.d.ts +2 -0
  10. package/dist/data/capability.test.d.ts.map +1 -0
  11. package/dist/data/mock.d.ts +8 -0
  12. package/dist/data/mock.d.ts.map +1 -0
  13. package/dist/data/supabase.d.ts +11 -0
  14. package/dist/data/supabase.d.ts.map +1 -0
  15. package/dist/data/types.d.ts +12 -0
  16. package/dist/data/types.d.ts.map +1 -0
  17. package/dist/index.cjs +221 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +215 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/locales/en.d.ts +2 -0
  24. package/dist/locales/en.d.ts.map +1 -0
  25. package/dist/locales/index.d.ts +2 -0
  26. package/dist/locales/index.d.ts.map +1 -0
  27. package/dist/locales/pt-BR.d.ts +2 -0
  28. package/dist/locales/pt-BR.d.ts.map +1 -0
  29. package/dist/store.d.ts +9 -0
  30. package/dist/store.d.ts.map +1 -0
  31. package/dist/types.d.ts +23 -0
  32. package/dist/types.d.ts.map +1 -0
  33. package/package.json +52 -0
  34. package/src/AdminContext.tsx +24 -0
  35. package/src/AdminPage.tsx +84 -0
  36. package/src/contract.test.ts +40 -0
  37. package/src/data/capability.test.ts +30 -0
  38. package/src/data/mock.ts +14 -0
  39. package/src/data/supabase.ts +17 -0
  40. package/src/data/types.ts +20 -0
  41. package/src/index.ts +133 -0
  42. package/src/locales/en.ts +17 -0
  43. package/src/locales/index.ts +7 -0
  44. package/src/locales/pt-BR.ts +17 -0
  45. package/src/store.ts +29 -0
  46. package/src/types.ts +35 -0
package/src/index.ts ADDED
@@ -0,0 +1,133 @@
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'
@@ -0,0 +1,17 @@
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
+ }
@@ -0,0 +1,7 @@
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
+ }
@@ -0,0 +1,17 @@
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 ADDED
@@ -0,0 +1,29 @@
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 ADDED
@@ -0,0 +1,35 @@
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
+ }