@ramme-io/create-app 1.2.0 → 1.2.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.
Files changed (92) hide show
  1. package/package.json +1 -2
  2. package/template/package.json +41 -0
  3. package/template/pkg.json +1 -1
  4. package/template/src/App.tsx +65 -35
  5. package/template/src/components/AIChatWidget.tsx +2 -2
  6. package/template/src/components/AppHeader.tsx +2 -2
  7. package/template/src/components/AutoForm.tsx +13 -0
  8. package/template/src/{pages/styleguide → components}/NotFound.tsx +1 -1
  9. package/template/src/components/PageTitleUpdater.tsx +2 -2
  10. package/template/src/components/ProtectedRoute.tsx +18 -1
  11. package/template/src/components/ScrollToTop.tsx +19 -0
  12. package/template/src/config/app.manifest.ts +3 -1
  13. package/template/src/{core → config}/component-registry.tsx +1 -1
  14. package/template/src/config/navigation.ts +1 -1
  15. package/template/src/data/mock-charts.ts +32 -28
  16. package/template/src/{components → engine/renderers}/DynamicBlock.tsx +27 -7
  17. package/template/src/{pages → engine/renderers}/DynamicPage.tsx +23 -4
  18. package/template/src/{contexts → engine/runtime}/MqttContext.tsx +25 -11
  19. package/template/src/{contexts → engine/runtime}/SitemapContext.tsx +1 -1
  20. package/template/src/{core → engine/runtime}/data-seeder.ts +15 -5
  21. package/template/src/{hooks → engine/runtime}/useAction.ts +19 -8
  22. package/template/src/{hooks → engine/runtime}/useCrudLocalStorage.ts +27 -8
  23. package/template/src/{hooks → engine/runtime}/useDataQuery.ts +15 -1
  24. package/template/src/engine/runtime/useSignal.ts +51 -0
  25. package/template/src/engine/runtime/useSignalStore.ts +94 -0
  26. package/template/src/engine/runtime/useWorkflowEngine.ts +144 -0
  27. package/template/src/{core → engine/types}/manifest-types.ts +35 -3
  28. package/template/src/{types → engine/validation}/schema.ts +53 -2
  29. package/template/src/{pages → features/ai/pages}/AiChat.tsx +1 -1
  30. package/template/src/features/auth/AuthContext.tsx +118 -0
  31. package/template/src/features/auth/pages/AuthLayout.tsx +55 -0
  32. package/template/src/features/auth/pages/LoginPage.tsx +106 -0
  33. package/template/src/features/auth/pages/SignupPage.tsx +96 -0
  34. package/template/src/features/datagrid/SmartTable.tsx +222 -0
  35. package/template/src/features/onboarding/pages/Welcome.tsx +161 -0
  36. package/template/src/features/overview/index.ts +1 -0
  37. package/template/src/features/overview/pages/OverviewPage.tsx +127 -0
  38. package/template/src/{pages → features/playground/pages}/AccountingLedgerPage.tsx +1 -1
  39. package/template/src/{pages/prototypes → features/playground/pages}/ItemSelectorPage.tsx +1 -1
  40. package/template/src/{pages/settings → features/settings/pages}/BillingPage.tsx +1 -1
  41. package/template/src/features/settings/pages/ProfilePage.tsx +153 -0
  42. package/template/src/{pages/settings → features/settings/pages}/TeamPage.tsx +1 -1
  43. package/template/src/features/styleguide/Styleguide.tsx +75 -0
  44. package/template/src/features/users/components/UserDrawer.tsx +138 -0
  45. package/template/src/features/users/index.ts +2 -0
  46. package/template/src/features/users/pages/UsersPage.tsx +151 -0
  47. package/template/src/index.css +1 -1
  48. package/template/src/main.tsx +3 -3
  49. package/template/src/templates/dashboard/DashboardLayout.tsx +75 -106
  50. package/template/src/templates/dashboard/dashboard.sitemap.ts +34 -19
  51. package/template/src/templates/docs/DocsLayout.tsx +49 -38
  52. package/template/src/templates/docs/docs.sitemap.ts +22 -34
  53. package/template/src/templates/settings/SettingsLayout.tsx +83 -143
  54. package/template/src/templates/settings/settings.sitemap.ts +6 -6
  55. package/template/vite.config.ts +12 -9
  56. package/template/src/adaptors/.gitkeep +0 -0
  57. package/template/src/blocks/SmartTable.tsx +0 -191
  58. package/template/src/components/LocalSideNav.tsx +0 -120
  59. package/template/src/components/PageWithSideNav.tsx +0 -69
  60. package/template/src/config/dashboard.layout.ts +0 -110
  61. package/template/src/contexts/AuthContext.tsx +0 -64
  62. package/template/src/data/mockUsers.ts +0 -18
  63. package/template/src/generated/hooks.ts +0 -40
  64. package/template/src/hooks/useSignal.ts +0 -83
  65. package/template/src/hooks/useWorkflowEngine.ts +0 -6
  66. package/template/src/layouts/DataLayout.tsx +0 -37
  67. package/template/src/layouts/SideNavLayout.tsx +0 -28
  68. package/template/src/pages/Dashboard.tsx +0 -60
  69. package/template/src/pages/DataGridPage.tsx +0 -184
  70. package/template/src/pages/LoginPage.tsx +0 -58
  71. package/template/src/pages/settings/ProfilePage.tsx +0 -10
  72. package/template/src/pages/styleguide/Styleguide.tsx +0 -40
  73. package/template/src/templates/docs/pages/Introduction.tsx +0 -13
  74. package/template/src/types/signal.ts +0 -23
  75. /package/template/src/{core → engine/renderers}/route-generator.tsx +0 -0
  76. /package/template/src/{core → engine/types}/sitemap-entry.ts +0 -0
  77. /package/template/src/{pages → features}/GenericContentPage.tsx +0 -0
  78. /package/template/src/{hooks → features/assistant}/useMockChat.ts +0 -0
  79. /package/template/src/{components/dev → features/developer}/GhostOverlay.tsx +0 -0
  80. /package/template/src/{hooks → features/developer}/useDevTools.ts +0 -0
  81. /package/template/src/{pages → features}/styleguide/sections/charts/ChartsSection.tsx +0 -0
  82. /package/template/src/{pages → features}/styleguide/sections/colors/ColorsSection.tsx +0 -0
  83. /package/template/src/{pages → features}/styleguide/sections/elements/ElementsSection.tsx +0 -0
  84. /package/template/src/{pages → features}/styleguide/sections/feedback/FeedbackSection.tsx +0 -0
  85. /package/template/src/{pages → features}/styleguide/sections/forms/FormsSection.tsx +0 -0
  86. /package/template/src/{pages → features}/styleguide/sections/icons/IconsSection.tsx +0 -0
  87. /package/template/src/{pages → features}/styleguide/sections/layout/LayoutSection.tsx +0 -0
  88. /package/template/src/{pages → features}/styleguide/sections/navigation/NavigationSection.tsx +0 -0
  89. /package/template/src/{pages → features}/styleguide/sections/tables/TablesSection.tsx +0 -0
  90. /package/template/src/{pages → features}/styleguide/sections/templates/TemplatesSection.tsx +0 -0
  91. /package/template/src/{pages → features}/styleguide/sections/theming/ThemingSection.tsx +0 -0
  92. /package/template/src/{pages → features}/styleguide/sections/utilities/UtilitiesSection.tsx +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ramme-io/create-app",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "create-ramme-app": "./index.js"
