@lastbrain/app 0.1.24 → 0.1.25
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/dist/__tests__/module-registry.test.d.ts +2 -0
- package/dist/__tests__/module-registry.test.d.ts.map +1 -0
- package/dist/__tests__/module-registry.test.js +64 -0
- package/dist/app-shell/(admin)/layout.d.ts +3 -2
- package/dist/app-shell/(admin)/layout.d.ts.map +1 -1
- package/dist/app-shell/(admin)/layout.js +1 -1
- package/dist/app-shell/(auth)/layout.d.ts +3 -2
- package/dist/app-shell/(auth)/layout.d.ts.map +1 -1
- package/dist/app-shell/(auth)/layout.js +1 -1
- package/dist/cli.js +50 -0
- package/dist/layouts/AdminLayout.d.ts +3 -2
- package/dist/layouts/AdminLayout.d.ts.map +1 -1
- package/dist/layouts/AppProviders.d.ts +3 -2
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AuthLayout.d.ts +3 -2
- package/dist/layouts/AuthLayout.d.ts.map +1 -1
- package/dist/layouts/PublicLayout.d.ts +3 -2
- package/dist/layouts/PublicLayout.d.ts.map +1 -1
- package/dist/layouts/RootLayout.d.ts +3 -2
- package/dist/layouts/RootLayout.d.ts.map +1 -1
- package/dist/scripts/db-init.js +1 -1
- package/dist/scripts/db-migrations-sync.js +5 -5
- package/dist/scripts/init-app.js +13 -10
- package/dist/scripts/module-add.d.ts.map +1 -1
- package/dist/scripts/module-add.js +1 -1
- package/dist/scripts/script-runner.d.ts +5 -0
- package/dist/scripts/script-runner.d.ts.map +1 -0
- package/dist/scripts/script-runner.js +25 -0
- package/dist/templates/DocPage.d.ts.map +1 -1
- package/dist/templates/DocPage.js +14 -14
- package/package.json +1 -1
- package/src/__tests__/module-registry.test.ts +74 -0
- package/src/app-shell/(admin)/layout.tsx +5 -3
- package/src/app-shell/(auth)/layout.tsx +5 -3
- package/src/cli.ts +50 -0
- package/src/layouts/AdminLayout.tsx +1 -3
- package/src/layouts/AppProviders.tsx +2 -4
- package/src/layouts/AuthLayout.tsx +1 -3
- package/src/layouts/PublicLayout.tsx +1 -3
- package/src/layouts/RootLayout.tsx +1 -2
- package/src/scripts/db-init.ts +2 -2
- package/src/scripts/db-migrations-sync.ts +1 -1
- package/src/scripts/init-app.ts +13 -10
- package/src/scripts/module-add.ts +1 -3
- package/src/scripts/script-runner.ts +28 -0
- package/src/templates/DocPage.tsx +74 -46
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/module-registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { AVAILABLE_MODULES } from "../scripts/module-add";
|
|
3
|
+
describe("Module Registry", () => {
|
|
4
|
+
describe("AVAILABLE_MODULES", () => {
|
|
5
|
+
it("should have at least one module defined", () => {
|
|
6
|
+
expect(AVAILABLE_MODULES.length).toBeGreaterThan(0);
|
|
7
|
+
});
|
|
8
|
+
it("should have auth module defined", () => {
|
|
9
|
+
const authModule = AVAILABLE_MODULES.find((m) => m.name === "auth");
|
|
10
|
+
expect(authModule).toBeDefined();
|
|
11
|
+
expect(authModule?.package).toBe("@lastbrain/module-auth");
|
|
12
|
+
expect(authModule?.hasMigrations).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it("should have ai module defined", () => {
|
|
15
|
+
const aiModule = AVAILABLE_MODULES.find((m) => m.name === "ai");
|
|
16
|
+
expect(aiModule).toBeDefined();
|
|
17
|
+
expect(aiModule?.package).toBe("@lastbrain/module-ai");
|
|
18
|
+
expect(aiModule?.hasMigrations).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it("should have all required properties for each module", () => {
|
|
21
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
22
|
+
expect(module.name).toBeDefined();
|
|
23
|
+
expect(module.package).toBeDefined();
|
|
24
|
+
expect(module.displayName).toBeDefined();
|
|
25
|
+
expect(module.description).toBeDefined();
|
|
26
|
+
expect(typeof module.hasMigrations).toBe("boolean");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
it("should have migrations paths when hasMigrations is true", () => {
|
|
30
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
31
|
+
if (module.hasMigrations) {
|
|
32
|
+
expect(module.migrationsPath).toBeDefined();
|
|
33
|
+
expect(module.migrationsDownPath).toBeDefined();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("should have unique module names", () => {
|
|
38
|
+
const names = AVAILABLE_MODULES.map((m) => m.name);
|
|
39
|
+
const uniqueNames = new Set(names);
|
|
40
|
+
expect(names.length).toBe(uniqueNames.size);
|
|
41
|
+
});
|
|
42
|
+
it("should have unique package names", () => {
|
|
43
|
+
const packages = AVAILABLE_MODULES.map((m) => m.package);
|
|
44
|
+
const uniquePackages = new Set(packages);
|
|
45
|
+
expect(packages.length).toBe(uniquePackages.size);
|
|
46
|
+
});
|
|
47
|
+
it("should have display names with emoji", () => {
|
|
48
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
49
|
+
// Check if displayName contains at least one emoji (basic check)
|
|
50
|
+
expect(module.displayName).toMatch(/[\u{1F300}-\u{1F9FF}]/u);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
it("should have non-empty descriptions", () => {
|
|
54
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
55
|
+
expect(module.description.length).toBeGreaterThan(0);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it("should have valid package names", () => {
|
|
59
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
60
|
+
expect(module.package).toMatch(/^@lastbrain\/module-/);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export default function AdminShellLayout({ children, }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(admin)/layout.tsx"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(admin)/layout.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,2CAQA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function AdminShellLayout({ children }) {
|
|
3
|
+
export default function AdminShellLayout({ children, }) {
|
|
4
4
|
return (_jsxs("div", { className: "mx-auto max-w-5xl px-4 py-16", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Section Admin" }), _jsx("p", { className: "text-slate-600", children: "Gestion avanc\u00E9e des modules." }), children] }));
|
|
5
5
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export default function AuthLayout({ children, }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(auth)/layout.tsx"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(auth)/layout.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,2CAQA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function AuthLayout({ children }) {
|
|
3
|
+
export default function AuthLayout({ children, }) {
|
|
4
4
|
return (_jsxs("div", { className: "mx-auto max-w-5xl px-4 py-16", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Section Auth" }), _jsx("p", { className: "text-slate-600", children: "Les pages authentifi\u00E9es regroup\u00E9es ici." }), children] }));
|
|
5
5
|
}
|
package/dist/cli.js
CHANGED
|
@@ -85,4 +85,54 @@ program
|
|
|
85
85
|
process.exit(1);
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
+
// Commandes de build et maintenance
|
|
89
|
+
program
|
|
90
|
+
.command("module:build")
|
|
91
|
+
.description("Build les configurations de modules")
|
|
92
|
+
.action(async () => {
|
|
93
|
+
try {
|
|
94
|
+
const { runModuleBuild } = await import("./scripts/module-build.js");
|
|
95
|
+
await runModuleBuild();
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error("❌ Erreur lors du build des modules:", error);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
program
|
|
103
|
+
.command("db:init")
|
|
104
|
+
.description("Initialise la base de données Supabase")
|
|
105
|
+
.action(async () => {
|
|
106
|
+
try {
|
|
107
|
+
await import("./scripts/db-init.js");
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error("❌ Erreur lors de l'initialisation de la DB:", error);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
program
|
|
115
|
+
.command("db:migrations:sync")
|
|
116
|
+
.description("Synchronise les migrations de modules")
|
|
117
|
+
.action(async () => {
|
|
118
|
+
try {
|
|
119
|
+
await import("./scripts/db-migrations-sync.js");
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error("❌ Erreur lors de la sync des migrations:", error);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
program
|
|
127
|
+
.command("readme:create")
|
|
128
|
+
.description("Génère le fichier README")
|
|
129
|
+
.action(async () => {
|
|
130
|
+
try {
|
|
131
|
+
await import("./scripts/readme-build.js");
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.error("❌ Erreur lors de la création du README:", error);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
88
138
|
program.parse();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare function AdminLayout({ children }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=AdminLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayout.tsx"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"AdminLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AdminLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAEtE"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { PropsWithChildren } from "react";
|
|
2
1
|
import type { User } from "@supabase/supabase-js";
|
|
3
2
|
export declare function useModules(): import("@lastbrain/core").ModuleBuildConfig[];
|
|
4
3
|
export declare function useNotifications(): {
|
|
@@ -9,5 +8,7 @@ export declare function useAuth(): {
|
|
|
9
8
|
loading: boolean;
|
|
10
9
|
isSuperAdmin: boolean;
|
|
11
10
|
};
|
|
12
|
-
export declare function AppProviders({ children }:
|
|
11
|
+
export declare function AppProviders({ children }: {
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
14
|
//# sourceMappingURL=AppProviders.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppProviders.d.ts","sourceRoot":"","sources":["../../src/layouts/AppProviders.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AppProviders.d.ts","sourceRoot":"","sources":["../../src/layouts/AppProviders.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAclD,wBAAgB,UAAU,kDAEzB;AAED,wBAAgB,gBAAgB;cAf4B,MAAM,EAAE;EAiBnE;AAED,wBAAgB,OAAO;UAjBf,IAAI,GAAG,IAAI;aACR,OAAO;kBACF,OAAO;EAiBtB;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CA0BvE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare function AuthLayout({ children }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=AuthLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayout.tsx"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"AuthLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/AuthLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAErE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare function PublicLayout({ children }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=PublicLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PublicLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayout.tsx"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"PublicLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/PublicLayout.tsx"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAEvE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare function RootLayout({ children }: {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
3
4
|
//# sourceMappingURL=RootLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RootLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/RootLayout.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RootLayout.d.ts","sourceRoot":"","sources":["../../src/layouts/RootLayout.tsx"],"names":[],"mappings":"AAMA,wBAAgB,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAmBrE"}
|
package/dist/scripts/db-init.js
CHANGED
|
@@ -7,11 +7,11 @@ const migrationsDir = path.join(projectRoot, "supabase/migrations");
|
|
|
7
7
|
function ensureDirectory(dir) {
|
|
8
8
|
fs.mkdirSync(dir, { recursive: true });
|
|
9
9
|
}
|
|
10
|
-
var
|
|
11
|
-
(function (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})(
|
|
10
|
+
var _CopyStrategy;
|
|
11
|
+
(function (_CopyStrategy) {
|
|
12
|
+
_CopyStrategy[_CopyStrategy["overwrite"] = 0] = "overwrite";
|
|
13
|
+
_CopyStrategy[_CopyStrategy["skip"] = 1] = "skip";
|
|
14
|
+
})(_CopyStrategy || (_CopyStrategy = {}));
|
|
15
15
|
function getModulePackageDir(moduleName) {
|
|
16
16
|
return path.join(projectRoot, "node_modules", ...moduleName.split("/"));
|
|
17
17
|
}
|
package/dist/scripts/init-app.js
CHANGED
|
@@ -223,6 +223,7 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
|
|
|
223
223
|
// Ajouter les dépendances HeroUI si nécessaire
|
|
224
224
|
if (useHeroUI) {
|
|
225
225
|
// Tous les packages HeroUI nécessaires (car @lastbrain/ui les ré-exporte)
|
|
226
|
+
requiredDeps["@heroui/system"] = "^2.4.23";
|
|
226
227
|
requiredDeps["@heroui/theme"] = "^2.4.23";
|
|
227
228
|
requiredDeps["@heroui/accordion"] = "^2.2.24";
|
|
228
229
|
requiredDeps["@heroui/alert"] = "^2.2.27";
|
|
@@ -257,7 +258,6 @@ async function addDependencies(targetDir, useHeroUI, withAuth, selectedModules =
|
|
|
257
258
|
requiredDeps["@heroui/switch"] = "^2.2.24";
|
|
258
259
|
requiredDeps["@heroui/table"] = "^2.2.27";
|
|
259
260
|
requiredDeps["@heroui/tabs"] = "^2.2.24";
|
|
260
|
-
requiredDeps["@heroui/system"] = "^2.4.23"; // Ajout pour HeroUIProvider
|
|
261
261
|
requiredDeps["@heroui/toast"] = "^2.0.17";
|
|
262
262
|
requiredDeps["@heroui/tooltip"] = "^2.2.24";
|
|
263
263
|
requiredDeps["@heroui/user"] = "^2.2.22";
|
|
@@ -903,21 +903,24 @@ async function addScriptsToPackageJson(targetDir) {
|
|
|
903
903
|
// Détecter si le projet cible est dans un workspace
|
|
904
904
|
const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
|
|
905
905
|
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
906
|
-
let scriptsPrefix = "
|
|
907
|
-
if (targetIsInMonorepo) {
|
|
908
|
-
//
|
|
909
|
-
scriptsPrefix = "
|
|
906
|
+
let scriptsPrefix = "lastbrain";
|
|
907
|
+
if (!targetIsInMonorepo) {
|
|
908
|
+
// Hors monorepo, utiliser le chemin direct vers le CLI
|
|
909
|
+
scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
|
|
910
910
|
}
|
|
911
911
|
const scripts = {
|
|
912
|
+
predev: targetIsInMonorepo
|
|
913
|
+
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
914
|
+
: "echo 'No prebuild needed outside monorepo'",
|
|
912
915
|
dev: "next dev",
|
|
913
916
|
build: "next build",
|
|
914
917
|
start: "next start",
|
|
915
918
|
lint: "next lint",
|
|
916
|
-
lastbrain: "node node_modules/@lastbrain/app/dist/cli.js",
|
|
917
|
-
"build:modules":
|
|
918
|
-
"db:migrations:sync":
|
|
919
|
-
"db:init":
|
|
920
|
-
"readme:create":
|
|
919
|
+
lastbrain: targetIsInMonorepo ? "lastbrain" : "node node_modules/@lastbrain/app/dist/cli.js",
|
|
920
|
+
"build:modules": `${scriptsPrefix} module:build`,
|
|
921
|
+
"db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
|
|
922
|
+
"db:init": `${scriptsPrefix} db:init`,
|
|
923
|
+
"readme:create": `${scriptsPrefix} readme:create`,
|
|
921
924
|
};
|
|
922
925
|
pkg.scripts = { ...pkg.scripts, ...scripts };
|
|
923
926
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAGD,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAsB/C,CAAC;AAEF,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"module-add.d.ts","sourceRoot":"","sources":["../../src/scripts/module-add.ts"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAGD,eAAO,MAAM,iBAAiB,EAAE,gBAAgB,EAsB/C,CAAC;AAEF,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,iBAsMpE"}
|
|
@@ -63,7 +63,7 @@ export async function addModule(moduleName, targetDir) {
|
|
|
63
63
|
process.exit(1);
|
|
64
64
|
}
|
|
65
65
|
// 5. Copier les migrations du module
|
|
66
|
-
|
|
66
|
+
const copiedMigrationFiles = [];
|
|
67
67
|
if (module.hasMigrations) {
|
|
68
68
|
console.log(chalk.yellow("\n📋 Copie des migrations du module..."));
|
|
69
69
|
// Trouver le chemin du module installé
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-runner.d.ts","sourceRoot":"","sources":["../../src/scripts/script-runner.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,iBAqBtE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Exécute un script via node en ajustant le chemin
|
|
5
|
+
*/
|
|
6
|
+
export async function runScript(scriptName, args = []) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const scriptPath = path.join(__dirname, `${scriptName}.js`);
|
|
9
|
+
const child = spawn("node", [scriptPath, ...args], {
|
|
10
|
+
stdio: "inherit",
|
|
11
|
+
env: { ...process.env, PROJECT_ROOT: process.cwd() }
|
|
12
|
+
});
|
|
13
|
+
child.on("close", (code) => {
|
|
14
|
+
if (code === 0) {
|
|
15
|
+
resolve();
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
reject(new Error(`Script ${scriptName} exited with code ${code}`));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
child.on("error", (error) => {
|
|
22
|
+
reject(error);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocPage.d.ts","sourceRoot":"","sources":["../../src/templates/DocPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DocPage.d.ts","sourceRoot":"","sources":["../../src/templates/DocPage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AA6FnD,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EACF,SAAS,GACT,WAAW,GACX,SAAS,GACT,QAAQ,GACR,SAAS,GACT,SAAS,GACT,SAAS,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAClC;AAED,wBAAgB,OAAO,CAAC,EAAE,OAAY,EAAE,cAAc,EAAE,EAAE,YAAY,2CAySrE"}
|
|
@@ -5,6 +5,19 @@ import { useState, useEffect } from "react";
|
|
|
5
5
|
import { Card, CardBody, CardHeader, Listbox, ListboxItem, Chip, Button, Drawer, DrawerContent, DrawerHeader, DrawerBody, Snippet, } from "@lastbrain/ui";
|
|
6
6
|
import { Menu, Home, Sparkles, Rocket, Building2, Package, Database, Palette, BookOpen, Link, Blocks, HardDrive, } from "lucide-react";
|
|
7
7
|
import { DefaultDocumentation } from "./DefaultDoc.js";
|
|
8
|
+
const NavigationListbox = ({ navigationItems, selectedModule, scrollToSection, setSelectedModule, }) => (_jsx(Listbox, { "aria-label": "Navigation", selectionMode: "single", selectedKeys: selectedModule ? [selectedModule] : [], onSelectionChange: (keys) => {
|
|
9
|
+
const key = Array.from(keys)[0];
|
|
10
|
+
if (key) {
|
|
11
|
+
scrollToSection(key);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
setSelectedModule("");
|
|
15
|
+
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
16
|
+
}
|
|
17
|
+
}, items: navigationItems, children: (item) => {
|
|
18
|
+
const IconComponent = item.icon;
|
|
19
|
+
return (_jsx(ListboxItem, { textValue: item.name, description: item.description, color: item.color, variant: "solid", endContent: item.number && (_jsx(Chip, { size: "sm", color: "primary", children: item.number ?? 0 })), className: `${selectedModule === item.id ? "bg-default-200/40" : ""}`, startContent: _jsx(IconComponent, { size: 18, className: "shrink-0" }), children: item.name }, item.id));
|
|
20
|
+
} }));
|
|
8
21
|
export function DocPage({ modules = [], defaultContent }) {
|
|
9
22
|
const [selectedModule, setSelectedModule] = useState("default");
|
|
10
23
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
|
@@ -150,20 +163,7 @@ export function DocPage({ modules = [], defaultContent }) {
|
|
|
150
163
|
color: "primary",
|
|
151
164
|
})),
|
|
152
165
|
];
|
|
153
|
-
|
|
154
|
-
const key = Array.from(keys)[0];
|
|
155
|
-
if (key) {
|
|
156
|
-
scrollToSection(key);
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
setSelectedModule("");
|
|
160
|
-
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
161
|
-
}
|
|
162
|
-
}, items: navigationItems, children: (item) => {
|
|
163
|
-
const IconComponent = item.icon;
|
|
164
|
-
return (_jsx(ListboxItem, { textValue: item.name, description: item.description, color: item.color, variant: "solid", endContent: item.number && (_jsx(Chip, { size: "sm", color: "primary", children: item.number ?? 0 })), className: `${selectedModule === item.id ? "bg-default-200/40" : ""}`, startContent: _jsx(IconComponent, { size: 18, className: "shrink-0" }), children: item.name }, item.id));
|
|
165
|
-
} }));
|
|
166
|
-
return (_jsx("div", { className: "w-full pt-8 md:pt-12 pb-24 lg:pb-8", children: _jsxs("div", { className: "container mx-auto md:px-4 py-8", children: [_jsx("div", { className: "fixed w-full h-16 left-0 bottom-0 bg-background/20 backdrop-blur-lg z-50 lg:hidden p-2", children: _jsx("div", { className: "flex justify-center", children: _jsx(Button, { isIconOnly: true, variant: "solid", onPress: () => setIsDrawerOpen(true), children: _jsx(Menu, { size: 24 }) }) }) }), _jsx(Drawer, { isOpen: isDrawerOpen, onOpenChange: setIsDrawerOpen, placement: "left", children: _jsxs(DrawerContent, { children: [_jsx(DrawerHeader, { children: _jsx("h2", { className: "text-xl font-semibold", children: "Navigation" }) }), _jsx(DrawerBody, { children: _jsx(NavigationListbox, {}) })] }) }), _jsxs("div", { className: "flex gap-8", children: [_jsx("aside", { className: "hidden lg:block w-64 shrink-0 sticky top-18 self-start", children: _jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-2", children: _jsx("h2", { className: "text-xl font-semibold", children: "Navigation" }) }), _jsx(CardBody, { children: _jsx(NavigationListbox, {}) })] }) }), _jsxs("main", { className: "flex-1 w-full min-w-0 space-y-8", children: [defaultContent ? (_jsx("div", { children: defaultContent })) : (_jsx(DefaultDocumentation, {})), modules.length > 0 && (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { id: "section-modules", className: "scroll-mt-32", children: [_jsx(CardHeader, { children: _jsx("h2", { className: "text-2xl font-semibold", children: "Modules disponibles" }) }), _jsxs(CardBody, { children: [_jsx("p", { className: "text-slate-600 dark:text-slate-400 mb-4", children: "Voici la liste de tous les modules disponibles dans LastBrain. Les modules actifs sont utilis\u00E9s dans votre application." }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: modules.map((module) => (_jsx(Card, { isPressable: module.available, onPress: () => module.available && scrollToSection(module.id), className: `${module.available
|
|
166
|
+
return (_jsx("div", { className: "w-full pt-8 md:pt-12 pb-24 lg:pb-8", children: _jsxs("div", { className: "container mx-auto md:px-4 py-8", children: [_jsx("div", { className: "fixed w-full h-16 left-0 bottom-0 bg-background/20 backdrop-blur-lg z-50 lg:hidden p-2", children: _jsx("div", { className: "flex justify-center", children: _jsx(Button, { isIconOnly: true, variant: "solid", onPress: () => setIsDrawerOpen(true), children: _jsx(Menu, { size: 24 }) }) }) }), _jsx(Drawer, { isOpen: isDrawerOpen, onOpenChange: setIsDrawerOpen, placement: "left", children: _jsxs(DrawerContent, { children: [_jsx(DrawerHeader, { children: _jsx("h2", { className: "text-xl font-semibold", children: "Navigation" }) }), _jsx(DrawerBody, { children: _jsx(NavigationListbox, { navigationItems: navigationItems, selectedModule: selectedModule, scrollToSection: scrollToSection, setSelectedModule: setSelectedModule }) })] }) }), _jsxs("div", { className: "flex gap-8", children: [_jsx("aside", { className: "hidden lg:block w-64 shrink-0 sticky top-18 self-start", children: _jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-2", children: _jsx("h2", { className: "text-xl font-semibold", children: "Navigation" }) }), _jsx(CardBody, { children: _jsx(NavigationListbox, { navigationItems: navigationItems, selectedModule: selectedModule, scrollToSection: scrollToSection, setSelectedModule: setSelectedModule }) })] }) }), _jsxs("main", { className: "flex-1 w-full min-w-0 space-y-8", children: [defaultContent ? (_jsx("div", { children: defaultContent })) : (_jsx(DefaultDocumentation, {})), modules.length > 0 && (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { id: "section-modules", className: "scroll-mt-32", children: [_jsx(CardHeader, { children: _jsx("h2", { className: "text-2xl font-semibold", children: "Modules disponibles" }) }), _jsxs(CardBody, { children: [_jsx("p", { className: "text-slate-600 dark:text-slate-400 mb-4", children: "Voici la liste de tous les modules disponibles dans LastBrain. Les modules actifs sont utilis\u00E9s dans votre application." }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: modules.map((module) => (_jsx(Card, { isPressable: module.available, onPress: () => module.available && scrollToSection(module.id), className: `${module.available
|
|
167
167
|
? "cursor-pointer hover:shadow-lg"
|
|
168
168
|
: "opacity-70"} transition-shadow`, children: _jsxs(CardBody, { children: [_jsxs("div", { className: "flex items-start justify-between mb-2", children: [_jsx("h3", { className: "text-lg font-semibold", children: module.name }), _jsx(Chip, { size: "sm", color: module.available ? "success" : "warning", variant: "flat", children: module.available ? "Actif" : "Inactif" })] }), _jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400 mb-2", children: module.description }), !module.available && (_jsxs("div", { className: "flex justify-between items-center text-xs text-default-700 mt-2", children: [_jsx("span", { children: "Pour activer : " }), _jsx(Snippet, { hideSymbol: true, color: "primary", children: `pnpm lastbrain add-module ${module.id}` })] }))] }) }, module.id))) })] })] }), modules
|
|
169
169
|
.filter((m) => m.available)
|
package/package.json
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { AVAILABLE_MODULES } from "../scripts/module-add";
|
|
3
|
+
|
|
4
|
+
describe("Module Registry", () => {
|
|
5
|
+
describe("AVAILABLE_MODULES", () => {
|
|
6
|
+
it("should have at least one module defined", () => {
|
|
7
|
+
expect(AVAILABLE_MODULES.length).toBeGreaterThan(0);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should have auth module defined", () => {
|
|
11
|
+
const authModule = AVAILABLE_MODULES.find((m) => m.name === "auth");
|
|
12
|
+
expect(authModule).toBeDefined();
|
|
13
|
+
expect(authModule?.package).toBe("@lastbrain/module-auth");
|
|
14
|
+
expect(authModule?.hasMigrations).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should have ai module defined", () => {
|
|
18
|
+
const aiModule = AVAILABLE_MODULES.find((m) => m.name === "ai");
|
|
19
|
+
expect(aiModule).toBeDefined();
|
|
20
|
+
expect(aiModule?.package).toBe("@lastbrain/module-ai");
|
|
21
|
+
expect(aiModule?.hasMigrations).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should have all required properties for each module", () => {
|
|
25
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
26
|
+
expect(module.name).toBeDefined();
|
|
27
|
+
expect(module.package).toBeDefined();
|
|
28
|
+
expect(module.displayName).toBeDefined();
|
|
29
|
+
expect(module.description).toBeDefined();
|
|
30
|
+
expect(typeof module.hasMigrations).toBe("boolean");
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should have migrations paths when hasMigrations is true", () => {
|
|
35
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
36
|
+
if (module.hasMigrations) {
|
|
37
|
+
expect(module.migrationsPath).toBeDefined();
|
|
38
|
+
expect(module.migrationsDownPath).toBeDefined();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should have unique module names", () => {
|
|
44
|
+
const names = AVAILABLE_MODULES.map((m) => m.name);
|
|
45
|
+
const uniqueNames = new Set(names);
|
|
46
|
+
expect(names.length).toBe(uniqueNames.size);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("should have unique package names", () => {
|
|
50
|
+
const packages = AVAILABLE_MODULES.map((m) => m.package);
|
|
51
|
+
const uniquePackages = new Set(packages);
|
|
52
|
+
expect(packages.length).toBe(uniquePackages.size);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should have display names with emoji", () => {
|
|
56
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
57
|
+
// Check if displayName contains at least one emoji (basic check)
|
|
58
|
+
expect(module.displayName).toMatch(/[\u{1F300}-\u{1F9FF}]/u);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should have non-empty descriptions", () => {
|
|
63
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
64
|
+
expect(module.description.length).toBeGreaterThan(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should have valid package names", () => {
|
|
69
|
+
AVAILABLE_MODULES.forEach((module) => {
|
|
70
|
+
expect(module.package).toMatch(/^@lastbrain\/module-/);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export default function AdminShellLayout({
|
|
4
|
+
children,
|
|
5
|
+
}: {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}) {
|
|
6
8
|
return (
|
|
7
9
|
<div className="mx-auto max-w-5xl px-4 py-16">
|
|
8
10
|
<h1 className="text-3xl font-bold">Section Admin</h1>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export default function AuthLayout({
|
|
4
|
+
children,
|
|
5
|
+
}: {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}) {
|
|
6
8
|
return (
|
|
7
9
|
<div className="mx-auto max-w-5xl px-4 py-16">
|
|
8
10
|
<h1 className="text-3xl font-bold">Section Auth</h1>
|
package/src/cli.ts
CHANGED
|
@@ -93,4 +93,54 @@ program
|
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// Commandes de build et maintenance
|
|
97
|
+
program
|
|
98
|
+
.command("module:build")
|
|
99
|
+
.description("Build les configurations de modules")
|
|
100
|
+
.action(async () => {
|
|
101
|
+
try {
|
|
102
|
+
const { runModuleBuild } = await import("./scripts/module-build.js");
|
|
103
|
+
await runModuleBuild();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error("❌ Erreur lors du build des modules:", error);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
program
|
|
111
|
+
.command("db:init")
|
|
112
|
+
.description("Initialise la base de données Supabase")
|
|
113
|
+
.action(async () => {
|
|
114
|
+
try {
|
|
115
|
+
await import("./scripts/db-init.js");
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error("❌ Erreur lors de l'initialisation de la DB:", error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
program
|
|
123
|
+
.command("db:migrations:sync")
|
|
124
|
+
.description("Synchronise les migrations de modules")
|
|
125
|
+
.action(async () => {
|
|
126
|
+
try {
|
|
127
|
+
await import("./scripts/db-migrations-sync.js");
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error("❌ Erreur lors de la sync des migrations:", error);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
program
|
|
135
|
+
.command("readme:create")
|
|
136
|
+
.description("Génère le fichier README")
|
|
137
|
+
.action(async () => {
|
|
138
|
+
try {
|
|
139
|
+
await import("./scripts/readme-build.js");
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error("❌ Erreur lors de la création du README:", error);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
96
146
|
program.parse();
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function AdminLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <div className="pt-18 px-2 md:px-5">{children}</div>;
|
|
7
5
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
3
|
import { createContext, useContext, useMemo } from "react";
|
|
5
4
|
import { getModuleConfigs } from "../modules/module-loader.js";
|
|
6
|
-
import {
|
|
5
|
+
import { ToastProvider } from "@lastbrain/ui";
|
|
7
6
|
import { useAuthSession } from "../auth/useAuthSession.js";
|
|
8
7
|
import type { User } from "@supabase/supabase-js";
|
|
9
|
-
import { useRouter } from "next/navigation.js";
|
|
10
8
|
|
|
11
9
|
const ModuleContext = createContext(getModuleConfigs());
|
|
12
10
|
const NotificationContext = createContext({ messages: [] as string[] });
|
|
@@ -32,7 +30,7 @@ export function useAuth() {
|
|
|
32
30
|
return useContext(AuthContext);
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
export function AppProviders({ children }:
|
|
33
|
+
export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
36
34
|
const modules = useMemo(() => getModuleConfigs(), []);
|
|
37
35
|
const notifications = useMemo(() => ({ messages: [] as string[] }), []);
|
|
38
36
|
const { user, loading, isSuperAdmin } = useAuthSession();
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function AuthLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function AuthLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <div className="pt-18 px-2 md:px-5 ">{children}</div>;
|
|
7
5
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function PublicLayout({ children }: PropsWithChildren<{}>) {
|
|
3
|
+
export function PublicLayout({ children }: { children: React.ReactNode }) {
|
|
6
4
|
return <section className=" px-4 ">{children}</section>;
|
|
7
5
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import type { PropsWithChildren } from "react";
|
|
4
3
|
import { ThemeProvider } from "next-themes";
|
|
5
4
|
import { AppProviders } from "./AppProviders.js";
|
|
6
5
|
|
|
7
6
|
// Note: L'app Next.js doit importer son propre globals.css dans son layout
|
|
8
|
-
export function RootLayout({ children }:
|
|
7
|
+
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
9
8
|
return (
|
|
10
9
|
<html lang="fr" suppressHydrationWarning>
|
|
11
10
|
<body className="min-h-screen">
|
package/src/scripts/db-init.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn, spawnSync, execSync, execFileSync } from "node:child_process";
|
|
1
|
+
import { spawn, spawnSync, execSync as _execSync, execFileSync as _execFileSync } from "node:child_process";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -282,7 +282,7 @@ async function main() {
|
|
|
282
282
|
console.log("⚙️ Starting Supabase...");
|
|
283
283
|
try {
|
|
284
284
|
runSupabase("start");
|
|
285
|
-
} catch (
|
|
285
|
+
} catch (_error) {
|
|
286
286
|
console.warn("⚠️ Supabase start had issues, continuing...");
|
|
287
287
|
}
|
|
288
288
|
|
package/src/scripts/init-app.ts
CHANGED
|
@@ -292,6 +292,7 @@ async function addDependencies(
|
|
|
292
292
|
// Ajouter les dépendances HeroUI si nécessaire
|
|
293
293
|
if (useHeroUI) {
|
|
294
294
|
// Tous les packages HeroUI nécessaires (car @lastbrain/ui les ré-exporte)
|
|
295
|
+
requiredDeps["@heroui/system"] = "^2.4.23";
|
|
295
296
|
requiredDeps["@heroui/theme"] = "^2.4.23";
|
|
296
297
|
requiredDeps["@heroui/accordion"] = "^2.2.24";
|
|
297
298
|
requiredDeps["@heroui/alert"] = "^2.2.27";
|
|
@@ -326,7 +327,6 @@ async function addDependencies(
|
|
|
326
327
|
requiredDeps["@heroui/switch"] = "^2.2.24";
|
|
327
328
|
requiredDeps["@heroui/table"] = "^2.2.27";
|
|
328
329
|
requiredDeps["@heroui/tabs"] = "^2.2.24";
|
|
329
|
-
requiredDeps["@heroui/system"] = "^2.4.23"; // Ajout pour HeroUIProvider
|
|
330
330
|
requiredDeps["@heroui/toast"] = "^2.0.17";
|
|
331
331
|
requiredDeps["@heroui/tooltip"] = "^2.2.24";
|
|
332
332
|
requiredDeps["@heroui/user"] = "^2.2.22";
|
|
@@ -1054,23 +1054,26 @@ async function addScriptsToPackageJson(targetDir: string) {
|
|
|
1054
1054
|
const targetIsInMonorepo = fs.existsSync(path.join(targetDir, "../../../packages/core/package.json")) ||
|
|
1055
1055
|
fs.existsSync(path.join(targetDir, "../../packages/core/package.json"));
|
|
1056
1056
|
|
|
1057
|
-
let scriptsPrefix = "
|
|
1057
|
+
let scriptsPrefix = "lastbrain";
|
|
1058
1058
|
|
|
1059
|
-
if (targetIsInMonorepo) {
|
|
1060
|
-
//
|
|
1061
|
-
scriptsPrefix = "
|
|
1059
|
+
if (!targetIsInMonorepo) {
|
|
1060
|
+
// Hors monorepo, utiliser le chemin direct vers le CLI
|
|
1061
|
+
scriptsPrefix = "node node_modules/@lastbrain/app/dist/cli.js";
|
|
1062
1062
|
}
|
|
1063
1063
|
|
|
1064
1064
|
const scripts = {
|
|
1065
|
+
predev: targetIsInMonorepo
|
|
1066
|
+
? "pnpm --filter @lastbrain/core build && pnpm --filter @lastbrain/ui build && pnpm --filter @lastbrain/module-auth build && pnpm --filter @lastbrain/module-ai build"
|
|
1067
|
+
: "echo 'No prebuild needed outside monorepo'",
|
|
1065
1068
|
dev: "next dev",
|
|
1066
1069
|
build: "next build",
|
|
1067
1070
|
start: "next start",
|
|
1068
1071
|
lint: "next lint",
|
|
1069
|
-
lastbrain: "node node_modules/@lastbrain/app/dist/cli.js",
|
|
1070
|
-
"build:modules":
|
|
1071
|
-
"db:migrations:sync":
|
|
1072
|
-
"db:init":
|
|
1073
|
-
"readme:create":
|
|
1072
|
+
lastbrain: targetIsInMonorepo ? "lastbrain" : "node node_modules/@lastbrain/app/dist/cli.js",
|
|
1073
|
+
"build:modules": `${scriptsPrefix} module:build`,
|
|
1074
|
+
"db:migrations:sync": `${scriptsPrefix} db:migrations:sync`,
|
|
1075
|
+
"db:init": `${scriptsPrefix} db:init`,
|
|
1076
|
+
"readme:create": `${scriptsPrefix} readme:create`,
|
|
1074
1077
|
};
|
|
1075
1078
|
|
|
1076
1079
|
pkg.scripts = { ...pkg.scripts, ...scripts };
|
|
@@ -87,9 +87,7 @@ export async function addModule(moduleName: string, targetDir: string) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// 5. Copier les migrations du module
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (module.hasMigrations) {
|
|
90
|
+
const copiedMigrationFiles: string[] = []; if (module.hasMigrations) {
|
|
93
91
|
console.log(chalk.yellow("\n📋 Copie des migrations du module..."));
|
|
94
92
|
|
|
95
93
|
// Trouver le chemin du module installé
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Exécute un script via node en ajustant le chemin
|
|
6
|
+
*/
|
|
7
|
+
export async function runScript(scriptName: string, args: string[] = []) {
|
|
8
|
+
return new Promise<void>((resolve, reject) => {
|
|
9
|
+
const scriptPath = path.join(__dirname, `${scriptName}.js`);
|
|
10
|
+
|
|
11
|
+
const child = spawn("node", [scriptPath, ...args], {
|
|
12
|
+
stdio: "inherit",
|
|
13
|
+
env: { ...process.env, PROJECT_ROOT: process.cwd() }
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
child.on("close", (code) => {
|
|
17
|
+
if (code === 0) {
|
|
18
|
+
resolve();
|
|
19
|
+
} else {
|
|
20
|
+
reject(new Error(`Script ${scriptName} exited with code ${code}`));
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
child.on("error", (error) => {
|
|
25
|
+
reject(error);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -31,6 +31,68 @@ import {
|
|
|
31
31
|
} from "lucide-react";
|
|
32
32
|
import { DefaultDocumentation } from "./DefaultDoc.js";
|
|
33
33
|
|
|
34
|
+
// Composant NavigationListbox séparé pour éviter la recréation
|
|
35
|
+
interface NavigationListboxProps {
|
|
36
|
+
navigationItems: Array<{
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
icon: any;
|
|
41
|
+
color?: string;
|
|
42
|
+
number?: number;
|
|
43
|
+
}>;
|
|
44
|
+
selectedModule: string;
|
|
45
|
+
scrollToSection: (id: string) => void;
|
|
46
|
+
setSelectedModule: (id: string) => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const NavigationListbox: React.FC<NavigationListboxProps> = ({
|
|
50
|
+
navigationItems,
|
|
51
|
+
selectedModule,
|
|
52
|
+
scrollToSection,
|
|
53
|
+
setSelectedModule,
|
|
54
|
+
}) => (
|
|
55
|
+
<Listbox
|
|
56
|
+
aria-label="Navigation"
|
|
57
|
+
selectionMode="single"
|
|
58
|
+
selectedKeys={selectedModule ? [selectedModule] : []}
|
|
59
|
+
onSelectionChange={(keys) => {
|
|
60
|
+
const key = Array.from(keys)[0] as string;
|
|
61
|
+
if (key) {
|
|
62
|
+
scrollToSection(key);
|
|
63
|
+
} else {
|
|
64
|
+
setSelectedModule("");
|
|
65
|
+
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
66
|
+
}
|
|
67
|
+
}}
|
|
68
|
+
items={navigationItems}
|
|
69
|
+
>
|
|
70
|
+
{(item: any) => {
|
|
71
|
+
const IconComponent = item.icon;
|
|
72
|
+
return (
|
|
73
|
+
<ListboxItem
|
|
74
|
+
key={item.id}
|
|
75
|
+
textValue={item.name}
|
|
76
|
+
description={item.description}
|
|
77
|
+
color={item.color}
|
|
78
|
+
variant="solid"
|
|
79
|
+
endContent={
|
|
80
|
+
item.number && (
|
|
81
|
+
<Chip size="sm" color="primary">
|
|
82
|
+
{item.number ?? 0}
|
|
83
|
+
</Chip>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
className={`${selectedModule === item.id ? "bg-default-200/40" : ""}`}
|
|
87
|
+
startContent={<IconComponent size={18} className="shrink-0" />}
|
|
88
|
+
>
|
|
89
|
+
{item.name}
|
|
90
|
+
</ListboxItem>
|
|
91
|
+
);
|
|
92
|
+
}}
|
|
93
|
+
</Listbox>
|
|
94
|
+
);
|
|
95
|
+
|
|
34
96
|
interface ModuleDocConfig {
|
|
35
97
|
id: string;
|
|
36
98
|
name: string;
|
|
@@ -207,50 +269,6 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
|
|
|
207
269
|
})),
|
|
208
270
|
];
|
|
209
271
|
|
|
210
|
-
const NavigationListbox = () => (
|
|
211
|
-
<Listbox
|
|
212
|
-
aria-label="Navigation"
|
|
213
|
-
selectionMode="single"
|
|
214
|
-
selectedKeys={selectedModule ? [selectedModule] : []}
|
|
215
|
-
onSelectionChange={(keys) => {
|
|
216
|
-
const key = Array.from(keys)[0] as string;
|
|
217
|
-
if (key) {
|
|
218
|
-
scrollToSection(key);
|
|
219
|
-
} else {
|
|
220
|
-
setSelectedModule("");
|
|
221
|
-
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
222
|
-
}
|
|
223
|
-
}}
|
|
224
|
-
items={navigationItems}
|
|
225
|
-
>
|
|
226
|
-
{(item: any) => {
|
|
227
|
-
const IconComponent = item.icon;
|
|
228
|
-
return (
|
|
229
|
-
<ListboxItem
|
|
230
|
-
key={item.id}
|
|
231
|
-
textValue={item.name}
|
|
232
|
-
description={item.description}
|
|
233
|
-
color={item.color}
|
|
234
|
-
variant="solid"
|
|
235
|
-
endContent={
|
|
236
|
-
item.number && (
|
|
237
|
-
<Chip size="sm" color="primary">
|
|
238
|
-
{item.number ?? 0}
|
|
239
|
-
</Chip>
|
|
240
|
-
)
|
|
241
|
-
}
|
|
242
|
-
className={`${
|
|
243
|
-
selectedModule === item.id ? "bg-default-200/40" : ""
|
|
244
|
-
}`}
|
|
245
|
-
startContent={<IconComponent size={18} className="shrink-0" />}
|
|
246
|
-
>
|
|
247
|
-
{item.name}
|
|
248
|
-
</ListboxItem>
|
|
249
|
-
);
|
|
250
|
-
}}
|
|
251
|
-
</Listbox>
|
|
252
|
-
);
|
|
253
|
-
|
|
254
272
|
return (
|
|
255
273
|
<div className="w-full pt-8 md:pt-12 pb-24 lg:pb-8">
|
|
256
274
|
<div className="container mx-auto md:px-4 py-8">
|
|
@@ -278,7 +296,12 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
|
|
|
278
296
|
<h2 className="text-xl font-semibold">Navigation</h2>
|
|
279
297
|
</DrawerHeader>
|
|
280
298
|
<DrawerBody>
|
|
281
|
-
<NavigationListbox
|
|
299
|
+
<NavigationListbox
|
|
300
|
+
navigationItems={navigationItems}
|
|
301
|
+
selectedModule={selectedModule}
|
|
302
|
+
scrollToSection={scrollToSection}
|
|
303
|
+
setSelectedModule={setSelectedModule}
|
|
304
|
+
/>
|
|
282
305
|
</DrawerBody>
|
|
283
306
|
</DrawerContent>
|
|
284
307
|
</Drawer>
|
|
@@ -291,7 +314,12 @@ export function DocPage({ modules = [], defaultContent }: DocPageProps) {
|
|
|
291
314
|
<h2 className="text-xl font-semibold">Navigation</h2>
|
|
292
315
|
</CardHeader>
|
|
293
316
|
<CardBody>
|
|
294
|
-
<NavigationListbox
|
|
317
|
+
<NavigationListbox
|
|
318
|
+
navigationItems={navigationItems}
|
|
319
|
+
selectedModule={selectedModule}
|
|
320
|
+
scrollToSection={scrollToSection}
|
|
321
|
+
setSelectedModule={setSelectedModule}
|
|
322
|
+
/>
|
|
295
323
|
</CardBody>
|
|
296
324
|
</Card>
|
|
297
325
|
</aside>
|