@thatopen/services 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +62 -62
  2. package/dist/built-in/index.d.ts +569 -0
  3. package/dist/cli.js +12 -23
  4. package/dist/index.cjs.js +2 -2
  5. package/dist/index.es.js +41 -49
  6. package/dist/vite-env.d.ts +1 -1
  7. package/docs/ai-quickstart.md +37 -0
  8. package/docs/builtin/paths.json +4 -0
  9. package/docs/cli/create.md +29 -29
  10. package/docs/cli/local-server.md +38 -38
  11. package/docs/cli/login.md +32 -32
  12. package/docs/cli/publish.md +31 -31
  13. package/docs/cli/run.md +26 -26
  14. package/docs/cli/serve.md +43 -43
  15. package/docs/cli/swap.md +30 -30
  16. package/docs/flow-architecture.md +389 -0
  17. package/docs/flow-plugin-guide.md +337 -0
  18. package/docs/platform-token.md +81 -0
  19. package/docs/revit-collab-quickstart.md +363 -173
  20. package/docs/rhino-interop-quickstart.md +391 -0
  21. package/package.json +1 -1
  22. package/resources/AGENTS.md +40 -40
  23. package/src/built-in/CDEManager/example.ts +214 -214
  24. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  25. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  26. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  27. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  28. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  29. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  30. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  31. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  32. package/src/built-in/UIManager/src/app/example.ts +97 -97
  33. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
  34. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
  35. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
  36. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
  37. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
  38. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
  39. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
  40. package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
  41. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
  42. package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
  43. package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -0
  44. package/src/built-in/UIManager/src/models-list/example.ts +122 -122
  45. package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
  46. package/src/built-in/index.ts +570 -0
  47. package/src/cli/templates/app/index.html +35 -35
  48. package/src/cli/templates/app/package.json +32 -32
  49. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
  50. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  51. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  52. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  53. package/src/cli/templates/app/src/globals.ts +1 -1
  54. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
  55. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
  56. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
  57. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
  58. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
  59. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
  60. package/src/cli/templates/app/src/ui-components/index.ts +2 -2
  61. package/src/cli/templates/app/tsconfig.json +16 -16
  62. package/src/cli/templates/app/vite.config.js +57 -57
  63. package/src/cli/templates/cloud-component/README.md +205 -205
  64. package/src/cli/templates/cloud-component/_thatopen +5 -5
  65. package/src/cli/templates/cloud-component/declarations.json +4 -4
  66. package/src/cli/templates/cloud-component/package.json +21 -21
  67. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  68. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  69. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  70. package/src/cli/templates/shared/AGENTS.md +8 -8
  71. package/src/cli/templates/shared/CLAUDE.md +1 -1
  72. package/src/cli/templates/shared/_gitignore +5 -5