@@ -18,7 +18,6 @@
18
18
  "zip:builder": "cd template && zip -r ../base.zip . -x \"node_modules/*\" \"dist/*\" \".DS_Store\" && mv ../base.zip ../../ramme-app-builder/public/base.zip && echo '✅ base.zip updated in Builder!'"
19
19
  },
20
20
  "dependencies": {
21
- "@ramme-io/ui": "^1.1.5",
22
21
  "ag-grid-community": "^34.1.2",
23
22
  "ag-grid-enterprise": "^34.1.2",
24
23
  "ag-grid-react": "^34.1.2",
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "ramme-app",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@ai-sdk/google": "^0.0.10",
13
+ "@ramme-io/ui": "^1.2.2",
14
+ "@types/uuid": "^10.0.0",
15
+ "ag-grid-community": "^31.3.1",
16
+ "ag-grid-enterprise": "^31.3.1",
17
+ "ag-grid-react": "^31.3.1",
18
+ "ai": "^3.0.0",
19
+ "framer-motion": "^11.0.0",
20
+ "fs-extra": "^11.2.0",
21
+ "mqtt": "^5.3.5",
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "react-resizable-panels": "^2.0.9",
25
+ "react-router-dom": "^6.22.0",
26
+ "uuid": "^13.0.0",
27
+ "zod": "^3.22.0",
28
+ "zustand": "^4.5.7"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.11.0",
32
+ "@types/react": "^18.2.0",
33
+ "@types/react-dom": "^18.2.0",
34
+ "@vitejs/plugin-react": "^4.2.0",
35
+ "autoprefixer": "^10.4.19",
36
+ "postcss": "^8.4.38",
37
+ "tailwindcss": "^3.4.3",
38
+ "typescript": "^5.2.0",
39
+ "vite": "^5.2.0"
40
+ }
41
+ }
package/template/pkg.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "dependencies": {
12
- "@ramme-io/ui": "^1.1.5",
12
+ "@ramme-io/ui": "^1.2.2",
13
13
  "mqtt": "^5.3.5",
14
14
  "zustand": "^4.5.0",
15
15
  "ag-grid-community": "^31.3.1",
@@ -1,55 +1,85 @@
1
+ import { useEffect } from 'react';
1
2
  import { Routes, Route, Navigate } from 'react-router-dom';
2
- import { generateRoutes } from './core/route-generator';
3
- import { useEffect } from 'react'; // <-- 1. Import useEffect
3
+ import { generateRoutes } from './engine/renderers/route-generator';
4
+ import { ThemeProvider } from '@ramme-io/ui';
5
+ import { AuthProvider } from './features/auth/AuthContext';
6
+ import { MqttProvider } from './engine/runtime/MqttContext';
4
7
 
5
- // --- 1. IMPORT ALL THREE TEMPLATES ---
8
+ // --- 1. IMPORT AUTH CLUSTER ---
9
+ import { AuthLayout } from './features/auth/pages/AuthLayout';
10
+ import LoginPage from './features/auth/pages/LoginPage';
11
+ import SignupPage from './features/auth/pages/SignupPage';
12
+
13
+ // --- 2. IMPORT TEMPLATES ---
6
14
  import DashboardLayout from './templates/dashboard/DashboardLayout';
7
- import { dashboardSitemap as dashboardSitemap } from './templates/dashboard/dashboard.sitemap';
15
+ import { dashboardSitemap } from './templates/dashboard/dashboard.sitemap';
8
16
  import DocsLayout from './templates/docs/DocsLayout';
9
- import { docsSitemap as docsSitemap } from './templates/docs/docs.sitemap';
17
+ import { docsSitemap } from './templates/docs/docs.sitemap';
10
18
  import SettingsLayout from './templates/settings/SettingsLayout';
11
- import { settingsSitemap as settingsSitemap } from './templates/settings/settings.sitemap';
19
+ import { settingsSitemap } from './templates/settings/settings.sitemap';
12
20
 
13
21
  // Other Imports
14
22
  import ProtectedRoute from './components/ProtectedRoute';
15
- import LoginPage from './pages/LoginPage';
16
- import NotFound from './pages/styleguide/NotFound';
23
+ import NotFound from './components/NotFound';
24
+
25
+ // --- 3. DATA SEEDER ---
26
+ import { initializeDataLake } from './engine/runtime/data-seeder';
17
27
 
18
- // --- 2. IMPORT THE SEEDER ---
19
- import { initializeDataLake } from './core/data-seeder';
28
+ import ScrollToTop from './components/ScrollToTop';
29
+ import HashLinkScroll from './components/HashLinkScroll';
20
30
 
21
31
  function App() {
22
32
 
23
- // 3. TRIGGER DATA SEEDING ON MOUNT
24
- // This checks localStorage and injects our mock database if missing.
33
+ // Trigger data seeding on mount
25
34
  useEffect(() => {
26
35
  initializeDataLake();
27
36
  }, []);
28
37
 
29
38
  return (
30
- <Routes>
31
- <Route path="/login" element={<LoginPage />} />
32
- <Route element={<ProtectedRoute />}>
33
- {/* Default redirect to the dashboard's root */}
34
- <Route path="/" element={<Navigate to="/dashboard" replace />} />
35
-
36
- {/* Dashboard Template Routes */}
37
- <Route path="/dashboard/*" element={<DashboardLayout />}>
38
- {generateRoutes(dashboardSitemap)}
39
- </Route>
40
-
41
- {/* Docs Template Routes */}
42
- <Route path="/docs/*" element={<DocsLayout />}>
43
- {generateRoutes(docsSitemap)}
44
- </Route>
45
-
46
- {/* Settings Layout Route */}
47
- <Route path="/settings/*" element={<SettingsLayout />}>
48
- {generateRoutes(settingsSitemap)}
49
- </Route>
50
- </Route>
51
- <Route path="*" element={<NotFound />} />
52
- </Routes>
39
+ <ThemeProvider>
40
+ <AuthProvider>
41
+ <MqttProvider>
42
+ <ScrollToTop />
43
+ <HashLinkScroll />
44
+ <Routes>
45
+ {/* --- NEW AUTH CLUSTER --- */}
46
+ {/* This handles the layout and background for all auth pages */}
47
+ <Route path="/auth" element={<AuthLayout />}>
48
+ <Route index element={<Navigate to="/auth/login" replace />} />
49
+ <Route path="login" element={<LoginPage />} />
50
+ <Route path="signup" element={<SignupPage />} />
51
+ </Route>
52
+
53
+ {/* Fallback for legacy /login access */}
54
+ <Route path="/login" element={<Navigate to="/auth/login" replace />} />
55
+
56
+ {/* --- PROTECTED APP ROUTES --- */}
57
+ <Route element={<ProtectedRoute />}>
58
+ <Route path="/" element={<Navigate to="/dashboard/welcome" replace />} />
59
+
60
+ {/* Dashboard Template */}
61
+ <Route path="/dashboard/*" element={<DashboardLayout />}>
62
+ <Route index element={<Navigate to="welcome" replace />} />
63
+ {generateRoutes(dashboardSitemap)}
64
+ </Route>
65
+
66
+ {/* Docs Template */}
67
+ <Route path="/docs/*" element={<DocsLayout />}>
68
+ {generateRoutes(docsSitemap)}
69
+ </Route>
70
+
71
+ {/* Settings Template */}
72
+ <Route path="/settings/*" element={<SettingsLayout />}>
73
+ {generateRoutes(settingsSitemap)}
74
+ </Route>
75
+ </Route>
76
+
77
+ {/* 404 Handler */}
78
+ <Route path="*" element={<NotFound />} />
79
+ </Routes>
80
+ </MqttProvider>
81
+ </AuthProvider>
82
+ </ThemeProvider>
53
83
  );
54
84
  }
55
85
 
@@ -7,7 +7,7 @@ import {
7
7
  Button,
8
8
  Icon,
9
9
  } from '@ramme-io/ui';
10
- import { useMockChat } from '../hooks/useMockChat';
10
+ import { useMockChat } from '../features/assistant/useMockChat';
11
11
 
12
12
  interface AIChatWidgetProps {
13
13
  onClose: () => void;
@@ -31,7 +31,7 @@ export const AIChatWidget: React.FC<AIChatWidgetProps> = ({ onClose }) => {
31
31
  <div className="p-4 border-b flex justify-between items-center bg-muted/50 rounded-t-lg">
32
32
  <div className="flex items-center gap-2">
33
33
  <div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
34
- <span className="font-semibold text-sm">Bodewell AI</span>
34
+ <span className="font-semibold text-sm">AI Chat</span>
35
35
  </div>
36
36
  <Button variant="ghost" size="icon" onClick={onClose} className="h-6 w-6">
37
37
  <Icon name="x" size={16} />
@@ -19,11 +19,11 @@ import {
19
19
  useTheme,
20
20
  type ThemeName,
21
21
  } from '@ramme-io/ui';
22
- import { useAuth } from '../contexts/AuthContext';
22
+ import { useAuth } from '../features/auth/AuthContext';
23
23
 
24
24
  // --- STRATEGIC IMPORTS ---
25
25
  import { appManifest } from '../config/navigation';
26
- import type { ManifestLink } from '../core/manifest-types';
26
+ import type { ManifestLink } from '../engine/types/manifest-types';
27
27
  import TemplateSwitcher from './TemplateSwitcher';
28
28
  import rammeLogo from '../assets/orange.png'; // <-- 1. IMPORT THE LOGO
29
29
 
@@ -1,6 +1,19 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { Drawer, FormTemplate, Button, type FormField } from '@ramme-io/ui';
3
3
 
4
+ /**
5
+ * @file AutoForm.tsx
6
+ * @description The "Zero-Boilerplate" Form Engine.
7
+ * * ARCHITECTURAL ROLE:
8
+ * This component acts as the bridge between your data schema (JSON) and the UI.
9
+ * Instead of writing manual form code for every resource (Users, Products, Orders),
10
+ * this component dynamically generates the correct inputs based on the field type.
11
+ * * KEY FEATURES:
12
+ * 1. **Smart Mapping:** Automatically converts 'boolean' -> Toggle, 'date' -> DatePicker, etc.
13
+ * 2. **Context Aware:** Auto-detects "Create" vs "Edit" mode based on `initialData`.
14
+ * 3. **Safety Logic:** Automatically hides primary keys during creation and locks them during editing.
15
+ */
16
+
4
17
  interface AutoFormProps {
5
18
  isOpen: boolean;
6
19
  onClose: () => void;
@@ -13,7 +13,7 @@ const NotFound: React.FC = () => {
13
13
  </p>
14
14
  {/* Wrap the Button with the Link component */}
15
15
  <Link to="/">
16
- <Button size="lg">Return to Style Guide</Button>
16
+ <Button size="lg">Return to Dashboard</Button>
17
17
  </Link>
18
18
  </div>
19
19
  );
@@ -6,8 +6,8 @@
6
6
  */
7
7
  import React, { useEffect } from 'react';
8
8
  import { useLocation } from 'react-router-dom';
9
- import { useSitemap } from '../contexts/SitemapContext'; // Import our context hook
10
- import type { SitemapEntry } from '../core/sitemap-entry';
9
+ import { useSitemap } from '../engine/runtime/SitemapContext'; // Import our context hook
10
+ import type { SitemapEntry } from '../engine/types/sitemap-entry';
11
11
 
12
12
  // Helper function to recursively find a route by path
13
13
  const findRouteByPath = (
@@ -1,8 +1,25 @@
1
1
  import React from 'react';
2
2
  import { Navigate, Outlet } from 'react-router-dom';
3
- import { useAuth } from '../contexts/AuthContext';
3
+ import { useAuth } from '../features/auth/AuthContext';
4
4
  import { Icon } from '@ramme-io/ui';
5
5
 
6
+ /**
7
+ * @file ProtectedRoute.tsx
8
+ * @description The "Security Gatekeeper" for the application.
9
+ *
10
+ * ARCHITECTURAL ROLE:
11
+ * This component wraps all private routes (Dashboard, Settings, Docs) in `App.tsx`.
12
+ * It acts as a middleware that checks the user's authentication status before
13
+ * allowing access to the child components (Outlet).
14
+ *
15
+ * KEY FEATURES:
16
+ * 1. **Auth Verification:** Automatically redirects unauthenticated users to `/login`.
17
+ * 2. **Loading State:** Displays a spinner while the Auth Provider is initializing,
18
+ * preventing "flash of login screen" bugs.
19
+ * 3. **History Management:** Uses `replace` on redirect to ensure the browser
20
+ * back button works correctly (skips the restricted page).
21
+ */
22
+
6
23
  const ProtectedRoute: React.FC = () => {
7
24
  const { user, isLoading } = useAuth();
8
25
 
@@ -0,0 +1,19 @@
1
+ import { useEffect } from 'react';
2
+ import { useLocation } from 'react-router-dom';
3
+
4
+ const ScrollToTop = () => {
5
+ const { pathname } = useLocation();
6
+
7
+ useEffect(() => {
8
+ // "instant" prevents the user from seeing the page scroll up
9
+ window.scrollTo({
10
+ top: 0,
11
+ left: 0,
12
+ behavior: 'instant',
13
+ });
14
+ }, [pathname]);
15
+
16
+ return null;
17
+ };
18
+
19
+ export default ScrollToTop;
@@ -1,4 +1,6 @@
1
- import type { AppSpecification } from '../types/schema';
1
+ import type { AppSpecification } from '../engine/validation/schema';
2
+
3
+
2
4
 
3
5
  export const appManifest: AppSpecification = {
4
6
  meta: {
@@ -13,7 +13,7 @@ import {
13
13
  } from '@ramme-io/ui';
14
14
 
15
15
  // ✅ IMPORT YOUR CUSTOM COMPONENT
16
- import { SmartTable } from '../blocks/SmartTable';
16
+ import { SmartTable } from '../features/datagrid/SmartTable';
17
17
 
18
18
  export const COMPONENT_REGISTRY: Record<string, React.FC<any>> = {
19
19
  // IoT Primitives
@@ -5,7 +5,7 @@
5
5
  * This is the central manifest for all GLOBAL, shared navigation elements.
6
6
  * Corrected paths to point within the /settings layout.
7
7
  */
8
- import type { ManifestLink } from '../core/manifest-types';
8
+ import type { ManifestLink } from '../engine/types/manifest-types';
9
9
 
10
10
  interface AppManifest {
11
11
  userMenu: ManifestLink[];
@@ -1,37 +1,41 @@
1
- // src/data/mock-charts.ts
2
- import type { ChartData } from 'chart.js';
1
+ /**
2
+ * @file mock-charts.ts
3
+ * @description The "Chart Data Lake".
4
+ *
5
+ * ARCHITECTURAL ROLE:
6
+ * This file stores the structured data required by Recharts components.
7
+ * Separating this from the tabular `mockData.ts` prevents bloat and allows
8
+ * for specific optimization of visualization data.
9
+ */
3
10
 
4
- // The centralized registry of "Heavy Data"
5
- export const MOCK_CHART_DATA: Record<string, ChartData<any>> = {
11
+ // 1. Define a generic shape for Recharts data
12
+ // Recharts expects an array of objects: [{ name: 'A', value: 10 }, ...]
13
+ export type RechartsData = Record<string, any>[];
14
+
15
+ export const MOCK_CHART_DATA: Record<string, RechartsData> = {
6
16
 
7
17
  // ID: energy_history
8
- energy_history: {
9
- labels: ["12am", "4am", "8am", "12pm", "4pm", "8pm"],
10
- datasets: [
11
- {
12
- label: "Energy (kWh)",
13
- data: [12, 19, 3, 5, 2, 3],
14
- borderColor: "#3b82f6",
15
- backgroundColor: "rgba(59, 130, 246, 0.5)",
16
- tension: 0.4
17
- }
18
- ]
19
- },
18
+ energy_history: [
19
+ { time: "12am", value: 12 },
20
+ { time: "4am", value: 19 },
21
+ { time: "8am", value: 3 },
22
+ { time: "12pm", value: 5 },
23
+ { time: "4pm", value: 2 },
24
+ { time: "8pm", value: 3 }
25
+ ],
20
26
 
21
27
  // ID: server_load
22
- server_load: {
23
- labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
24
- datasets: [
25
- {
26
- label: "CPU Load %",
27
- data: [45, 52, 38, 70, 65, 30, 40],
28
- borderColor: "#10b981",
29
- backgroundColor: "rgba(16, 185, 129, 0.5)"
30
- }
31
- ]
32
- }
28
+ server_load: [
29
+ { day: "Mon", load: 45 },
30
+ { day: "Tue", load: 52 },
31
+ { day: "Wed", load: 38 },
32
+ { day: "Thu", load: 70 },
33
+ { day: "Fri", load: 65 },
34
+ { day: "Sat", load: 30 },
35
+ { day: "Sun", load: 40 }
36
+ ]
33
37
  };
34
38
 
35
39
  export const getChartData = (id: string) => {
36
- return MOCK_CHART_DATA[id] || null;
40
+ return MOCK_CHART_DATA[id] || [];
37
41
  };
@@ -1,8 +1,23 @@
1
1
  import React from 'react';
2
- import { getComponent } from '../core/component-registry';
2
+ import { getComponent } from '../../config/component-registry';
3
3
  // @ts-ignore
4
4
  import { useGeneratedSignals } from '../generated/hooks';
5
- import { getMockData } from '../data/mockData';
5
+ import { getMockData } from '../../data/mockData';
6
+
7
+ /**
8
+ * @file DynamicBlock.tsx
9
+ * @description The "Runtime Hydrator" for the application.
10
+ *
11
+ * ARCHITECTURAL ROLE:
12
+ * This component acts as the bridge between the Abstract Syntax Tree (JSON Manifest)
13
+ * and the concrete React UI.
14
+ *
15
+ * KEY RESPONSIBILITIES:
16
+ * 1. **Component Lookup:** Resolves string types ('StatCard') to actual React components.
17
+ * 2. **Signal Injection:** Subscribes to the real-time Signal Engine and feeds live values to props.
18
+ * 3. **Data Hydration:** Fetches static or async data (users, logs) based on `dataId`.
19
+ * 4. **Status Normalization:** Translates system-level signal states into UI-friendly status colors.
20
+ */
6
21
 
7
22
  const mapSignalStatus = (status: string): string => {
8
23
  switch (status) {
@@ -39,18 +54,23 @@ export const DynamicBlock: React.FC<any> = ({ block }) => {
39
54
  const signalState = signals[signalId];
40
55
 
41
56
  if (signalState) {
42
- // ✅ FIX: Handle both Raw Values (Legacy) and Signal Objects (New)
43
- // If it's an object with a 'value' property, use that. Otherwise use it directly.
44
- const rawValue = (typeof signalState === 'object' && 'value' in signalState)
57
+ // ✅ FIX: Check for null and handle objects vs raw values
58
+ const isSignalObject = typeof signalState === 'object' && signalState !== null;
59
+
60
+ // Extract Value
61
+ const rawValue = (isSignalObject && 'value' in signalState)
45
62
  ? signalState.value
46
63
  : signalState;
47
64
 
48
- const status = (typeof signalState === 'object' && 'status' in signalState)
65
+ // Extract Status
66
+ const rawStatus = (isSignalObject && 'status' in signalState)
49
67
  ? signalState.status
50
68
  : 'fresh'; // Default for raw values
51
69
 
52
70
  dynamicProps.value = typeof rawValue === 'number' ? rawValue : String(rawValue);
53
- dynamicProps.status = mapSignalStatus(status);
71
+
72
+ // ✅ FIX: Explicitly cast to String to satisfy TypeScript
73
+ dynamicProps.status = mapSignalStatus(String(rawStatus));
54
74
  } else {
55
75
  dynamicProps.status = mapSignalStatus('disconnected');
56
76
  }
@@ -1,12 +1,31 @@
1
1
  import React from 'react';
2
2
  import { PageHeader, Alert, Button, Icon } from '@ramme-io/ui';
3
- import { appManifest } from '../config/app.manifest';
3
+ import { appManifest } from '../../config/app.manifest';
4
4
  // Reuse the GhostOverlay for structure visualization
5
- import { GhostOverlay } from '../components/dev/GhostOverlay';
5
+ import { GhostOverlay } from '../../features/developer/GhostOverlay';
6
6
  // Import the Worker Bee
7
- import { DynamicBlock } from '../components/DynamicBlock';
7
+ import { DynamicBlock } from './DynamicBlock';
8
8
  // Import the Hook to control the overlay
9
- import { useDevTools } from '../hooks/useDevTools';
9
+ import { useDevTools } from '../../features/developer/useDevTools';
10
+
11
+ /**
12
+ * @file DynamicPage.tsx
13
+ * @description The "Layout Engine" of the application.
14
+ *
15
+ * ARCHITECTURAL ROLE:
16
+ * This component is the bridge between the Abstract JSON Manifest and the Concrete DOM.
17
+ * It acts as the "General Contractor," taking the blueprint (Manifest) and instructing
18
+ * the workers (DynamicBlock) where to build.
19
+ *
20
+ * HIERARCHY:
21
+ * App -> Routes -> DynamicPage -> (Iterates Sections) -> DynamicBlock -> (Actual Component)
22
+ *
23
+ * KEY FEATURES:
24
+ * 1. **Manifest Lookup:** Uses the `pageId` prop to find the correct configuration in `app.manifest.ts`.
25
+ * 2. **Grid Composition:** Translates abstract layout numbers (e.g., `columns: 3`) into real CSS Grid styles.
26
+ * 3. **DevTools Integration:** Wraps blocks in `GhostOverlay` (when enabled) to visualize the
27
+ * hidden boundaries and signal connections during development.
28
+ */
10
29
 
11
30
  interface DynamicPageProps {
12
31
  pageId: string;
@@ -1,5 +1,6 @@
1
1
  import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
2
2
  import mqtt, { type MqttClient } from 'mqtt';
3
+ import { appManifest } from '../../config/app.manifest'; // ✅ Connect to the Single Source of Truth
3
4
 
4
5
  interface MqttContextType {
5
6
  isConnected: boolean;
@@ -11,22 +12,33 @@ interface MqttContextType {
11
12
 
12
13
  const MqttContext = createContext<MqttContextType | null>(null);
13
14
 
14
- // Public Test Broker for "Out of the Box" functionality
15
- // In a real app, this comes from config.ts
16
- const DEFAULT_BROKER = 'wss://test.mosquitto.org:8081';
15
+ /**
16
+ * @file MqttContext.tsx
17
+ * @description The Real-Time Connectivity Layer.
18
+ *
19
+ * ARCHITECTURAL ROLE:
20
+ * This provider establishes a persistent WebSocket connection to the MQTT Broker
21
+ * defined in `app.manifest.ts`.
22
+ *
23
+ * KEY FEATURES:
24
+ * 1. **Global Connection:** Maintains one connection for the whole app (Singleton pattern).
25
+ * 2. **Topic Management:** specific components (like DeviceCard) can subscribe to
26
+ * specific topics on demand using `subscribe()`.
27
+ * 3. **State Distribution:** Broadcasts the latest messages to any component using `useMqtt()`.
28
+ */
17
29
 
18
30
  export const MqttProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
19
31
  const [isConnected, setIsConnected] = useState(false);
20
32
  const [lastMessage, setLastMessage] = useState<Record<string, string>>({});
21
33
  const clientRef = useRef<MqttClient | null>(null);
22
-
23
- // Track active subscriptions to avoid double-subscribing
24
34
  const subscriptions = useRef<Set<string>>(new Set());
25
35
 
26
36
  useEffect(() => {
27
- console.log(`[MQTT] Connecting to ${DEFAULT_BROKER}...`);
37
+ // Load Broker URL from the Manifest Config
38
+ const brokerUrl = appManifest.config.brokerUrl || 'wss://test.mosquitto.org:8081';
39
+ console.log(`[MQTT] Connecting to ${brokerUrl}...`);
28
40
 
29
- const client = mqtt.connect(DEFAULT_BROKER);
41
+ const client = mqtt.connect(brokerUrl);
30
42
  clientRef.current = client;
31
43
 
32
44
  client.on('connect', () => {
@@ -34,12 +46,14 @@ export const MqttProvider: React.FC<{ children: React.ReactNode }> = ({ children
34
46
  setIsConnected(true);
35
47
  });
36
48
 
37
- client.on('message', (topic: any, message: { toString: () => any; }) => {
38
- const payload = message.toString();
39
- setLastMessage((prev) => ({ ...prev, [topic]: payload }));
49
+ // FIX: Proper typing for MQTT payload (Buffer)
50
+ client.on('message', (topic: string, payload: Buffer) => {
51
+ const messageStr = payload.toString();
52
+ // console.log(`[MQTT] Msg: ${topic} -> ${messageStr}`); // Optional debug
53
+ setLastMessage((prev) => ({ ...prev, [topic]: messageStr }));
40
54
  });
41
55
 
42
- client.on('error', (err: any) => {
56
+ client.on('error', (err) => {
43
57
  console.error('[MQTT] Connection error: ', err);
44
58
  client.end();
45
59
  });
@@ -20,7 +20,7 @@
20
20
 
21
21
  import { createContext, useContext } from 'react';
22
22
  // Import the canonical "schema" for a sitemap entry
23
- import type { SitemapEntry } from '../core/sitemap-entry';
23
+ import type { SitemapEntry } from '../types/sitemap-entry';
24
24
 
25
25
  // 1. Create the context
26
26
  // We initialize it with an empty array as a safe default.
@@ -1,7 +1,17 @@
1
+ // src/core/data-seeder.ts
2
+
1
3
  // ✅ Match the export from your new mockData.ts
2
- import { DATA_REGISTRY } from '../data/mockData';
4
+ import { DATA_REGISTRY } from '../../data/mockData';
3
5
 
4
- const DB_PREFIX = 'ramme_db_';
6
+ /**
7
+ * @file data-seeder.ts
8
+ * @description The "Big Bang" for the client-side database.
9
+ * * ARCHITECTURAL ROLE:
10
+ * This utility ensures that the LocalStorage "Data Lake" is never empty.
11
+ * On app launch, it checks if data exists. If not, it writes the seed data
12
+ * from `mockData.ts` into the browser's storage.
13
+ * * This allows the app to feel "alive" with data immediately after installation.
14
+ */
5
15
 
6
16
  export const initializeDataLake = () => {
7
17
  if (typeof window === 'undefined') return;
@@ -9,7 +19,8 @@ export const initializeDataLake = () => {
9
19
  console.groupCollapsed('🌊 [Data Lake] Initialization');
10
20
 
11
21
  Object.entries(DATA_REGISTRY).forEach(([key, seedData]) => {
12
- const storageKey = `${DB_PREFIX}${key}`;
22
+ // ⚠️ REMOVED PREFIX ('ramme_db_') so it matches AuthContext
23
+ const storageKey = key;
13
24
  const existing = localStorage.getItem(storageKey);
14
25
 
15
26
  if (!existing) {
@@ -27,9 +38,8 @@ export const initializeDataLake = () => {
27
38
  * Utility to clear the lake (useful for a "Reset Data" button)
28
39
  */
29
40
  export const resetDataLake = () => {
30
- // ✅ FIX: Use DATA_REGISTRY (the new name)
31
41
  Object.keys(DATA_REGISTRY).forEach((key) => {
32
- localStorage.removeItem(`${DB_PREFIX}${key}`);
42
+ localStorage.removeItem(key); // Matches the storageKey above
33
43
  });
34
44
  window.location.reload();
35
45
  };