@thatopen/services 0.7.0 → 0.9.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 +62 -62
- package/dist/built-in/index.d.ts +66 -41
- package/dist/cli/lib/revit-addin.d.ts +8 -0
- package/dist/cli.js +154 -13
- package/dist/core/client.d.ts +6 -0
- package/dist/core/platform-client.d.ts +139 -0
- package/dist/core/platform-client.live.test.d.ts +1 -0
- package/dist/core/platform-client.notifications.test.d.ts +1 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +635 -445
- package/dist/types/notifications.d.ts +54 -0
- package/dist/vite-env.d.ts +1 -1
- package/docs/ai-quickstart.md +120 -1
- package/docs/cli/create.md +29 -29
- 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/docs/flow-plugin-guide.md +26 -0
- package/docs/revit-collab-quickstart.md +26 -17
- package/docs/rhino-interop-quickstart.md +74 -7
- package/package.json +1 -1
- 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 +97 -97
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
- package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
- package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
- package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -70
- package/src/built-in/UIManager/src/models-list/example.ts +122 -122
- package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
- package/src/built-in/index.ts +66 -41
- package/src/cli/templates/app/index.html +35 -35
- package/src/cli/templates/app/package.json +32 -32
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
- 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 -1
- package/src/cli/templates/app/src/main.history.ts +191 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
- package/src/cli/templates/app/src/ui-components/index.ts +2 -2
- package/src/cli/templates/app/tsconfig.json +16 -16
- package/src/cli/templates/app/vite.config.js +57 -57
- 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 -5
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
/* MD
|
|
2
|
-
## topics-panel
|
|
3
|
-
---
|
|
4
|
-
Every coordination workflow needs a place to track issues, clashes, and
|
|
5
|
-
action items against a 3D model — who's responsible, what still needs
|
|
6
|
-
review, and where in the model it actually is. Building that from scratch
|
|
7
|
-
means a BCF-compatible data model, a form, comment threads, viewpoint
|
|
8
|
-
capture/navigation, document links, and a persistence layer — all before a
|
|
9
|
-
single issue gets tracked.
|
|
10
|
-
|
|
11
|
-
`topics-panel` is a ready-made web component that delivers exactly that. It
|
|
12
|
-
connects to `@thatopen/components`' `BCFTopics` (and `Viewpoints`)
|
|
13
|
-
automatically and manages the entire workflow: the topic list with search,
|
|
14
|
-
full CRUD on topics/comments/viewpoints/documents, camera navigation,
|
|
15
|
-
BCF export/import, and auto-save — without you writing any UI code.
|
|
16
|
-
|
|
17
|
-
This tutorial covers the prerequisites before mounting the panel; dropping
|
|
18
|
-
it into a `top-app` layout alongside a 3D viewer; and a breakdown of
|
|
19
|
-
everything the panel handles automatically so you know what you do not need
|
|
20
|
-
to implement yourself.
|
|
21
|
-
|
|
22
|
-
By the end, you'll have a fully working topics/issues environment running
|
|
23
|
-
in your application with a single line of markup.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
import { html } from "lit";
|
|
27
|
-
import * as THREE from "three";
|
|
28
|
-
import * as OBC from "@thatopen/components";
|
|
29
|
-
import * as OBF from "@thatopen/components-front";
|
|
30
|
-
import * as FRAGS from "@thatopen/fragments";
|
|
31
|
-
import * as BUI from "@thatopen/ui";
|
|
32
|
-
import { PlatformClient, UIManager, TopicsManager } from "@thatopen/services";
|
|
33
|
-
import type { App } from "../app/index";
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/* MD
|
|
37
|
-
### ✅ Prerequisites
|
|
38
|
-
|
|
39
|
-
Two conditions must be met before the panel mounts:
|
|
40
|
-
|
|
41
|
-
1. **`UIManager` must be in the setup call.** It registers all platform web
|
|
42
|
-
components, including `<top-topics-panel>` itself. Without it the
|
|
43
|
-
element is unknown to the browser and renders as an empty box.
|
|
44
|
-
|
|
45
|
-
2. **`TopicsManager.init(client)` must have resolved.** It configures
|
|
46
|
-
`BCFTopics` (version, author, assignable users — all from real project
|
|
47
|
-
data) and loads whatever BCF was previously saved for this project. The
|
|
48
|
-
panel mounts into an empty state and never catches up on its own if you
|
|
49
|
-
load a BCF after the fact; it only subscribes to change events, it does
|
|
50
|
-
not poll.
|
|
51
|
-
|
|
52
|
-
Both conditions are naturally satisfied when you call `init` before
|
|
53
|
-
appending `top-app` to the document, which is the pattern shown below.
|
|
54
|
-
*/
|
|
55
|
-
|
|
56
|
-
const client = PlatformClient.fromPlatformContext();
|
|
57
|
-
|
|
58
|
-
// The `{ uuid }` entries tell the platform which built-ins to register for
|
|
59
|
-
// this app — one per built-in beyond the "stable" `@thatopen/components`
|
|
60
|
-
// globals passed as the first argument.
|
|
61
|
-
const { components } = (await client.setup(
|
|
62
|
-
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
63
|
-
{ uuid: UIManager.uuid },
|
|
64
|
-
{ uuid: TopicsManager.uuid },
|
|
65
|
-
)) as { components: OBC.Components };
|
|
66
|
-
|
|
67
|
-
components.get(UIManager).init();
|
|
68
|
-
|
|
69
|
-
// init must resolve before top-app (and therefore topics-panel) mounts.
|
|
70
|
-
await components.get(TopicsManager).init(client);
|
|
71
|
-
|
|
72
|
-
/* MD
|
|
73
|
-
### 🖥️ Wiring the panel
|
|
74
|
-
|
|
75
|
-
Add `topics-panel` as a named area in `app.elements` and reference it in
|
|
76
|
-
your layout template, next to the 3D viewer — the panel controls the
|
|
77
|
-
camera and element selection directly in the scene when you click a
|
|
78
|
-
viewpoint.
|
|
79
|
-
*/
|
|
80
|
-
|
|
81
|
-
const app = document.createElement("top-app") as unknown as App;
|
|
82
|
-
|
|
83
|
-
app.setup = (waitUntil) => {
|
|
84
|
-
waitUntil(
|
|
85
|
-
(async () => {
|
|
86
|
-
const fragments = components.get(OBC.FragmentsManager);
|
|
87
|
-
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
88
|
-
fragments.init(await FRAGS.toClassicWorker(workerUrl), { classicWorker: true });
|
|
89
|
-
})(),
|
|
90
|
-
"Fragments Core",
|
|
91
|
-
);
|
|
92
|
-
return { components, client };
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
app.elements = {
|
|
96
|
-
viewer: () => html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
97
|
-
topics: () => html`<top-topics-panel></top-topics-panel>`,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
app.layouts = {
|
|
101
|
-
main: {
|
|
102
|
-
label: "Main",
|
|
103
|
-
icon: "solar:3d-square-bold",
|
|
104
|
-
template: `"viewer topics" 1fr / 1fr 30rem`,
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
app.layout = "main";
|
|
109
|
-
|
|
110
|
-
const container = document.getElementById("that-open-app") ?? document.body;
|
|
111
|
-
container.appendChild(app);
|
|
112
|
-
document.body.style.margin = "0";
|
|
113
|
-
|
|
114
|
-
/* MD
|
|
115
|
-
### 🤖 What's handled automatically
|
|
116
|
-
|
|
117
|
-
**`TopicsManager`** resolves `Viewpoints.world` in the background once
|
|
118
|
-
`top-viewer` creates it (which only happens after `top-app` finishes
|
|
119
|
-
mounting), including backfilling it onto viewpoints that were restored
|
|
120
|
-
from the saved BCF before the world existed — `Viewpoint.go()` would
|
|
121
|
-
otherwise silently no-op for every one of them. Nothing to wire yourself.
|
|
122
|
-
|
|
123
|
-
**`topics-panel`**, once mounted, takes ownership of the following without
|
|
124
|
-
any further code from you:
|
|
125
|
-
|
|
126
|
-
**Full topic CRUD** — create, edit, and delete (behind a confirmation
|
|
127
|
-
modal) topics with title, type, status, priority, assigned-to, due date,
|
|
128
|
-
and stage. The list shows a search bar, a type badge next to each title,
|
|
129
|
-
and switches to an empty state with a "New topic" call-to-action when
|
|
130
|
-
there's nothing yet.
|
|
131
|
-
|
|
132
|
-
**Comments** — add, edit, and delete (with confirmation) threaded comments
|
|
133
|
-
on a topic, each optionally linked to a specific viewpoint via a clickable
|
|
134
|
-
tag that jumps the camera there.
|
|
135
|
-
|
|
136
|
-
**Viewpoints** — capture the current camera + selection as a new
|
|
137
|
-
viewpoint, browse them in a snapshot carousel, and click one to fly the
|
|
138
|
-
camera and re-apply its selection highlight. Navigation is a no-op (not an
|
|
139
|
-
error) if no models are loaded yet, so a stray click can't fly the camera
|
|
140
|
-
toward nothing.
|
|
141
|
-
|
|
142
|
-
**Documents** — link files from the project's CDE storage (searchable tree
|
|
143
|
-
picker), unlink from just this topic or hard-delete everywhere it's
|
|
144
|
-
referenced, and download. Linking is genuinely shared: the same file
|
|
145
|
-
referenced by two topics reuses one document entry instead of duplicating
|
|
146
|
-
it.
|
|
147
|
-
|
|
148
|
-
**BCF export/import** — export the selected topics (or, with nothing
|
|
149
|
-
selected, the whole project) to a single `.bcf` file named after the
|
|
150
|
-
project or the lone topic's title. Import merges a `.bcf` into the current
|
|
151
|
-
project instead of replacing it; a topic sharing a GUID with an existing
|
|
152
|
-
one is overwritten (treated as an update from elsewhere, not a conflict).
|
|
153
|
-
|
|
154
|
-
**Persistence** — every mutation is auto-saved through `top-app`'s
|
|
155
|
-
`projectStorageContext`, debounced per file so rapid edits collapse into
|
|
156
|
-
one upload. A small "Saving..." indicator (shared with any other built-in
|
|
157
|
-
using the same context, e.g. `clashes-panel`) reflects the real
|
|
158
|
-
debounce-then-upload cycle: just the icon while pending, the full pill
|
|
159
|
-
while actually uploading.
|
|
160
|
-
|
|
161
|
-
**Author/assignee names** — emails resolve to real names (with an
|
|
162
|
-
initials avatar) via `top-app`'s `projectDataContext`, which already
|
|
163
|
-
covers the project owner as well as regular collaborators — no separate
|
|
164
|
-
lookup needed.
|
|
165
|
-
|
|
166
|
-
**Cross-panel awareness** — the list updates live even when a topic is
|
|
167
|
-
created somewhere else entirely (e.g. `clashes-panel`'s "Create topic from
|
|
168
|
-
clash"), including the empty-state → list transition if this was the
|
|
169
|
-
project's first topic.
|
|
170
|
-
*/
|
|
1
|
+
/* MD
|
|
2
|
+
## topics-panel
|
|
3
|
+
---
|
|
4
|
+
Every coordination workflow needs a place to track issues, clashes, and
|
|
5
|
+
action items against a 3D model — who's responsible, what still needs
|
|
6
|
+
review, and where in the model it actually is. Building that from scratch
|
|
7
|
+
means a BCF-compatible data model, a form, comment threads, viewpoint
|
|
8
|
+
capture/navigation, document links, and a persistence layer — all before a
|
|
9
|
+
single issue gets tracked.
|
|
10
|
+
|
|
11
|
+
`topics-panel` is a ready-made web component that delivers exactly that. It
|
|
12
|
+
connects to `@thatopen/components`' `BCFTopics` (and `Viewpoints`)
|
|
13
|
+
automatically and manages the entire workflow: the topic list with search,
|
|
14
|
+
full CRUD on topics/comments/viewpoints/documents, camera navigation,
|
|
15
|
+
BCF export/import, and auto-save — without you writing any UI code.
|
|
16
|
+
|
|
17
|
+
This tutorial covers the prerequisites before mounting the panel; dropping
|
|
18
|
+
it into a `top-app` layout alongside a 3D viewer; and a breakdown of
|
|
19
|
+
everything the panel handles automatically so you know what you do not need
|
|
20
|
+
to implement yourself.
|
|
21
|
+
|
|
22
|
+
By the end, you'll have a fully working topics/issues environment running
|
|
23
|
+
in your application with a single line of markup.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { html } from "lit";
|
|
27
|
+
import * as THREE from "three";
|
|
28
|
+
import * as OBC from "@thatopen/components";
|
|
29
|
+
import * as OBF from "@thatopen/components-front";
|
|
30
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
31
|
+
import * as BUI from "@thatopen/ui";
|
|
32
|
+
import { PlatformClient, UIManager, TopicsManager } from "@thatopen/services";
|
|
33
|
+
import type { App } from "../app/index";
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
/* MD
|
|
37
|
+
### ✅ Prerequisites
|
|
38
|
+
|
|
39
|
+
Two conditions must be met before the panel mounts:
|
|
40
|
+
|
|
41
|
+
1. **`UIManager` must be in the setup call.** It registers all platform web
|
|
42
|
+
components, including `<top-topics-panel>` itself. Without it the
|
|
43
|
+
element is unknown to the browser and renders as an empty box.
|
|
44
|
+
|
|
45
|
+
2. **`TopicsManager.init(client)` must have resolved.** It configures
|
|
46
|
+
`BCFTopics` (version, author, assignable users — all from real project
|
|
47
|
+
data) and loads whatever BCF was previously saved for this project. The
|
|
48
|
+
panel mounts into an empty state and never catches up on its own if you
|
|
49
|
+
load a BCF after the fact; it only subscribes to change events, it does
|
|
50
|
+
not poll.
|
|
51
|
+
|
|
52
|
+
Both conditions are naturally satisfied when you call `init` before
|
|
53
|
+
appending `top-app` to the document, which is the pattern shown below.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
const client = PlatformClient.fromPlatformContext();
|
|
57
|
+
|
|
58
|
+
// The `{ uuid }` entries tell the platform which built-ins to register for
|
|
59
|
+
// this app — one per built-in beyond the "stable" `@thatopen/components`
|
|
60
|
+
// globals passed as the first argument.
|
|
61
|
+
const { components } = (await client.setup(
|
|
62
|
+
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
63
|
+
{ uuid: UIManager.uuid },
|
|
64
|
+
{ uuid: TopicsManager.uuid },
|
|
65
|
+
)) as { components: OBC.Components };
|
|
66
|
+
|
|
67
|
+
components.get(UIManager).init();
|
|
68
|
+
|
|
69
|
+
// init must resolve before top-app (and therefore topics-panel) mounts.
|
|
70
|
+
await components.get(TopicsManager).init(client);
|
|
71
|
+
|
|
72
|
+
/* MD
|
|
73
|
+
### 🖥️ Wiring the panel
|
|
74
|
+
|
|
75
|
+
Add `topics-panel` as a named area in `app.elements` and reference it in
|
|
76
|
+
your layout template, next to the 3D viewer — the panel controls the
|
|
77
|
+
camera and element selection directly in the scene when you click a
|
|
78
|
+
viewpoint.
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
const app = document.createElement("top-app") as unknown as App;
|
|
82
|
+
|
|
83
|
+
app.setup = (waitUntil) => {
|
|
84
|
+
waitUntil(
|
|
85
|
+
(async () => {
|
|
86
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
87
|
+
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
88
|
+
fragments.init(await FRAGS.toClassicWorker(workerUrl), { classicWorker: true });
|
|
89
|
+
})(),
|
|
90
|
+
"Fragments Core",
|
|
91
|
+
);
|
|
92
|
+
return { components, client };
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
app.elements = {
|
|
96
|
+
viewer: () => html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
97
|
+
topics: () => html`<top-topics-panel></top-topics-panel>`,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
app.layouts = {
|
|
101
|
+
main: {
|
|
102
|
+
label: "Main",
|
|
103
|
+
icon: "solar:3d-square-bold",
|
|
104
|
+
template: `"viewer topics" 1fr / 1fr 30rem`,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
app.layout = "main";
|
|
109
|
+
|
|
110
|
+
const container = document.getElementById("that-open-app") ?? document.body;
|
|
111
|
+
container.appendChild(app);
|
|
112
|
+
document.body.style.margin = "0";
|
|
113
|
+
|
|
114
|
+
/* MD
|
|
115
|
+
### 🤖 What's handled automatically
|
|
116
|
+
|
|
117
|
+
**`TopicsManager`** resolves `Viewpoints.world` in the background once
|
|
118
|
+
`top-viewer` creates it (which only happens after `top-app` finishes
|
|
119
|
+
mounting), including backfilling it onto viewpoints that were restored
|
|
120
|
+
from the saved BCF before the world existed — `Viewpoint.go()` would
|
|
121
|
+
otherwise silently no-op for every one of them. Nothing to wire yourself.
|
|
122
|
+
|
|
123
|
+
**`topics-panel`**, once mounted, takes ownership of the following without
|
|
124
|
+
any further code from you:
|
|
125
|
+
|
|
126
|
+
**Full topic CRUD** — create, edit, and delete (behind a confirmation
|
|
127
|
+
modal) topics with title, type, status, priority, assigned-to, due date,
|
|
128
|
+
and stage. The list shows a search bar, a type badge next to each title,
|
|
129
|
+
and switches to an empty state with a "New topic" call-to-action when
|
|
130
|
+
there's nothing yet.
|
|
131
|
+
|
|
132
|
+
**Comments** — add, edit, and delete (with confirmation) threaded comments
|
|
133
|
+
on a topic, each optionally linked to a specific viewpoint via a clickable
|
|
134
|
+
tag that jumps the camera there.
|
|
135
|
+
|
|
136
|
+
**Viewpoints** — capture the current camera + selection as a new
|
|
137
|
+
viewpoint, browse them in a snapshot carousel, and click one to fly the
|
|
138
|
+
camera and re-apply its selection highlight. Navigation is a no-op (not an
|
|
139
|
+
error) if no models are loaded yet, so a stray click can't fly the camera
|
|
140
|
+
toward nothing.
|
|
141
|
+
|
|
142
|
+
**Documents** — link files from the project's CDE storage (searchable tree
|
|
143
|
+
picker), unlink from just this topic or hard-delete everywhere it's
|
|
144
|
+
referenced, and download. Linking is genuinely shared: the same file
|
|
145
|
+
referenced by two topics reuses one document entry instead of duplicating
|
|
146
|
+
it.
|
|
147
|
+
|
|
148
|
+
**BCF export/import** — export the selected topics (or, with nothing
|
|
149
|
+
selected, the whole project) to a single `.bcf` file named after the
|
|
150
|
+
project or the lone topic's title. Import merges a `.bcf` into the current
|
|
151
|
+
project instead of replacing it; a topic sharing a GUID with an existing
|
|
152
|
+
one is overwritten (treated as an update from elsewhere, not a conflict).
|
|
153
|
+
|
|
154
|
+
**Persistence** — every mutation is auto-saved through `top-app`'s
|
|
155
|
+
`projectStorageContext`, debounced per file so rapid edits collapse into
|
|
156
|
+
one upload. A small "Saving..." indicator (shared with any other built-in
|
|
157
|
+
using the same context, e.g. `clashes-panel`) reflects the real
|
|
158
|
+
debounce-then-upload cycle: just the icon while pending, the full pill
|
|
159
|
+
while actually uploading.
|
|
160
|
+
|
|
161
|
+
**Author/assignee names** — emails resolve to real names (with an
|
|
162
|
+
initials avatar) via `top-app`'s `projectDataContext`, which already
|
|
163
|
+
covers the project owner as well as regular collaborators — no separate
|
|
164
|
+
lookup needed.
|
|
165
|
+
|
|
166
|
+
**Cross-panel awareness** — the list updates live even when a topic is
|
|
167
|
+
created somewhere else entirely (e.g. `clashes-panel`'s "Create topic from
|
|
168
|
+
clash"), including the empty-state → list transition if this was the
|
|
169
|
+
project's first topic.
|
|
170
|
+
*/
|
package/src/built-in/index.ts
CHANGED
|
@@ -1142,7 +1142,7 @@ export type ContextMode = "default" | "hidden";
|
|
|
1142
1142
|
/** The three kinds of change a commit can carry. */
|
|
1143
1143
|
export type ChangeKind = "create" | "update" | "delete";
|
|
1144
1144
|
/**
|
|
1145
|
-
* Stable id for a commit across models
|
|
1145
|
+
* Stable id for a commit across models — which is now just its guid.
|
|
1146
1146
|
*
|
|
1147
1147
|
* It used to have to be `${model}:${id}`, because the id was a per-model version number and every
|
|
1148
1148
|
* model had a commit 3. A guid needs no help being unique, and that is exactly what it was for.
|
|
@@ -1155,25 +1155,25 @@ export declare const commitKey: (c: {
|
|
|
1155
1155
|
}) => string;
|
|
1156
1156
|
/** How the commit is shown in 3D: review colours, or the model as it ended up. */
|
|
1157
1157
|
export type HighlightMode = "colored" | "plain";
|
|
1158
|
-
/** Dominant change type of a commit: delete
|
|
1158
|
+
/** Dominant change type of a commit: delete → create → update. */
|
|
1159
1159
|
export declare function dominantChange(commit: RevitFlowCommit): DominantChange;
|
|
1160
1160
|
/**
|
|
1161
|
-
* GitHistoryManager
|
|
1161
|
+
* GitHistoryManager — headless engine for the revit-flow git-history built-in.
|
|
1162
1162
|
*
|
|
1163
|
-
* Owns ALL viewer mutation for the change outlines. It does NOT load the model
|
|
1163
|
+
* Owns ALL viewer mutation for the change outlines. It does NOT load the model —
|
|
1164
1164
|
* the user opens a model from the Project Files panel, and this manager reacts to
|
|
1165
1165
|
* that load: it reads the model's hidden `revitflow_history.json` (if any) and
|
|
1166
1166
|
* publishes the commit list. Showing a commit outlines its changed elements
|
|
1167
|
-
* (create
|
|
1168
|
-
* `OBF.Outliner` groups
|
|
1167
|
+
* (create → green, update → blue, delete → red) via three independently-colored
|
|
1168
|
+
* `OBF.Outliner` groups — a cheap post-process outline that never recolors the
|
|
1169
1169
|
* fragment geometry. The Lit panel (`top-git-history`) is intent-only: it calls
|
|
1170
1170
|
* these methods and subscribes to the events below.
|
|
1171
1171
|
*
|
|
1172
1172
|
* Data model, per loaded model (fileId == modelId), all HIDDEN children of it:
|
|
1173
|
-
* - revitflow_history.json
|
|
1173
|
+
* - revitflow_history.json — { model, commits: [{ id, parent, author, source,
|
|
1174
1174
|
* timestamp, changes:[{type,uniqueId}], counts }] }. The first commit is the
|
|
1175
1175
|
* INITIAL full-model capture (its geometry == the visible baseline file).
|
|
1176
|
-
* - revitflow_frag_<N>.frag
|
|
1176
|
+
* - revitflow_frag_<N>.frag — delta fragments for commit N (its created+modified
|
|
1177
1177
|
* geometry), loaded on demand so created elements can be colored.
|
|
1178
1178
|
*/
|
|
1179
1179
|
declare class _GitHistoryManager extends OBC.Component {
|
|
@@ -1186,15 +1186,40 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1186
1186
|
readonly onError: OBC.Event<string>;
|
|
1187
1187
|
/** The GUID currently selected in the 3D view (null when the selection is cleared). */
|
|
1188
1188
|
readonly onSelectedGuidChanged: OBC.Event<string | null>;
|
|
1189
|
+
/** A source icon was added or replaced. */
|
|
1190
|
+
readonly onSourceIconsChanged: OBC.Event<void>;
|
|
1191
|
+
/**
|
|
1192
|
+
* Which mark to draw on a commit, by the application that wrote it.
|
|
1193
|
+
*
|
|
1194
|
+
* Every commit already says who made it, in `source`. The panel used to draw the Revit logo on
|
|
1195
|
+
* all of them regardless, which was true while Revit was the only thing that could write one and
|
|
1196
|
+
* became a lie the moment anything else did: a commit from another tool would claim to be a
|
|
1197
|
+
* Revit commit, on the one part of the row whose whole job is to say where a change came from.
|
|
1198
|
+
*
|
|
1199
|
+
* The format is deliberately open about who writes history, so the icons have to be too. This is
|
|
1200
|
+
* the registry. Only `revit` is built in; an application adds its own:
|
|
1201
|
+
*
|
|
1202
|
+
* const history = components.get(GitHistoryManager);
|
|
1203
|
+
* history.setSourceIcon("rhino", "https://…/rhino.svg"); // a URL, or a data: URI
|
|
1204
|
+
* history.setSourceIcon("tekla", "<svg viewBox='0 0 24 24'>…</svg>"); // or the markup
|
|
1205
|
+
*
|
|
1206
|
+
* A source with no icon gets a neutral one rather than somebody else's.
|
|
1207
|
+
*/
|
|
1208
|
+
readonly sourceIcons: Map<string, string>;
|
|
1209
|
+
/**
|
|
1210
|
+
* @param source the commit's own `source` value, matched case-insensitively.
|
|
1211
|
+
* @param icon a URL, a `data:` URI, or inline `<svg>` markup.
|
|
1212
|
+
*/
|
|
1213
|
+
setSourceIcon(source: string, icon: string): void;
|
|
1189
1214
|
world?: OBC.World;
|
|
1190
1215
|
/**
|
|
1191
1216
|
* What happens to elements that are NOT part of the selected commit:
|
|
1192
|
-
* "default"
|
|
1193
|
-
* "hidden"
|
|
1217
|
+
* "default" — left as they are (the change outlines sit on the full model)
|
|
1218
|
+
* "hidden" — hidden entirely, isolating the commit's elements
|
|
1194
1219
|
*
|
|
1195
1220
|
* A dimmed ("ghost") middle ground was dropped: the fragments x-ray writes depth
|
|
1196
1221
|
* from the pixels its screen door keeps, so dimmed geometry still occluded the very
|
|
1197
|
-
* elements under review
|
|
1222
|
+
* elements under review — worse the denser the model in front. Fixing that properly
|
|
1198
1223
|
* belongs in the renderer, not here, so this offers the two states that are exact.
|
|
1199
1224
|
*/
|
|
1200
1225
|
contextMode: ContextMode;
|
|
@@ -1212,18 +1237,18 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1212
1237
|
prefetchRadius: number;
|
|
1213
1238
|
/**
|
|
1214
1239
|
* How a commit is presented in 3D:
|
|
1215
|
-
* "colored"
|
|
1216
|
-
* "plain"
|
|
1240
|
+
* "colored" — outline created/edited/deleted in their colours (the review lens)
|
|
1241
|
+
* "plain" — no outlines: the model simply as it stood AFTER the commit, so the
|
|
1217
1242
|
* deleted elements are hidden rather than painted red
|
|
1218
1243
|
*/
|
|
1219
1244
|
highlightMode: HighlightMode;
|
|
1220
|
-
/** @deprecated kept so older callers still compile
|
|
1245
|
+
/** @deprecated kept so older callers still compile — maps onto contextMode. */
|
|
1221
1246
|
get isolateChanges(): boolean;
|
|
1222
|
-
/** Green
|
|
1247
|
+
/** Green — created elements. */
|
|
1223
1248
|
readonly COLOR_CREATED = "#22c55e";
|
|
1224
|
-
/** Golden yellow
|
|
1249
|
+
/** Golden yellow — modified elements. */
|
|
1225
1250
|
readonly COLOR_MODIFIED = "#e3b341";
|
|
1226
|
-
/** Red
|
|
1251
|
+
/** Red — deleted elements. */
|
|
1227
1252
|
readonly COLOR_DELETED = "#ef4444";
|
|
1228
1253
|
readonly GROUP_CREATED = "revitflow-created";
|
|
1229
1254
|
readonly GROUP_MODIFIED = "revitflow-modified";
|
|
@@ -1232,7 +1257,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1232
1257
|
private _projectId?;
|
|
1233
1258
|
/**
|
|
1234
1259
|
* One entry per loaded revit-flow model. Commit ids are per-model version numbers, so
|
|
1235
|
-
* they collide across models
|
|
1260
|
+
* they collide across models — every commit is tagged with its modelId and a commit is
|
|
1236
1261
|
* addressed by {@link commitKey}, never by id alone.
|
|
1237
1262
|
*/
|
|
1238
1263
|
private _models;
|
|
@@ -1304,7 +1329,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1304
1329
|
init(client: PlatformClient): Promise<void>;
|
|
1305
1330
|
/**
|
|
1306
1331
|
* Follow the viewer's selection so the element view tracks whatever the user clicks in
|
|
1307
|
-
* 3D
|
|
1332
|
+
* 3D — no "trace this" button to press. The Highlighter's events appear asynchronously
|
|
1308
1333
|
* (they're registered when the viewer sets it up), so retry briefly until they exist.
|
|
1309
1334
|
*/
|
|
1310
1335
|
private _watchSelection;
|
|
@@ -1313,7 +1338,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1313
1338
|
/**
|
|
1314
1339
|
* Probe a loaded model for a sibling visible `revitflow_history.json` in its
|
|
1315
1340
|
* folder. If present, adopt it as the active model and publish its commits.
|
|
1316
|
-
* Silent for non-revit models and for our own delta frags
|
|
1341
|
+
* Silent for non-revit models and for our own delta frags — only genuine
|
|
1317
1342
|
* fetch/parse failures raise onError.
|
|
1318
1343
|
*/
|
|
1319
1344
|
private _probeModel;
|
|
@@ -1348,7 +1373,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1348
1373
|
* Show the model as it stood AT `commit`: the visible baseline is the model at its
|
|
1349
1374
|
* INITIAL commit, and everything created later lives in per-commit delta .frags loaded
|
|
1350
1375
|
* as separate models. Those deltas stay loaded (the prefetch window keeps neighbours
|
|
1351
|
-
* warm), so stepping BACK has to hide the ones from later commits
|
|
1376
|
+
* warm), so stepping BACK has to hide the ones from later commits — otherwise a wall
|
|
1352
1377
|
* added in commit 3 was still sitting there while you were looking at commit 2.
|
|
1353
1378
|
* Only touches deltas of the commit's own model; other models keep their own state.
|
|
1354
1379
|
*/
|
|
@@ -1388,7 +1413,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1388
1413
|
selectedGuids(): Promise<string[]>;
|
|
1389
1414
|
selectedGuid(): Promise<string | null>;
|
|
1390
1415
|
/**
|
|
1391
|
-
* Select every element the commit touched, in the viewer's own selection
|
|
1416
|
+
* Select every element the commit touched, in the viewer's own selection — so the
|
|
1392
1417
|
* usual tools (properties, isolate, zoom) work on it like any hand-made selection.
|
|
1393
1418
|
* Honours the current type filter, so "only deletions" selects only those.
|
|
1394
1419
|
* @returns how many elements ended up selected.
|
|
@@ -1402,11 +1427,11 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1402
1427
|
private _outliner;
|
|
1403
1428
|
/**
|
|
1404
1429
|
* Create the three independently-colored outline groups once. The viewer
|
|
1405
|
-
* owns the Outliner's DEFAULT group (selection)
|
|
1430
|
+
* owns the Outliner's DEFAULT group (selection) — we only add our own named
|
|
1406
1431
|
* groups and never touch "default".
|
|
1407
1432
|
*/
|
|
1408
1433
|
private _ensureGroups;
|
|
1409
|
-
/** Clear our three outline groups only
|
|
1434
|
+
/** Clear our three outline groups only — leaves the viewer's default group. */
|
|
1410
1435
|
private _clearOutlines;
|
|
1411
1436
|
/**
|
|
1412
1437
|
* Resolve each change bucket's GUIDs to localIds across every loaded model
|
|
@@ -1420,7 +1445,7 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1420
1445
|
private _dropSuperseded;
|
|
1421
1446
|
/**
|
|
1422
1447
|
* Hide (or restore) the elements a commit deleted. Tracked separately from the context
|
|
1423
|
-
* modes so switching Colored
|
|
1448
|
+
* modes so switching Colored↔Plain doesn't disturb ghosting or the rest of the model.
|
|
1424
1449
|
*/
|
|
1425
1450
|
private _applyDeletedVisibility;
|
|
1426
1451
|
/**
|
|
@@ -1429,14 +1454,14 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1429
1454
|
* THE BUG THIS EXISTS FOR. The baseline .frag holds the whole model as of the first
|
|
1430
1455
|
* commit, and every later commit ships a delta .frag with the geometry it created AND
|
|
1431
1456
|
* the geometry it modified. Both stay in the scene. For a CREATED element that is
|
|
1432
|
-
* right
|
|
1457
|
+
* right — it exists in exactly one place. For a MODIFIED one it is not: the element is
|
|
1433
1458
|
* in the baseline at its old shape and in the delta at its new one, and the viewer drew
|
|
1434
1459
|
* both. Measured 2026-08-05 on a wall whose height Quim raised: the new wall stood
|
|
1435
1460
|
* proud of the old one, with the coincident faces z-fighting into a dotted band.
|
|
1436
1461
|
*
|
|
1437
1462
|
* The rule is the obvious one once stated: for any element, only the newest VISIBLE
|
|
1438
1463
|
* source may draw it. Deltas are walked newest-first, each guid is claimed by the first
|
|
1439
|
-
* source that has it, and every older copy
|
|
1464
|
+
* source that has it, and every older copy — in an older delta or in the baseline — is
|
|
1440
1465
|
* hidden. Deltas newer than the commit being shown are already hidden wholesale by
|
|
1441
1466
|
* `_applyFutureVisibility`, so they never get to claim anything.
|
|
1442
1467
|
*
|
|
@@ -1454,13 +1479,13 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1454
1479
|
* load that commit's delta, which is the last place its geometry existed.
|
|
1455
1480
|
*/
|
|
1456
1481
|
private _ensureDeletedGeometry;
|
|
1457
|
-
/** GUIDs
|
|
1482
|
+
/** GUIDs → { modelId: Set<localId> } across the given models. */
|
|
1458
1483
|
private _buildMap;
|
|
1459
1484
|
private _mergeMaps;
|
|
1460
1485
|
/**
|
|
1461
1486
|
* Dim ("ghost") or hide every element that is NOT part of the shown commit, per the
|
|
1462
1487
|
* chosen context mode. Best-effort per model: a model that doesn't support the call is
|
|
1463
|
-
* simply left alone
|
|
1488
|
+
* simply left alone — the outlines still convey the change.
|
|
1464
1489
|
*/
|
|
1465
1490
|
private _applyContext;
|
|
1466
1491
|
/** Undo whatever the context mode did: drop the ghost overlay and restore visibility. */
|
|
@@ -1479,42 +1504,42 @@ declare class _GitHistoryManager extends OBC.Component {
|
|
|
1479
1504
|
}
|
|
1480
1505
|
|
|
1481
1506
|
/**
|
|
1482
|
-
* GitHistoryManager
|
|
1507
|
+
* GitHistoryManager — headless engine for the revit-flow git-history built-in.
|
|
1483
1508
|
*
|
|
1484
|
-
* Owns ALL viewer mutation for the change outlines. It does NOT load the model
|
|
1509
|
+
* Owns ALL viewer mutation for the change outlines. It does NOT load the model —
|
|
1485
1510
|
* the user opens a model from the Project Files panel, and this manager reacts to
|
|
1486
1511
|
* that load: it reads the model's hidden `revitflow_history.json` (if any) and
|
|
1487
1512
|
* publishes the commit list. Showing a commit outlines its changed elements
|
|
1488
|
-
* (create
|
|
1489
|
-
* `OBF.Outliner` groups
|
|
1513
|
+
* (create → green, update → blue, delete → red) via three independently-colored
|
|
1514
|
+
* `OBF.Outliner` groups — a cheap post-process outline that never recolors the
|
|
1490
1515
|
* fragment geometry. The Lit panel (`top-git-history`) is intent-only: it calls
|
|
1491
1516
|
* these methods and subscribes to the events below.
|
|
1492
1517
|
*
|
|
1493
1518
|
* Data model, per loaded model (fileId == modelId), all HIDDEN children of it:
|
|
1494
|
-
* - revitflow_history.json
|
|
1519
|
+
* - revitflow_history.json — { model, commits: [{ id, parent, author, source,
|
|
1495
1520
|
* timestamp, changes:[{type,uniqueId}], counts }] }. The first commit is the
|
|
1496
1521
|
* INITIAL full-model capture (its geometry == the visible baseline file).
|
|
1497
|
-
* - revitflow_frag_<N>.frag
|
|
1522
|
+
* - revitflow_frag_<N>.frag — delta fragments for commit N (its created+modified
|
|
1498
1523
|
* geometry), loaded on demand so created elements can be colored.
|
|
1499
1524
|
*/
|
|
1500
1525
|
export type GitHistoryManager = InstanceType<typeof _GitHistoryManager>;
|
|
1501
1526
|
/**
|
|
1502
|
-
* GitHistoryManager
|
|
1527
|
+
* GitHistoryManager — headless engine for the revit-flow git-history built-in.
|
|
1503
1528
|
*
|
|
1504
|
-
* Owns ALL viewer mutation for the change outlines. It does NOT load the model
|
|
1529
|
+
* Owns ALL viewer mutation for the change outlines. It does NOT load the model —
|
|
1505
1530
|
* the user opens a model from the Project Files panel, and this manager reacts to
|
|
1506
1531
|
* that load: it reads the model's hidden `revitflow_history.json` (if any) and
|
|
1507
1532
|
* publishes the commit list. Showing a commit outlines its changed elements
|
|
1508
|
-
* (create
|
|
1509
|
-
* `OBF.Outliner` groups
|
|
1533
|
+
* (create → green, update → blue, delete → red) via three independently-colored
|
|
1534
|
+
* `OBF.Outliner` groups — a cheap post-process outline that never recolors the
|
|
1510
1535
|
* fragment geometry. The Lit panel (`top-git-history`) is intent-only: it calls
|
|
1511
1536
|
* these methods and subscribes to the events below.
|
|
1512
1537
|
*
|
|
1513
1538
|
* Data model, per loaded model (fileId == modelId), all HIDDEN children of it:
|
|
1514
|
-
* - revitflow_history.json
|
|
1539
|
+
* - revitflow_history.json — { model, commits: [{ id, parent, author, source,
|
|
1515
1540
|
* timestamp, changes:[{type,uniqueId}], counts }] }. The first commit is the
|
|
1516
1541
|
* INITIAL full-model capture (its geometry == the visible baseline file).
|
|
1517
|
-
* - revitflow_frag_<N>.frag
|
|
1542
|
+
* - revitflow_frag_<N>.frag — delta fragments for commit N (its created+modified
|
|
1518
1543
|
* geometry), loaded on demand so created elements can be colored.
|
|
1519
1544
|
*/
|
|
1520
1545
|
export const GitHistoryManager = { uuid: '3f9c1a7e-6b2d-4e18-9a5c-7d0e2f4b6c81' } as typeof _GitHistoryManager & { uuid: '3f9c1a7e-6b2d-4e18-9a5c-7d0e2f4b6c81' };
|