@@ -1,90 +1,90 @@
1
- /* MD
2
- ## Floating layout
3
- ---
4
- Developers building BIM coordination tools often want the 3D model to fill the
5
- entire window while control panels float above it — but standard grid layouts
6
- give every area equal standing, shrinking the viewer into one cell and leaving
7
- visible seams between it and the panels.
8
-
9
- top-app supports a floating mode where one element is mounted as an absolute
10
- background that fills the container edge-to-edge, and all other layout areas
11
- render as a transparent overlay on top of it with independent pointer events.
12
-
13
- This tutorial covers assigning the viewer as the absolute background of the app;
14
- defining an overlay layout where a side panel floats above the viewer without
15
- sharing grid space; and annotating why the base element is excluded from the
16
- layout template.
17
-
18
- By the end, you'll have a full-screen 3D viewer with a floating side panel
19
- hovering above it, with the model filling the entire window and the panel
20
- receiving its own pointer events.
21
- */
22
-
23
- import { html } from "lit";
24
- import * as THREE from "three";
25
- import * as OBC from "@thatopen/components";
26
- import * as OBF from "@thatopen/components-front";
27
- import * as FRAGS from "@thatopen/fragments";
28
- import * as BUI from "@thatopen/ui";
29
- import { PlatformClient, UIManager } from "@thatopen/services";
30
- import type { App } from "../../index";
31
-
32
- const client = PlatformClient.fromPlatformContext();
33
- const { components } = (await client.setup(
34
- { OBC, OBF, BUI, THREE, FRAGS },
35
- { uuid: UIManager.uuid },
36
- )) as { components: OBC.Components };
37
- components.get(UIManager).init();
38
-
39
- const app = document.createElement("top-app") as unknown as App;
40
-
41
- app.setup = (waitUntil) => {
42
- waitUntil(
43
- (async () => {
44
- const fragments = components.get(OBC.FragmentsManager);
45
- const workerUrl = await FRAGS.FragmentsModels.getWorker();
46
- fragments.init(await FRAGS.toClassicWorker(workerUrl), {
47
- classicWorker: true,
48
- });
49
- })(),
50
- "Fragments Core",
51
- );
52
- return { components, client };
53
- };
54
-
55
- app.elements = {
56
- // "viewer" is referenced by app.base — rendered as a position:absolute layer
57
- // behind all layout content so it fills the container edge-to-edge.
58
- viewer: () =>
59
- html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
60
-
61
- // Panels declared here appear in the floating content grid on top of the viewer.
62
- // Their container has pointer-events: none; each child re-enables them individually.
63
- panel: () => html`
64
- <bim-panel>
65
- <bim-panel-section label="Models" icon="solar:layers-bold">
66
- <bim-label>Load models here</bim-label>
67
- </bim-panel-section>
68
- </bim-panel>
69
- `,
70
- };
71
-
72
- // Setting app.base to an element key mounts that element as the absolute background.
73
- // Layout templates then only list the floating overlay areas — not the base element.
74
- // Without app.base, every area in the template is a peer grid cell (inline mode).
75
- app.base = "viewer";
76
-
77
- app.layouts = {
78
- main: {
79
- label: "Main",
80
- icon: "solar:home-bold",
81
- // Only overlay areas appear here. "viewer" is not listed because it is the base.
82
- template: `"panel" 1fr / 22rem`,
83
- },
84
- };
85
-
86
- app.layout = "main";
87
-
88
- const container = document.getElementById("that-open-app") ?? document.body;
89
- container.appendChild(app);
90
- document.body.style.margin = "0";
1
+ /* MD
2
+ ## Floating layout
3
+ ---
4
+ Developers building BIM coordination tools often want the 3D model to fill the
5
+ entire window while control panels float above it — but standard grid layouts
6
+ give every area equal standing, shrinking the viewer into one cell and leaving
7
+ visible seams between it and the panels.
8
+
9
+ top-app supports a floating mode where one element is mounted as an absolute
10
+ background that fills the container edge-to-edge, and all other layout areas
11
+ render as a transparent overlay on top of it with independent pointer events.
12
+
13
+ This tutorial covers assigning the viewer as the absolute background of the app;
14
+ defining an overlay layout where a side panel floats above the viewer without
15
+ sharing grid space; and annotating why the base element is excluded from the
16
+ layout template.
17
+
18
+ By the end, you'll have a full-screen 3D viewer with a floating side panel
19
+ hovering above it, with the model filling the entire window and the panel
20
+ receiving its own pointer events.
21
+ */
22
+
23
+ import { html } from "lit";
24
+ import * as THREE from "three";
25
+ import * as OBC from "@thatopen/components";
26
+ import * as OBF from "@thatopen/components-front";
27
+ import * as FRAGS from "@thatopen/fragments";
28
+ import * as BUI from "@thatopen/ui";
29
+ import { PlatformClient, UIManager } from "@thatopen/services";
30
+ import type { App } from "../../index";
31
+
32
+ const client = PlatformClient.fromPlatformContext();
33
+ const { components } = (await client.setup(
34
+ { OBC, OBF, BUI, THREE, FRAGS },
35
+ { uuid: UIManager.uuid },
36
+ )) as { components: OBC.Components };
37
+ components.get(UIManager).init();
38
+
39
+ const app = document.createElement("top-app") as unknown as App;
40
+
41
+ app.setup = (waitUntil) => {
42
+ waitUntil(
43
+ (async () => {
44
+ const fragments = components.get(OBC.FragmentsManager);
45
+ const workerUrl = await FRAGS.FragmentsModels.getWorker();
46
+ fragments.init(await FRAGS.toClassicWorker(workerUrl), {
47
+ classicWorker: true,
48
+ });
49
+ })(),
50
+ "Fragments Core",
51
+ );
52
+ return { components, client };
53
+ };
54
+
55
+ app.elements = {
56
+ // "viewer" is referenced by app.base — rendered as a position:absolute layer
57
+ // behind all layout content so it fills the container edge-to-edge.
58
+ viewer: () =>
59
+ html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
60
+
61
+ // Panels declared here appear in the floating content grid on top of the viewer.
62
+ // Their container has pointer-events: none; each child re-enables them individually.
63
+ panel: () => html`
64
+ <bim-panel>
65
+ <bim-panel-section label="Models" icon="solar:layers-bold">
66
+ <bim-label>Load models here</bim-label>
67
+ </bim-panel-section>
68
+ </bim-panel>
69
+ `,
70
+ };
71
+
72
+ // Setting app.base to an element key mounts that element as the absolute background.
73
+ // Layout templates then only list the floating overlay areas — not the base element.
74
+ // Without app.base, every area in the template is a peer grid cell (inline mode).
75
+ app.base = "viewer";
76
+
77
+ app.layouts = {
78
+ main: {
79
+ label: "Main",
80
+ icon: "solar:home-bold",
81
+ // Only overlay areas appear here. "viewer" is not listed because it is the base.
82
+ template: `"panel" 1fr / 22rem`,
83
+ },
84
+ };
85
+
86
+ app.layout = "main";
87
+
88
+ const container = document.getElementById("that-open-app") ?? document.body;
89
+ container.appendChild(app);
90
+ document.body.style.margin = "0";
@@ -1,163 +1,163 @@
1
- /* MD
2
- ## Confirmation modals with top:modal
3
- ---
4
- Destructive or irreversible actions — deleting records, overwriting files,
5
- leaving unsaved changes — should ask the user to confirm before proceeding.
6
- Opening a custom dialog element from a deeply nested component means threading
7
- a reference to a controller up through every layer of the tree.
8
-
9
- top-app provides a modal slot that any descendant can trigger by dispatching
10
- a single DOM event. The modal blocks the UI, shows a configurable message and
11
- action labels, and calls back into the originating component when the user
12
- confirms or cancels — no reference to the root element required.
13
-
14
- This tutorial covers showing a modal from a child component by dispatching
15
- top:modal; setting the label, icon, and button labels; running an async
16
- confirm handler while the modal shows a loading spinner; and handling the
17
- cancel path without side effects.
18
-
19
- By the end, you'll have an app where a panel can trigger confirmation dialogs
20
- for actions of varying severity, each with its own copy and async behaviour.
21
- */
22
-
23
- import { html, LitElement } from "lit";
24
- import { customElement, state } from "lit/decorators.js";
25
- import * as THREE from "three";
26
- import * as OBC from "@thatopen/components";
27
- import * as OBF from "@thatopen/components-front";
28
- import * as FRAGS from "@thatopen/fragments";
29
- import * as BUI from "@thatopen/ui";
30
- import { PlatformClient, UIManager } from "@thatopen/services";
31
- import type { App } from "../../index";
32
-
33
- // A child component that triggers modals without holding a reference to top-app.
34
- // It dispatches top:modal and receives the result via onConfirm / onCancel callbacks.
35
- @customElement("modal-actions")
36
- class ModalActions extends LitElement {
37
- @state() private _lastAction = "—";
38
-
39
- private _confirmDelete() {
40
- // top:modal opens a blocking dialog on the nearest top-app ancestor.
41
- // The modal stays open (with a loading spinner) while onConfirm is awaited.
42
- this.dispatchEvent(
43
- new CustomEvent("top:modal", {
44
- bubbles: true,
45
- composed: true,
46
- detail: {
47
- label: "Delete model",
48
- icon: "tabler:trash",
49
- confirmLabel: "Delete",
50
- cancelLabel: "Keep",
51
- content: html`
52
- <bim-label style="white-space:normal;">
53
- This will permanently remove the model and all its versions.
54
- This action cannot be undone.
55
- </bim-label>
56
- `,
57
- onConfirm: async () => {
58
- // Simulate an async delete operation.
59
- // The modal shows a loading spinner until this promise resolves.
60
- await new Promise<void>((resolve) => setTimeout(resolve, 1500));
61
- this._lastAction = "Model deleted";
62
- },
63
- onCancel: () => {
64
- this._lastAction = "Delete cancelled";
65
- },
66
- },
67
- }),
68
- );
69
- }
70
-
71
- private _confirmOverwrite() {
72
- this.dispatchEvent(
73
- new CustomEvent("top:modal", {
74
- bubbles: true,
75
- composed: true,
76
- detail: {
77
- label: "File already exists",
78
- icon: "tabler:alert-triangle",
79
- confirmLabel: "Overwrite",
80
- cancelLabel: "Cancel",
81
- content: html`
82
- <bim-label style="white-space:normal;">
83
- A file named <strong>structure.ifc</strong> already exists in this
84
- folder. Uploading will create a new version alongside it.
85
- </bim-label>
86
- `,
87
- // onConfirm can be synchronous too — the modal closes immediately.
88
- onConfirm: () => {
89
- this._lastAction = "Overwrite confirmed";
90
- },
91
- onCancel: () => {
92
- this._lastAction = "Overwrite cancelled";
93
- },
94
- },
95
- }),
96
- );
97
- }
98
-
99
- render() {
100
- return html`
101
- <bim-panel label="Modal Actions">
102
- <bim-panel-section label="Actions" icon="tabler:click">
103
- <bim-button
104
- label="Delete model (async confirm)"
105
- icon="tabler:trash"
106
- @click=${this._confirmDelete}
107
- ></bim-button>
108
- <bim-button
109
- label="Overwrite file (sync confirm)"
110
- icon="tabler:file-upload"
111
- @click=${this._confirmOverwrite}
112
- ></bim-button>
113
- <bim-label>Last action: ${this._lastAction}</bim-label>
114
- </bim-panel-section>
115
- </bim-panel>
116
- `;
117
- }
118
- }
119
-
120
- // ---- app wiring ----
121
-
122
- const client = PlatformClient.fromPlatformContext();
123
- const { components } = (await client.setup(
124
- { OBC, OBF, BUI, THREE, FRAGS },
125
- { uuid: UIManager.uuid },
126
- )) as { components: OBC.Components };
127
- components.get(UIManager).init();
128
-
129
- const app = document.createElement("top-app") as unknown as App;
130
-
131
- app.setup = (waitUntil) => {
132
- waitUntil(
133
- (async () => {
134
- const fragments = components.get(OBC.FragmentsManager);
135
- const workerUrl = await FRAGS.FragmentsModels.getWorker();
136
- fragments.init(await FRAGS.toClassicWorker(workerUrl), {
137
- classicWorker: true,
138
- });
139
- })(),
140
- "Fragments Core",
141
- );
142
- return { components, client };
143
- };
144
-
145
- app.elements = {
146
- viewer: () =>
147
- html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
148
- panel: () => html`<modal-actions></modal-actions>`,
149
- };
150
-
151
- app.base = "viewer";
152
- app.layouts = {
153
- main: {
154
- label: "Main",
155
- icon: "solar:home-bold",
156
- template: `"panel" 1fr / 22rem`,
157
- },
158
- };
159
- app.layout = "main";
160
-
161
- const container = document.getElementById("that-open-app") ?? document.body;
162
- container.appendChild(app);
163
- document.body.style.margin = "0";
1
+ /* MD
2
+ ## Confirmation modals with top:modal
3
+ ---
4
+ Destructive or irreversible actions — deleting records, overwriting files,
5
+ leaving unsaved changes — should ask the user to confirm before proceeding.
6
+ Opening a custom dialog element from a deeply nested component means threading
7
+ a reference to a controller up through every layer of the tree.
8
+
9
+ top-app provides a modal slot that any descendant can trigger by dispatching
10
+ a single DOM event. The modal blocks the UI, shows a configurable message and
11
+ action labels, and calls back into the originating component when the user
12
+ confirms or cancels — no reference to the root element required.
13
+
14
+ This tutorial covers showing a modal from a child component by dispatching
15
+ top:modal; setting the label, icon, and button labels; running an async
16
+ confirm handler while the modal shows a loading spinner; and handling the
17
+ cancel path without side effects.
18
+
19
+ By the end, you'll have an app where a panel can trigger confirmation dialogs
20
+ for actions of varying severity, each with its own copy and async behaviour.
21
+ */
22
+
23
+ import { html, LitElement } from "lit";
24
+ import { customElement, state } from "lit/decorators.js";
25
+ import * as THREE from "three";
26
+ import * as OBC from "@thatopen/components";
27
+ import * as OBF from "@thatopen/components-front";
28
+ import * as FRAGS from "@thatopen/fragments";
29
+ import * as BUI from "@thatopen/ui";
30
+ import { PlatformClient, UIManager } from "@thatopen/services";
31
+ import type { App } from "../../index";
32
+
33
+ // A child component that triggers modals without holding a reference to top-app.
34
+ // It dispatches top:modal and receives the result via onConfirm / onCancel callbacks.
35
+ @customElement("modal-actions")
36
+ class ModalActions extends LitElement {
37
+ @state() private _lastAction = "—";
38
+
39
+ private _confirmDelete() {
40
+ // top:modal opens a blocking dialog on the nearest top-app ancestor.
41
+ // The modal stays open (with a loading spinner) while onConfirm is awaited.
42
+ this.dispatchEvent(
43
+ new CustomEvent("top:modal", {
44
+ bubbles: true,
45
+ composed: true,
46
+ detail: {
47
+ label: "Delete model",
48
+ icon: "tabler:trash",
49
+ confirmLabel: "Delete",
50
+ cancelLabel: "Keep",
51
+ content: html`
52
+ <bim-label style="white-space:normal;">
53
+ This will permanently remove the model and all its versions.
54
+ This action cannot be undone.
55
+ </bim-label>
56
+ `,
57
+ onConfirm: async () => {
58
+ // Simulate an async delete operation.
59
+ // The modal shows a loading spinner until this promise resolves.
60
+ await new Promise<void>((resolve) => setTimeout(resolve, 1500));
61
+ this._lastAction = "Model deleted";
62
+ },
63
+ onCancel: () => {
64
+ this._lastAction = "Delete cancelled";
65
+ },
66
+ },
67
+ }),
68
+ );
69
+ }
70
+
71
+ private _confirmOverwrite() {
72
+ this.dispatchEvent(
73
+ new CustomEvent("top:modal", {
74
+ bubbles: true,
75
+ composed: true,
76
+ detail: {
77
+ label: "File already exists",
78
+ icon: "tabler:alert-triangle",
79
+ confirmLabel: "Overwrite",
80
+ cancelLabel: "Cancel",
81
+ content: html`
82
+ <bim-label style="white-space:normal;">
83
+ A file named <strong>structure.ifc</strong> already exists in this
84
+ folder. Uploading will create a new version alongside it.
85
+ </bim-label>
86
+ `,
87
+ // onConfirm can be synchronous too — the modal closes immediately.
88
+ onConfirm: () => {
89
+ this._lastAction = "Overwrite confirmed";
90
+ },
91
+ onCancel: () => {
92
+ this._lastAction = "Overwrite cancelled";
93
+ },
94
+ },
95
+ }),
96
+ );
97
+ }
98
+
99
+ render() {
100
+ return html`
101
+ <bim-panel label="Modal Actions">
102
+ <bim-panel-section label="Actions" icon="tabler:click">
103
+ <bim-button
104
+ label="Delete model (async confirm)"
105
+ icon="tabler:trash"
106
+ @click=${this._confirmDelete}
107
+ ></bim-button>
108
+ <bim-button
109
+ label="Overwrite file (sync confirm)"
110
+ icon="tabler:file-upload"
111
+ @click=${this._confirmOverwrite}
112
+ ></bim-button>
113
+ <bim-label>Last action: ${this._lastAction}</bim-label>
114
+ </bim-panel-section>
115
+ </bim-panel>
116
+ `;
117
+ }
118
+ }
119
+
120
+ // ---- app wiring ----
121
+
122
+ const client = PlatformClient.fromPlatformContext();
123
+ const { components } = (await client.setup(
124
+ { OBC, OBF, BUI, THREE, FRAGS },
125
+ { uuid: UIManager.uuid },
126
+ )) as { components: OBC.Components };
127
+ components.get(UIManager).init();
128
+
129
+ const app = document.createElement("top-app") as unknown as App;
130
+
131
+ app.setup = (waitUntil) => {
132
+ waitUntil(
133
+ (async () => {
134
+ const fragments = components.get(OBC.FragmentsManager);
135
+ const workerUrl = await FRAGS.FragmentsModels.getWorker();
136
+ fragments.init(await FRAGS.toClassicWorker(workerUrl), {
137
+ classicWorker: true,
138
+ });
139
+ })(),
140
+ "Fragments Core",
141
+ );
142
+ return { components, client };
143
+ };
144
+
145
+ app.elements = {
146
+ viewer: () =>
147
+ html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
148
+ panel: () => html`<modal-actions></modal-actions>`,
149
+ };
150
+
151
+ app.base = "viewer";
152
+ app.layouts = {
153
+ main: {
154
+ label: "Main",
155
+ icon: "solar:home-bold",
156
+ template: `"panel" 1fr / 22rem`,
157
+ },
158
+ };
159
+ app.layout = "main";
160
+
161
+ const container = document.getElementById("that-open-app") ?? document.body;
162
+ container.appendChild(app);
163
+ document.body.style.margin = "0";