Phase 1 (Foundation): - Project restructure (presenton-main → backend/ + frontend/) - Database schema (8 new models, Alembic config, seed script) - Auth (Azure AD SSO + dev bypass, JWT sessions, AuthMiddleware) - RBAC (access_service, rbac_middleware, admin routers) - Audit logging (fire-and-forget, AuditMiddleware, admin router) - i18n (react-i18next with 5 namespace files) Phase 2 (Admin Panel & Client Management): - Admin panel shell (sidebar layout, role guard, 12 pages) - Redux admin slice with 18 async thunks - User management (role changes, deactivation) - Client management (CRUD, brand config, team management) - Brand config editor (colors, fonts, logos, voice rules) - Master deck upload & parser (PPTX → HTML → React pipeline) - Audit log viewer with filters and CSV/JSON export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
4.6 KiB
TypeScript
132 lines
4.6 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import * as z from "zod";
|
|
import * as Recharts from "recharts";
|
|
import * as Babel from "@babel/standalone";
|
|
import * as d3 from "d3";
|
|
// import * as d3Cloud from "d3-cloud";
|
|
|
|
export interface CompiledLayout {
|
|
component: React.ComponentType<{ data: any }>;
|
|
layoutId: string;
|
|
layoutName: string;
|
|
layoutDescription: string;
|
|
schema: any;
|
|
sampleData: Record<string, any>;
|
|
schemaJSON: any;
|
|
}
|
|
|
|
/**
|
|
* Compiles a layout code string into a usable React component
|
|
*/
|
|
export function compileCustomLayout(layoutCode: string): CompiledLayout | null {
|
|
console.log('compileCustomLayout called');
|
|
try {
|
|
// Clean up imports that we'll provide ourselves
|
|
const cleanCode = layoutCode
|
|
// Remove React imports
|
|
.replace(/import\s+React\s*,?\s*\{?[^}]*\}?\s*from\s+['"]react['"];?/g, "")
|
|
.replace(/import\s+\*\s+as\s+React\s+from\s+['"]react['"];?/g, "")
|
|
.replace(/import\s+{\s*[^}]*\s*}\s*from\s+['"]react['"];?/g, "")
|
|
// Remove zod imports
|
|
.replace(/import\s+\*\s+as\s+z\s+from\s+['"]zod['"];?/g, "")
|
|
.replace(/import\s+{\s*z\s*}\s*from\s+['"]zod['"];?/g, "")
|
|
.replace(/import\s+.*\s+from\s+['"]zod['"];?/g, "")
|
|
// Remove recharts imports
|
|
.replace(/import\s+.*\s+from\s+['"]recharts['"];?/g, "")
|
|
// Remove other common imports we'll provide
|
|
.replace(/import\s+.*\s+from\s+['"]@\/[^'"]+['"];?/g, "")
|
|
// Remove export default at the end (we'll handle it differently)
|
|
.replace(/export\s+default\s+\w+;?\s*$/g, "");
|
|
|
|
|
|
|
|
const compiled = Babel.transform(cleanCode, {
|
|
presets: [
|
|
["react", { runtime: "classic" }],
|
|
["typescript", { isTSX: true, allExtensions: true }],
|
|
],
|
|
sourceType: "script",
|
|
}).code;
|
|
|
|
// Create a factory function that executes the compiled code
|
|
const factory = new Function(
|
|
"React",
|
|
"_z",
|
|
"Recharts",
|
|
"_d3",
|
|
// "_d3Cloud",
|
|
`
|
|
const z = _z;
|
|
// const d3Cloud= _d3Cloud;
|
|
const d3 = _d3;
|
|
// Expose React hooks
|
|
const { useState, useEffect, useRef, useMemo, useCallback, Fragment } = React;
|
|
|
|
// Expose Recharts components
|
|
const {
|
|
ResponsiveContainer, LineChart, Line, BarChart, Bar,
|
|
XAxis, YAxis, CartesianGrid, Tooltip, Legend,
|
|
PieChart, Pie, Cell, AreaChart, Area,
|
|
RadarChart, Radar, PolarGrid, PolarAngleAxis, PolarRadiusAxis,
|
|
ComposedChart, ScatterChart, Scatter,
|
|
RadialBarChart, RadialBar,
|
|
ReferenceLine, ReferenceDot, ReferenceArea,
|
|
Brush, LabelList, Label,Text
|
|
} = Recharts || {};
|
|
|
|
// Execute the compiled code
|
|
${compiled}
|
|
|
|
// Return the exports
|
|
return {
|
|
__esModule: true,
|
|
component: typeof dynamicSlideLayout !== 'undefined'
|
|
? dynamicSlideLayout
|
|
: (typeof DefaultLayout !== 'undefined' ? DefaultLayout : undefined),
|
|
layoutId: typeof layoutId !== 'undefined' ? layoutId : 'custom-layout',
|
|
layoutName: typeof layoutName !== 'undefined' ? layoutName : 'Custom Layout',
|
|
layoutDescription: typeof layoutDescription !== 'undefined' ? layoutDescription : '',
|
|
Schema: typeof Schema !== 'undefined' ? Schema : null,
|
|
};
|
|
`
|
|
);
|
|
|
|
// Execute the factory
|
|
const result = factory(React, z, Recharts, d3);
|
|
|
|
if (!result.component) {
|
|
console.error("No component found in compiled code");
|
|
return null;
|
|
}
|
|
|
|
// Parse schema to get sample data
|
|
let sampleData: Record<string, any> = {};
|
|
if (result.Schema) {
|
|
try {
|
|
sampleData = result.Schema.parse({});
|
|
} catch (e) {
|
|
console.warn("Could not parse schema defaults:", e);
|
|
}
|
|
}
|
|
const schemaJSON = z.toJSONSchema(result.Schema);
|
|
|
|
return {
|
|
component: result.component,
|
|
layoutId: result.layoutId,
|
|
layoutName: result.layoutName,
|
|
layoutDescription: result.layoutDescription,
|
|
schema: result.Schema,
|
|
sampleData,
|
|
schemaJSON,
|
|
};
|
|
} catch (error) {
|
|
console.error("Error compiling layout:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|