@thatopen/services 0.1.3 → 0.3.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.
- package/README.md +59 -46
- package/dist/built-in/index.d.ts +486 -563
- package/dist/cli/lib/npmrc.d.ts +28 -0
- package/dist/cli/lib/npmrc.test.d.ts +1 -0
- package/dist/cli.js +91 -7
- package/dist/core/client.d.ts +10 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +42 -32
- package/dist/types/npm.d.ts +14 -0
- package/dist/vite-env.d.ts +1 -1
- package/docs/builtin/paths.json +74 -70
- package/docs/cli/create.md +28 -28
- package/docs/cli/local-server.md +38 -38
- package/docs/cli/login.md +32 -32
- package/docs/cli/publish.md +31 -31
- package/docs/cli/run.md +26 -26
- package/docs/cli/serve.md +43 -43
- package/docs/cli/swap.md +30 -30
- package/package.json +100 -100
- package/resources/AGENTS.md +40 -40
- package/src/built-in/CDEManager/example.ts +214 -214
- package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
- package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
- package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
- package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
- package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
- package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
- package/src/built-in/UIManager/src/app/example.ts +99 -99
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +142 -142
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +161 -0
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +125 -125
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +126 -0
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +92 -92
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +165 -0
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +135 -161
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +104 -104
- package/src/built-in/index.ts +649 -755
- package/src/cli/templates/app/README.md +241 -241
- package/src/cli/templates/app/index.html +35 -27
- package/src/cli/templates/app/package.json +31 -27
- package/src/cli/templates/app/src/app.ts +37 -0
- package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -0
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -87
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
- package/src/cli/templates/app/src/bim-components/index.ts +1 -1
- package/src/cli/templates/app/src/globals.ts +1 -0
- package/src/cli/templates/app/src/main.ts +340 -56
- package/src/cli/templates/app/src/setups/active-tool-hud.ts +69 -0
- package/src/cli/templates/app/src/setups/camera-tools.ts +63 -0
- package/src/cli/templates/app/src/setups/camera-views.ts +201 -0
- package/src/cli/templates/app/src/setups/card-header.ts +35 -0
- package/src/cli/templates/app/src/setups/clipper-panel.ts +167 -0
- package/src/cli/templates/app/src/setups/clipper-tool.ts +754 -0
- package/src/cli/templates/app/src/setups/clipper.ts +75 -0
- package/src/cli/templates/app/src/setups/cloud-runner.ts +13 -9
- package/src/cli/templates/app/src/setups/commands-panel.ts +239 -0
- package/src/cli/templates/app/src/setups/data-table-panel.ts +2224 -0
- package/src/cli/templates/app/src/setups/exploded-view.ts +246 -0
- package/src/cli/templates/app/src/setups/file-format-icons.ts +95 -0
- package/src/cli/templates/app/src/setups/files-panel.ts +1503 -0
- package/src/cli/templates/app/src/setups/fps-indicator.ts +63 -0
- package/src/cli/templates/app/src/setups/graphics-panel.ts +490 -0
- package/src/cli/templates/app/src/setups/helper-panel.ts +88 -0
- package/src/cli/templates/app/src/setups/hider.ts +98 -0
- package/src/cli/templates/app/src/setups/index.ts +33 -3
- package/src/cli/templates/app/src/setups/inspection.ts +136 -0
- package/src/cli/templates/app/src/setups/measurement-panel.ts +188 -0
- package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +161 -0
- package/src/cli/templates/app/src/setups/measurement-tool.ts +570 -0
- package/src/cli/templates/app/src/setups/measurements.ts +133 -0
- package/src/cli/templates/app/src/setups/model-tree.ts +797 -0
- package/src/cli/templates/app/src/setups/navigation-gizmo.ts +316 -0
- package/src/cli/templates/app/src/setups/objects-panel.ts +127 -0
- package/src/cli/templates/app/src/setups/plans-panel.ts +619 -0
- package/src/cli/templates/app/src/setups/properties-panel.ts +1048 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -0
- package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -0
- package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -0
- package/src/cli/templates/app/src/setups/settings-panel.ts +94 -0
- package/src/cli/templates/app/src/setups/styles-panel.ts +110 -0
- package/src/cli/templates/app/src/setups/styles.ts +375 -0
- package/src/cli/templates/app/src/setups/tool-mode-manager.ts +150 -0
- package/src/cli/templates/app/src/setups/tool-mode.ts +23 -0
- package/src/cli/templates/app/src/setups/toolbar.ts +229 -0
- package/src/cli/templates/app/src/setups/ui-manager.ts +27 -0
- package/src/cli/templates/app/src/setups/visibility-toolbar.ts +498 -0
- package/src/cli/templates/app/src/setups/walkthrough.ts +528 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -0
- package/src/cli/templates/app/src/ui-components/index.ts +2 -1
- package/src/cli/templates/app/tsconfig.json +16 -17
- package/src/cli/templates/app/vite.config.js +45 -42
- package/src/cli/templates/cloud-component/README.md +205 -205
- package/src/cli/templates/cloud-component/_thatopen +5 -5
- package/src/cli/templates/cloud-component/declarations.json +4 -4
- package/src/cli/templates/cloud-component/package.json +21 -21
- package/src/cli/templates/cloud-component/src/main.ts +70 -70
- package/src/cli/templates/cloud-component/tsconfig.json +16 -16
- package/src/cli/templates/cloud-component/vite.config.js +46 -46
- package/src/cli/templates/shared/AGENTS.md +8 -8
- package/src/cli/templates/shared/CLAUDE.md +1 -1
- package/src/cli/templates/shared/_gitignore +5 -4
- package/src/built-in/AppManager/example.ts +0 -86
- package/src/built-in/FileList/example.ts +0 -107
- package/src/built-in/TabbedNavigation/example.ts +0 -115
- package/src/built-in/ViewportsManager/example.ts +0 -106
- package/src/cli/templates/app/src/setups/fragments.ts +0 -18
- package/src/cli/templates/app/src/setups/ifc-loader.ts +0 -12
- package/src/cli/templates/app/src/ui-components/AppPanel/index.ts +0 -160
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
// Cloud Component Entry Point
|
|
2
|
-
//
|
|
3
|
-
// Your component runs on the server as a Node.js process.
|
|
4
|
-
// The execution engine provides these globals — do NOT import them:
|
|
5
|
-
//
|
|
6
|
-
// thatOpenServices — pre-authenticated EngineServicesClient
|
|
7
|
-
// executionParams — parameters passed by the caller (shape defined in ../declarations.json)
|
|
8
|
-
// executionContext — platform-supplied run context: { projectId?, executionId, toolId, toolVersion }
|
|
9
|
-
// Use executionContext.projectId to scope uploads/lookups to the launching project.
|
|
10
|
-
// Undefined when the component is run outside a project context.
|
|
11
|
-
// executionReporter — { message(msg), error(msg), progress(pct) } for live feedback
|
|
12
|
-
//
|
|
13
|
-
// Parameters are declared in `declarations.json` at the project root. That
|
|
14
|
-
// file is bundled alongside this code at publish time so the platform (and
|
|
15
|
-
// the CLI's `thatopen run`) knows which parameters the component accepts
|
|
16
|
-
// and their types. Whenever you add, remove, or rename a parameter in this
|
|
17
|
-
// file you MUST update `declarations.json` to match — `thatopen publish`
|
|
18
|
-
// fails if they drift.
|
|
19
|
-
//
|
|
20
|
-
// Return value — must be { type, message }:
|
|
21
|
-
// type: "SUCCESS" | "FAIL" | "WARNING"
|
|
22
|
-
|
|
23
|
-
// Globals injected by the execution engine at runtime — keep these for type checking
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
-
declare const thatOpenServices: import("@thatopen/services").EngineServicesClient;
|
|
26
|
-
declare const executionParams: Record<string, unknown>;
|
|
27
|
-
declare const executionContext: {
|
|
28
|
-
projectId?: string;
|
|
29
|
-
executionId: string;
|
|
30
|
-
toolId: string;
|
|
31
|
-
toolVersion: string;
|
|
32
|
-
};
|
|
33
|
-
declare const executionReporter: {
|
|
34
|
-
message(msg: string): void;
|
|
35
|
-
error(msg: string): void;
|
|
36
|
-
progress(pct: number): void;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export async function main() {
|
|
40
|
-
const projectName = executionParams.projectName as string | undefined;
|
|
41
|
-
const iterations = Number(executionParams.iterations);
|
|
42
|
-
|
|
43
|
-
executionReporter.message(
|
|
44
|
-
`Starting for "${projectName ?? "(unnamed)"}"`,
|
|
45
|
-
);
|
|
46
|
-
executionReporter.message(`Will run ${iterations} iteration(s)`);
|
|
47
|
-
if (executionContext?.projectId) {
|
|
48
|
-
executionReporter.message(`Scoped to project ${executionContext.projectId}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (!projectName) {
|
|
52
|
-
return { type: "FAIL", message: "projectName parameter is required" };
|
|
53
|
-
}
|
|
54
|
-
if (!Number.isFinite(iterations) || iterations <= 0) {
|
|
55
|
-
return { type: "FAIL", message: "iterations must be a positive number" };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
for (let i = 1; i <= iterations; i++) {
|
|
59
|
-
executionReporter.message(`Iteration ${i} of ${iterations}`);
|
|
60
|
-
executionReporter.progress(Math.round((i / iterations) * 100));
|
|
61
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
executionReporter.message("All iterations completed");
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
type: "SUCCESS",
|
|
68
|
-
message: `Processed "${projectName}" across ${iterations} iteration(s)`,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
1
|
+
// Cloud Component Entry Point
|
|
2
|
+
//
|
|
3
|
+
// Your component runs on the server as a Node.js process.
|
|
4
|
+
// The execution engine provides these globals — do NOT import them:
|
|
5
|
+
//
|
|
6
|
+
// thatOpenServices — pre-authenticated EngineServicesClient
|
|
7
|
+
// executionParams — parameters passed by the caller (shape defined in ../declarations.json)
|
|
8
|
+
// executionContext — platform-supplied run context: { projectId?, executionId, toolId, toolVersion }
|
|
9
|
+
// Use executionContext.projectId to scope uploads/lookups to the launching project.
|
|
10
|
+
// Undefined when the component is run outside a project context.
|
|
11
|
+
// executionReporter — { message(msg), error(msg), progress(pct) } for live feedback
|
|
12
|
+
//
|
|
13
|
+
// Parameters are declared in `declarations.json` at the project root. That
|
|
14
|
+
// file is bundled alongside this code at publish time so the platform (and
|
|
15
|
+
// the CLI's `thatopen run`) knows which parameters the component accepts
|
|
16
|
+
// and their types. Whenever you add, remove, or rename a parameter in this
|
|
17
|
+
// file you MUST update `declarations.json` to match — `thatopen publish`
|
|
18
|
+
// fails if they drift.
|
|
19
|
+
//
|
|
20
|
+
// Return value — must be { type, message }:
|
|
21
|
+
// type: "SUCCESS" | "FAIL" | "WARNING"
|
|
22
|
+
|
|
23
|
+
// Globals injected by the execution engine at runtime — keep these for type checking
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
+
declare const thatOpenServices: import("@thatopen/services").EngineServicesClient;
|
|
26
|
+
declare const executionParams: Record<string, unknown>;
|
|
27
|
+
declare const executionContext: {
|
|
28
|
+
projectId?: string;
|
|
29
|
+
executionId: string;
|
|
30
|
+
toolId: string;
|
|
31
|
+
toolVersion: string;
|
|
32
|
+
};
|
|
33
|
+
declare const executionReporter: {
|
|
34
|
+
message(msg: string): void;
|
|
35
|
+
error(msg: string): void;
|
|
36
|
+
progress(pct: number): void;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export async function main() {
|
|
40
|
+
const projectName = executionParams.projectName as string | undefined;
|
|
41
|
+
const iterations = Number(executionParams.iterations);
|
|
42
|
+
|
|
43
|
+
executionReporter.message(
|
|
44
|
+
`Starting for "${projectName ?? "(unnamed)"}"`,
|
|
45
|
+
);
|
|
46
|
+
executionReporter.message(`Will run ${iterations} iteration(s)`);
|
|
47
|
+
if (executionContext?.projectId) {
|
|
48
|
+
executionReporter.message(`Scoped to project ${executionContext.projectId}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!projectName) {
|
|
52
|
+
return { type: "FAIL", message: "projectName parameter is required" };
|
|
53
|
+
}
|
|
54
|
+
if (!Number.isFinite(iterations) || iterations <= 0) {
|
|
55
|
+
return { type: "FAIL", message: "iterations must be a positive number" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (let i = 1; i <= iterations; i++) {
|
|
59
|
+
executionReporter.message(`Iteration ${i} of ${iterations}`);
|
|
60
|
+
executionReporter.progress(Math.round((i / iterations) * 100));
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
executionReporter.message("All iterations completed");
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
type: "SUCCESS",
|
|
68
|
+
message: `Processed "${projectName}" across ${iterations} iteration(s)`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": ["ES2020"],
|
|
6
|
-
"skipLibCheck": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"moduleResolution": "bundler",
|
|
9
|
-
"allowImportingTsExtensions": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"noEmit": true,
|
|
13
|
-
"strict": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src"]
|
|
16
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"isolatedModules": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"strict": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"]
|
|
16
|
+
}
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
// Production build config — builds dist/bundle.js as IIFE.
|
|
2
|
-
// For local development, use: npm run dev (runs thatopen serve with esbuild).
|
|
3
|
-
// Do NOT run "vite" or "vite build --watch" directly for dev.
|
|
4
|
-
import { defineConfig } from 'vite';
|
|
5
|
-
import { resolve } from 'path';
|
|
6
|
-
import { existsSync, readFileSync } from 'fs';
|
|
7
|
-
|
|
8
|
-
function getBetaAliases() {
|
|
9
|
-
if (!existsSync('.thatopen')) return {};
|
|
10
|
-
try {
|
|
11
|
-
const config = JSON.parse(readFileSync('.thatopen', 'utf-8'));
|
|
12
|
-
if (!config.beta) return {};
|
|
13
|
-
return {
|
|
14
|
-
'@thatopen/components': '@thatopen-platform/components-beta',
|
|
15
|
-
'@thatopen/components-front': '@thatopen-platform/components-front-beta',
|
|
16
|
-
'@thatopen/fragments': '@thatopen-platform/fragments-beta',
|
|
17
|
-
};
|
|
18
|
-
} catch {
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default defineConfig({
|
|
24
|
-
resolve: {
|
|
25
|
-
alias: getBetaAliases(),
|
|
26
|
-
},
|
|
27
|
-
build: {
|
|
28
|
-
lib: {
|
|
29
|
-
entry: resolve(__dirname, 'src/main.ts'),
|
|
30
|
-
name: 'ThatOpenComponent',
|
|
31
|
-
formats: ['iife'],
|
|
32
|
-
fileName: () => 'bundle.js',
|
|
33
|
-
},
|
|
34
|
-
outDir: 'dist',
|
|
35
|
-
rollupOptions: {
|
|
36
|
-
// Only @thatopen/services is externalized — the execution wrapper
|
|
37
|
-
// provides it at runtime via require('@thatopen/services'). Every
|
|
38
|
-
// other dependency (including @thatopen/components, three, web-ifc,
|
|
39
|
-
// or any npm package you install) must be bundled into bundle.js.
|
|
40
|
-
external: ['@thatopen/services'],
|
|
41
|
-
output: {
|
|
42
|
-
footer: 'var main = ThatOpenComponent.main;',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
});
|
|
1
|
+
// Production build config — builds dist/bundle.js as IIFE.
|
|
2
|
+
// For local development, use: npm run dev (runs thatopen serve with esbuild).
|
|
3
|
+
// Do NOT run "vite" or "vite build --watch" directly for dev.
|
|
4
|
+
import { defineConfig } from 'vite';
|
|
5
|
+
import { resolve } from 'path';
|
|
6
|
+
import { existsSync, readFileSync } from 'fs';
|
|
7
|
+
|
|
8
|
+
function getBetaAliases() {
|
|
9
|
+
if (!existsSync('.thatopen')) return {};
|
|
10
|
+
try {
|
|
11
|
+
const config = JSON.parse(readFileSync('.thatopen', 'utf-8'));
|
|
12
|
+
if (!config.beta) return {};
|
|
13
|
+
return {
|
|
14
|
+
'@thatopen/components': '@thatopen-platform/components-beta',
|
|
15
|
+
'@thatopen/components-front': '@thatopen-platform/components-front-beta',
|
|
16
|
+
'@thatopen/fragments': '@thatopen-platform/fragments-beta',
|
|
17
|
+
};
|
|
18
|
+
} catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default defineConfig({
|
|
24
|
+
resolve: {
|
|
25
|
+
alias: getBetaAliases(),
|
|
26
|
+
},
|
|
27
|
+
build: {
|
|
28
|
+
lib: {
|
|
29
|
+
entry: resolve(__dirname, 'src/main.ts'),
|
|
30
|
+
name: 'ThatOpenComponent',
|
|
31
|
+
formats: ['iife'],
|
|
32
|
+
fileName: () => 'bundle.js',
|
|
33
|
+
},
|
|
34
|
+
outDir: 'dist',
|
|
35
|
+
rollupOptions: {
|
|
36
|
+
// Only @thatopen/services is externalized — the execution wrapper
|
|
37
|
+
// provides it at runtime via require('@thatopen/services'). Every
|
|
38
|
+
// other dependency (including @thatopen/components, three, web-ifc,
|
|
39
|
+
// or any npm package you install) must be bundled into bundle.js.
|
|
40
|
+
external: ['@thatopen/services'],
|
|
41
|
+
output: {
|
|
42
|
+
footer: 'var main = ThatOpenComponent.main;',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# That Open Platform — Agent Guide
|
|
2
|
-
|
|
3
|
-
Read these two files before doing anything else:
|
|
4
|
-
|
|
5
|
-
1. `node_modules/@thatopen/services/resources/AGENTS.md` — rules, hard constraints, and the full navigation table for the That Open Platform. Always current for the installed library version.
|
|
6
|
-
2. `README.md` (this folder) — what this specific project is, its commands, architecture, and patterns.
|
|
7
|
-
|
|
8
|
-
If `node_modules/` doesn't exist yet, run `npm install` first or ask the user to do it.
|
|
1
|
+
# That Open Platform — Agent Guide
|
|
2
|
+
|
|
3
|
+
Read these two files before doing anything else:
|
|
4
|
+
|
|
5
|
+
1. `node_modules/@thatopen/services/resources/AGENTS.md` — rules, hard constraints, and the full navigation table for the That Open Platform. Always current for the installed library version.
|
|
6
|
+
2. `README.md` (this folder) — what this specific project is, its commands, architecture, and patterns.
|
|
7
|
+
|
|
8
|
+
If `node_modules/` doesn't exist yet, run `npm install` first or ask the user to do it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
See [AGENTS.md](./AGENTS.md).
|
|
1
|
+
See [AGENTS.md](./AGENTS.md).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
node_modules
|
|
2
|
-
dist
|
|
3
|
-
*.zip
|
|
4
|
-
.thatopen
|
|
1
|
+
node_modules
|
|
2
|
+
dist
|
|
3
|
+
*.zip
|
|
4
|
+
.thatopen
|
|
5
|
+
.npmrc
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import * as OBC from "@thatopen/components";
|
|
2
|
-
import * as BUI from "@thatopen/ui";
|
|
3
|
-
import appManagerDef from "./index";
|
|
4
|
-
|
|
5
|
-
// ── State types ───────────────────────────────────────────────────────
|
|
6
|
-
|
|
7
|
-
type Panel1State = { label: string; components: OBC.Components };
|
|
8
|
-
type Panel2State = { label: string; components: OBC.Components };
|
|
9
|
-
|
|
10
|
-
// ── App type ──────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
interface MyApp {
|
|
13
|
-
icons: ["LOAD", "TREE", "VIEW"];
|
|
14
|
-
grid: BUI.Grid<
|
|
15
|
-
["Split", "Viewer"],
|
|
16
|
-
[{ name: "panel1"; state: Panel1State }, { name: "panel2"; state: Panel2State }]
|
|
17
|
-
>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ── Initialise OBC & BUI ──────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
BUI.Manager.init();
|
|
23
|
-
const components = new OBC.Components();
|
|
24
|
-
|
|
25
|
-
const AppManager = appManagerDef.componentDefinition;
|
|
26
|
-
const app = components.get(AppManager<MyApp>);
|
|
27
|
-
|
|
28
|
-
// ── Define element templates ──────────────────────────────────────────
|
|
29
|
-
|
|
30
|
-
const panel1Template: BUI.StatefullComponent<Panel1State> = ({ label, components }) => {
|
|
31
|
-
const app = components.get(AppManager<MyApp>);
|
|
32
|
-
return BUI.html`
|
|
33
|
-
<bim-panel active label=${label} style="min-width: 14rem;">
|
|
34
|
-
<bim-panel-section label="Actions">
|
|
35
|
-
<bim-button icon=${app.icons.LOAD} label="Load School Model"></bim-button>
|
|
36
|
-
</bim-panel-section>
|
|
37
|
-
<bim-panel-section label="Info">
|
|
38
|
-
<bim-label>Use the sidebar to switch layouts.</bim-label>
|
|
39
|
-
</bim-panel-section>
|
|
40
|
-
</bim-panel>
|
|
41
|
-
`;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const panel2Template: BUI.StatefullComponent<Panel2State> = ({ label, components }) => {
|
|
45
|
-
const app = components.get(AppManager<MyApp>);
|
|
46
|
-
return BUI.html`
|
|
47
|
-
<bim-panel active label=${label} style="min-width: 14rem;">
|
|
48
|
-
<bim-panel-section label="Settings">
|
|
49
|
-
<bim-button icon=${app.icons.VIEW} label="View"></bim-button>
|
|
50
|
-
</bim-panel-section>
|
|
51
|
-
</bim-panel>
|
|
52
|
-
`;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// ── Init ──────────────────────────────────────────────────────────────
|
|
56
|
-
|
|
57
|
-
app.init({
|
|
58
|
-
icons: {
|
|
59
|
-
LOAD: "solar:upload-bold",
|
|
60
|
-
TREE: "mdi:file-tree",
|
|
61
|
-
VIEW: "mdi:monitor",
|
|
62
|
-
},
|
|
63
|
-
grid: (grid) => {
|
|
64
|
-
grid.elements = {
|
|
65
|
-
panel1: { template: panel1Template, initialState: { label: "Models", components } },
|
|
66
|
-
panel2: { template: panel2Template, initialState: { label: "Settings", components } },
|
|
67
|
-
};
|
|
68
|
-
grid.layouts = {
|
|
69
|
-
Split: {
|
|
70
|
-
template: `
|
|
71
|
-
"panel1" 1fr
|
|
72
|
-
"panel2" 1fr
|
|
73
|
-
/ 25rem 1fr`,
|
|
74
|
-
icon: app.icons.TREE,
|
|
75
|
-
},
|
|
76
|
-
Viewer: {
|
|
77
|
-
template: `"panel1" 1fr / 1fr`,
|
|
78
|
-
icon: app.icons.VIEW,
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
grid.layout = "Split";
|
|
82
|
-
},
|
|
83
|
-
container: document.getElementById("container")!,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
app.showSidebar = true;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import * as OBC from "@thatopen/components";
|
|
2
|
-
import * as BUI from "@thatopen/ui";
|
|
3
|
-
import type { EngineServicesClient, Item } from "thatopen-services";
|
|
4
|
-
|
|
5
|
-
import appManagerDef from "../AppManager/index";
|
|
6
|
-
import fileListDef from "./index";
|
|
7
|
-
|
|
8
|
-
const AppManager = appManagerDef.componentDefinition;
|
|
9
|
-
const FileList = fileListDef.componentDefinition;
|
|
10
|
-
|
|
11
|
-
// ── A tiny in-memory fake client for the example ──────────────────────
|
|
12
|
-
// Real apps should pass their `EngineServicesClient` instance here — this
|
|
13
|
-
// stub just implements the subset of the API the FileList component uses.
|
|
14
|
-
|
|
15
|
-
let nextId = 1;
|
|
16
|
-
const mkFile = (name: string, ext?: string): Item => ({
|
|
17
|
-
_id: `file-${nextId++}`,
|
|
18
|
-
name,
|
|
19
|
-
fileExtension: ext,
|
|
20
|
-
itemType: "FILE",
|
|
21
|
-
internalId: `internal-${nextId}`,
|
|
22
|
-
createdAt: new Date(),
|
|
23
|
-
creatingUser: "demo-user",
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const files: Item[] = [
|
|
27
|
-
mkFile("site-plan", "pdf"),
|
|
28
|
-
mkFile("structural-model", "ifc"),
|
|
29
|
-
mkFile("mep-coordination", "ifc"),
|
|
30
|
-
mkFile("bcf-issues", "bcf"),
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const fakeClient = {
|
|
34
|
-
async listFiles() {
|
|
35
|
-
// Small delay to show the loading state.
|
|
36
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
37
|
-
return files.filter((f) => !f.archived);
|
|
38
|
-
},
|
|
39
|
-
async downloadFile(id: string) {
|
|
40
|
-
const file = files.find((f) => f._id === id)!;
|
|
41
|
-
const body = `Pretend contents of ${file.name}`;
|
|
42
|
-
return new Response(body, { headers: { "Content-Type": "text/plain" } });
|
|
43
|
-
},
|
|
44
|
-
async updateFile(id: string, data: { name?: string }) {
|
|
45
|
-
const file = files.find((f) => f._id === id)!;
|
|
46
|
-
if (data.name) file.name = data.name;
|
|
47
|
-
return { item: file };
|
|
48
|
-
},
|
|
49
|
-
async archiveFile(id: string) {
|
|
50
|
-
const file = files.find((f) => f._id === id)!;
|
|
51
|
-
file.archived = true;
|
|
52
|
-
return file;
|
|
53
|
-
},
|
|
54
|
-
} as unknown as EngineServicesClient;
|
|
55
|
-
|
|
56
|
-
// ── App type ──────────────────────────────────────────────────────────
|
|
57
|
-
|
|
58
|
-
type FilesState = { components: OBC.Components };
|
|
59
|
-
|
|
60
|
-
interface FileListApp {
|
|
61
|
-
icons: ["FILES"];
|
|
62
|
-
grid: BUI.Grid<
|
|
63
|
-
["Files"],
|
|
64
|
-
[{ name: "files"; state: FilesState }]
|
|
65
|
-
>;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ── Initialise OBC & BUI ──────────────────────────────────────────────
|
|
69
|
-
|
|
70
|
-
BUI.Manager.init();
|
|
71
|
-
const components = new OBC.Components();
|
|
72
|
-
|
|
73
|
-
const app = components.get(AppManager<FileListApp>);
|
|
74
|
-
const fileList = components.get(FileList);
|
|
75
|
-
|
|
76
|
-
// ── Create a file list instance ───────────────────────────────────────
|
|
77
|
-
|
|
78
|
-
const { element: fileListElement } = fileList.create({ client: fakeClient });
|
|
79
|
-
|
|
80
|
-
const filesPanel: BUI.StatefullComponent<FilesState> = (_state) => BUI.html`
|
|
81
|
-
<bim-panel active label="Files" style="display: flex; flex-direction: column;">
|
|
82
|
-
<bim-panel-section label="Project files" style="flex: 1; min-height: 0;">
|
|
83
|
-
${fileListElement}
|
|
84
|
-
</bim-panel-section>
|
|
85
|
-
</bim-panel>
|
|
86
|
-
`;
|
|
87
|
-
|
|
88
|
-
// ── Init ──────────────────────────────────────────────────────────────
|
|
89
|
-
|
|
90
|
-
app.init({
|
|
91
|
-
icons: { FILES: "mdi:file-multiple" },
|
|
92
|
-
grid: (grid) => {
|
|
93
|
-
grid.elements = {
|
|
94
|
-
files: { template: filesPanel, initialState: { components } },
|
|
95
|
-
};
|
|
96
|
-
grid.layouts = {
|
|
97
|
-
Files: {
|
|
98
|
-
template: `"files" 1fr / 1fr`,
|
|
99
|
-
icon: app.icons.FILES,
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
grid.layout = "Files";
|
|
103
|
-
},
|
|
104
|
-
container: document.getElementById("container")!,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
components.init();
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import * as OBC from "@thatopen/components";
|
|
2
|
-
import * as BUI from "@thatopen/ui";
|
|
3
|
-
|
|
4
|
-
import appManagerDef from "../AppManager/index";
|
|
5
|
-
import tabbedNavDef from "./index";
|
|
6
|
-
|
|
7
|
-
const AppManager = appManagerDef.componentDefinition;
|
|
8
|
-
const TabbedNavigation = tabbedNavDef.componentDefinition;
|
|
9
|
-
|
|
10
|
-
// ── App type ──────────────────────────────────────────────────────────
|
|
11
|
-
|
|
12
|
-
type PanelState = { label: string };
|
|
13
|
-
|
|
14
|
-
interface NavApp {
|
|
15
|
-
icons: ["DASHBOARD", "FILES", "SETTINGS"];
|
|
16
|
-
grid: BUI.Grid<
|
|
17
|
-
["Dashboard", "Files", "Settings"],
|
|
18
|
-
[
|
|
19
|
-
{ name: "tabs"; state: null },
|
|
20
|
-
{ name: "dashboard"; state: PanelState },
|
|
21
|
-
{ name: "files"; state: PanelState },
|
|
22
|
-
{ name: "settings"; state: PanelState }
|
|
23
|
-
]
|
|
24
|
-
>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ── Initialise OBC & BUI ──────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
BUI.Manager.init();
|
|
30
|
-
const components = new OBC.Components();
|
|
31
|
-
|
|
32
|
-
const app = components.get(AppManager<NavApp>);
|
|
33
|
-
const tabs = components.get(TabbedNavigation);
|
|
34
|
-
|
|
35
|
-
// ── Templates ─────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
const makePanel = (): BUI.StatefullComponent<PanelState> =>
|
|
38
|
-
({ label }) => BUI.html`
|
|
39
|
-
<bim-panel active label=${label}>
|
|
40
|
-
<bim-panel-section label="Content">
|
|
41
|
-
<bim-label>Current screen: ${label}</bim-label>
|
|
42
|
-
</bim-panel-section>
|
|
43
|
-
</bim-panel>
|
|
44
|
-
`;
|
|
45
|
-
|
|
46
|
-
// The grid caches elements by template-function identity, so each tab area
|
|
47
|
-
// needs its own function reference — otherwise the grid reuses the same
|
|
48
|
-
// panel element across layouts.
|
|
49
|
-
const dashboardPanel = makePanel();
|
|
50
|
-
const filesPanel = makePanel();
|
|
51
|
-
const settingsPanel = makePanel();
|
|
52
|
-
|
|
53
|
-
// We'll fill the tabs element after init.
|
|
54
|
-
let tabsElement: HTMLElement | null = null;
|
|
55
|
-
|
|
56
|
-
// ── Init ──────────────────────────────────────────────────────────────
|
|
57
|
-
|
|
58
|
-
app.init({
|
|
59
|
-
icons: {
|
|
60
|
-
DASHBOARD: "mdi:view-dashboard",
|
|
61
|
-
FILES: "mdi:file-multiple",
|
|
62
|
-
SETTINGS: "mdi:cog",
|
|
63
|
-
},
|
|
64
|
-
grid: (grid) => {
|
|
65
|
-
grid.elements = {
|
|
66
|
-
tabs: (() => {
|
|
67
|
-
// Lazy placeholder — TabbedNavigation attaches here after app.init().
|
|
68
|
-
const slot = document.createElement("div");
|
|
69
|
-
slot.style.cssText = "display: flex; padding: 0.5rem;";
|
|
70
|
-
tabsElement = slot;
|
|
71
|
-
return slot;
|
|
72
|
-
})(),
|
|
73
|
-
dashboard: { template: dashboardPanel, initialState: { label: "Dashboard" } },
|
|
74
|
-
files: { template: filesPanel, initialState: { label: "Files" } },
|
|
75
|
-
settings: { template: settingsPanel, initialState: { label: "Settings" } },
|
|
76
|
-
};
|
|
77
|
-
grid.layouts = {
|
|
78
|
-
Dashboard: {
|
|
79
|
-
template: `
|
|
80
|
-
"tabs" auto
|
|
81
|
-
"dashboard" 1fr
|
|
82
|
-
/ 1fr
|
|
83
|
-
`,
|
|
84
|
-
icon: app.icons.DASHBOARD,
|
|
85
|
-
},
|
|
86
|
-
Files: {
|
|
87
|
-
template: `
|
|
88
|
-
"tabs" auto
|
|
89
|
-
"files" 1fr
|
|
90
|
-
/ 1fr
|
|
91
|
-
`,
|
|
92
|
-
icon: app.icons.FILES,
|
|
93
|
-
},
|
|
94
|
-
Settings: {
|
|
95
|
-
template: `
|
|
96
|
-
"tabs" auto
|
|
97
|
-
"settings" 1fr
|
|
98
|
-
/ 1fr
|
|
99
|
-
`,
|
|
100
|
-
icon: app.icons.SETTINGS,
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
grid.layout = "Dashboard";
|
|
104
|
-
},
|
|
105
|
-
container: document.getElementById("container")!,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Create the tab bar now that the grid exists.
|
|
109
|
-
const { element: tabBar } = tabs.create();
|
|
110
|
-
tabsElement?.appendChild(tabBar);
|
|
111
|
-
|
|
112
|
-
// Hide the default sidebar — tabs replace it.
|
|
113
|
-
app.showSidebar = false;
|
|
114
|
-
|
|
115
|
-
components.init();
|