@snaptrude/plugin-core 0.7.1 → 0.8.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/CHANGELOG.md +14 -0
- package/api-manifest.full.json +6442 -0
- package/api-manifest.json +2029 -128
- package/dist/api/core/camera/index.d.ts +208 -0
- package/dist/api/core/camera/index.d.ts.map +1 -0
- package/dist/api/core/comment/index.d.ts +105 -2
- package/dist/api/core/comment/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +13 -13
- package/dist/api/core/geom/delete/index.d.ts +8 -2
- package/dist/api/core/geom/delete/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/arc.d.ts +5 -5
- package/dist/api/core/geom/query/brep.d.ts +18 -18
- package/dist/api/core/geom/query/circle.d.ts +18 -18
- package/dist/api/core/geom/query/contour.d.ts +20 -20
- package/dist/api/core/geom/query/curve.d.ts +49 -49
- package/dist/api/core/geom/query/edge.d.ts +5 -5
- package/dist/api/core/geom/query/face.d.ts +16 -16
- package/dist/api/core/geom/query/halfedge.d.ts +8 -8
- package/dist/api/core/geom/query/profile.d.ts +19 -19
- package/dist/api/core/geom/query/vertex.d.ts +8 -8
- package/dist/api/core/geom/update/contour.d.ts +14 -14
- package/dist/api/core/geom/update/curve.d.ts +7 -7
- package/dist/api/core/geom/update/profile.d.ts +16 -16
- package/dist/api/core/handles/index.d.ts +210 -0
- package/dist/api/core/handles/index.d.ts.map +1 -0
- package/dist/api/core/index.d.ts +15 -0
- package/dist/api/core/index.d.ts.map +1 -1
- package/dist/api/core/io/export/index.d.ts +132 -0
- package/dist/api/core/io/export/index.d.ts.map +1 -0
- package/dist/api/core/io/import/index.d.ts +1 -1
- package/dist/api/core/io/index.d.ts +5 -0
- package/dist/api/core/io/index.d.ts.map +1 -1
- package/dist/api/core/layers.d.ts +7 -7
- package/dist/api/core/proposals/index.d.ts +65 -9
- package/dist/api/core/proposals/index.d.ts.map +1 -1
- package/dist/api/core/user.d.ts +44 -0
- package/dist/api/core/user.d.ts.map +1 -0
- package/dist/api/design/boolean/index.d.ts +4 -4
- package/dist/api/design/create/index.d.ts +139 -44
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +36 -0
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/edit/index.d.ts +1 -1
- package/dist/api/design/erase/index.d.ts +2 -2
- package/dist/api/design/furniture/index.d.ts +114 -3
- package/dist/api/design/furniture/index.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +10 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/materials/index.d.ts +111 -14
- package/dist/api/design/materials/index.d.ts.map +1 -1
- package/dist/api/design/query/index.d.ts +31 -1
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/query/spaces.d.ts +5 -5
- package/dist/api/design/transform/index.d.ts +83 -14
- package/dist/api/design/transform/index.d.ts.map +1 -1
- package/dist/api/design/types/index.d.ts +181 -0
- package/dist/api/design/types/index.d.ts.map +1 -0
- package/dist/api/design/update/index.d.ts +335 -2
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/design/visibility.d.ts +98 -0
- package/dist/api/design/visibility.d.ts.map +1 -0
- package/dist/api/entity/referenceLine.d.ts +2 -2
- package/dist/api/entity/space.d.ts +19 -19
- package/dist/api/entity/story.d.ts +128 -15
- package/dist/api/entity/story.d.ts.map +1 -1
- package/dist/api/presentation/annotate.d.ts +448 -0
- package/dist/api/presentation/annotate.d.ts.map +1 -0
- package/dist/api/presentation/diagrams.d.ts +49 -8
- package/dist/api/presentation/diagrams.d.ts.map +1 -1
- package/dist/api/presentation/export.d.ts +104 -0
- package/dist/api/presentation/export.d.ts.map +1 -0
- package/dist/api/presentation/index.d.ts +38 -0
- package/dist/api/presentation/index.d.ts.map +1 -1
- package/dist/api/presentation/sheets.d.ts +410 -13
- package/dist/api/presentation/sheets.d.ts.map +1 -1
- package/dist/api/presentation/views.d.ts +165 -10
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/api/program/areas.d.ts +63 -3
- package/dist/api/program/areas.d.ts.map +1 -1
- package/dist/api/program/cores.d.ts +3 -99
- package/dist/api/program/cores.d.ts.map +1 -1
- package/dist/api/program/index.d.ts +2 -2
- package/dist/api/program/index.d.ts.map +1 -1
- package/dist/api/program/layout.d.ts +172 -12
- package/dist/api/program/layout.d.ts.map +1 -1
- package/dist/api/program/site.d.ts +11 -8
- package/dist/api/program/site.d.ts.map +1 -1
- package/dist/api/program/spreadsheet.d.ts +105 -13
- package/dist/api/program/spreadsheet.d.ts.map +1 -1
- package/dist/handles.d.ts +64 -25
- package/dist/handles.d.ts.map +1 -1
- package/dist/index.cjs +2316 -1644
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2224 -1639
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/core/camera/index.ts +212 -0
- package/src/api/core/comment/index.ts +120 -2
- package/src/api/core/geom/delete/index.ts +6 -0
- package/src/api/core/handles/index.ts +233 -0
- package/src/api/core/index.ts +15 -0
- package/src/api/core/io/export/index.ts +124 -0
- package/src/api/core/io/index.ts +5 -0
- package/src/api/core/proposals/index.ts +71 -11
- package/src/api/core/user.ts +46 -0
- package/src/api/design/create/index.ts +166 -36
- package/src/api/design/doors/index.ts +40 -0
- package/src/api/design/furniture/index.ts +127 -3
- package/src/api/design/index.ts +10 -0
- package/src/api/design/materials/index.ts +157 -30
- package/src/api/design/query/index.ts +33 -7
- package/src/api/design/transform/index.ts +89 -12
- package/src/api/design/types/index.ts +156 -0
- package/src/api/design/update/index.ts +402 -6
- package/src/api/design/visibility.ts +109 -0
- package/src/api/entity/story.ts +141 -15
- package/src/api/presentation/annotate.ts +360 -0
- package/src/api/presentation/diagrams.ts +53 -8
- package/src/api/presentation/export.ts +104 -0
- package/src/api/presentation/index.ts +46 -0
- package/src/api/presentation/sheets.ts +346 -13
- package/src/api/presentation/views.ts +164 -12
- package/src/api/program/areas.ts +57 -6
- package/src/api/program/cores.ts +3 -91
- package/src/api/program/index.ts +2 -2
- package/src/api/program/layout.ts +182 -12
- package/src/api/program/site.ts +11 -8
- package/src/api/program/spreadsheet.ts +125 -29
- package/src/handles.ts +77 -13
- package/tsconfig.json +7 -2
|
@@ -19,10 +19,21 @@ import { PluginApiReturn } from "../../types"
|
|
|
19
19
|
* longer `"running"` — a run can take up to 20 minutes.
|
|
20
20
|
* 3. {@linkcode PluginProgramLayoutApi.cancel} aborts an in-flight run.
|
|
21
21
|
*
|
|
22
|
-
* `arrange` produces several candidate layouts
|
|
23
|
-
* solution** as one undoable edit
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* `arrange` produces several candidate layouts. By default it **auto-commits
|
|
23
|
+
* the first solution** as one undoable edit; pass `autoCommit: false` to hold
|
|
24
|
+
* the candidates for review instead — `getState` then reports
|
|
25
|
+
* `status: "pendingReview"` with `totalSolutions`, and
|
|
26
|
+
* {@linkcode PluginProgramLayoutApi.applySolution} commits the one you pick
|
|
27
|
+
* (the headless counterpart of the product's "Solution N of M → Apply" bar).
|
|
28
|
+
* `pack` re-shapes and applies its single result directly. Both are
|
|
29
|
+
* **Pro-plan-gated**, matching the product UI.
|
|
30
|
+
*
|
|
31
|
+
* {@linkcode PluginProgramLayoutApi.stack} is the **cross-storey** action —
|
|
32
|
+
* the product's *Pack in envelope* / auto-stack. It splits the building
|
|
33
|
+
* envelope by storey and packs each storey's departments into its slice as one
|
|
34
|
+
* undoable edit. Unlike `arrange` / `pack`, it is **not** the async-job model:
|
|
35
|
+
* it resolves inline when the whole multi-storey pack is done (no `getState`
|
|
36
|
+
* polling) and returns the storeys it had to skip. It is Pro-gated too.
|
|
26
37
|
*
|
|
27
38
|
* Accessed via `snaptrude.program.layout`.
|
|
28
39
|
*/
|
|
@@ -35,9 +46,16 @@ export abstract class PluginProgramLayoutApi {
|
|
|
35
46
|
* Starts the backend job and **returns immediately** — poll
|
|
36
47
|
* {@linkcode PluginProgramLayoutApi.getState} until `status` leaves
|
|
37
48
|
* `"running"` (a run can take up to 20 minutes). The solver produces
|
|
38
|
-
* several candidate layouts; this **auto-commits the first
|
|
39
|
-
*
|
|
40
|
-
*
|
|
49
|
+
* several candidate layouts; by default this **auto-commits the first
|
|
50
|
+
* solution** as one undoable edit. Pass `autoCommit: false` to review them
|
|
51
|
+
* instead: the run finishes with `status: "pendingReview"` and
|
|
52
|
+
* `totalSolutions` in `getState`, and
|
|
53
|
+
* {@linkcode PluginProgramLayoutApi.applySolution} commits the candidate you
|
|
54
|
+
* pick ({@linkcode PluginProgramLayoutApi.cancel} discards them). An
|
|
55
|
+
* arrange **without an envelope** applies directly (there is nothing to
|
|
56
|
+
* review) regardless of `autoCommit`. Starting a run while one is in flight
|
|
57
|
+
* replaces it; while solutions are pending review, new runs are refused —
|
|
58
|
+
* apply or cancel first.
|
|
41
59
|
*
|
|
42
60
|
* With no `options`, operates on the eligible Room/Department masses on the
|
|
43
61
|
* active storey and auto-detects the single buildable envelope there.
|
|
@@ -53,11 +71,14 @@ export abstract class PluginProgramLayoutApi {
|
|
|
53
71
|
* @throws When a `spaceId` / `departmentId` / `envelopeId` does not resolve.
|
|
54
72
|
* @throws When more than one envelope is on the active storey and none was
|
|
55
73
|
* given (ambiguous).
|
|
74
|
+
* @throws When arrange solutions are pending review (apply or cancel them
|
|
75
|
+
* first).
|
|
56
76
|
* @throws When plugin writes are disabled.
|
|
57
77
|
*
|
|
58
78
|
* @examplePrompt Arrange the rooms in the envelope
|
|
59
79
|
* @examplePrompt Lay out the departments inside the building envelope
|
|
60
80
|
* @examplePrompt Auto-arrange the program spaces
|
|
81
|
+
* @examplePrompt Arrange the rooms but let me pick the solution
|
|
61
82
|
*
|
|
62
83
|
* # Example
|
|
63
84
|
* ```ts
|
|
@@ -98,6 +119,8 @@ export abstract class PluginProgramLayoutApi {
|
|
|
98
119
|
* @throws When a `spaceId` / `departmentId` / `envelopeId` does not resolve.
|
|
99
120
|
* @throws When more than one envelope is on the active storey and none was
|
|
100
121
|
* given (ambiguous).
|
|
122
|
+
* @throws When arrange solutions are pending review (apply or cancel them
|
|
123
|
+
* first).
|
|
101
124
|
* @throws When plugin writes are disabled.
|
|
102
125
|
*
|
|
103
126
|
* @examplePrompt Pack the rooms into the envelope
|
|
@@ -118,6 +141,92 @@ export abstract class PluginProgramLayoutApi {
|
|
|
118
141
|
options?: PluginProgramLayoutRunArgs,
|
|
119
142
|
): PluginApiReturn<PluginProgramLayoutRunResult>
|
|
120
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Apply one of the pending arrange solutions.
|
|
146
|
+
*
|
|
147
|
+
* The headless counterpart of the product's **"Solution N of M → Apply"**
|
|
148
|
+
* review bar: after an {@linkcode PluginProgramLayoutApi.arrange} run
|
|
149
|
+
* started with `autoCommit: false` finishes with `status: "pendingReview"`,
|
|
150
|
+
* this commits the candidate at `index` (0-based,
|
|
151
|
+
* `0 ≤ index < totalSolutions` from
|
|
152
|
+
* {@linkcode PluginProgramLayoutApi.getState}) as **one undoable edit** and
|
|
153
|
+
* discards the other candidates. `getState` then reports
|
|
154
|
+
* `status: "active"`.
|
|
155
|
+
*
|
|
156
|
+
* @param index - 0-based index of the pending solution to apply.
|
|
157
|
+
* @returns A {@linkcode PluginProgramLayoutApplyResult} —
|
|
158
|
+
* `{ success: true }` when the solution was applied.
|
|
159
|
+
* @throws When no arrange solutions are pending review (no
|
|
160
|
+
* `arrange({ autoCommit: false })` run has finished, or its solutions were
|
|
161
|
+
* already applied / cancelled).
|
|
162
|
+
* @throws When `index` is out of range for the pending solutions.
|
|
163
|
+
* @throws When plugin writes are disabled.
|
|
164
|
+
*
|
|
165
|
+
* @examplePrompt Apply the second arrange solution
|
|
166
|
+
* @examplePrompt Pick layout solution 3 and commit it
|
|
167
|
+
* @examplePrompt Apply the arrange solution I chose
|
|
168
|
+
*
|
|
169
|
+
* # Example
|
|
170
|
+
* ```ts
|
|
171
|
+
* await snaptrude.program.layout.arrange({ autoCommit: false })
|
|
172
|
+
* let job = await snaptrude.program.layout.getState()
|
|
173
|
+
* while (job?.status === "running") {
|
|
174
|
+
* await new Promise((r) => setTimeout(r, 5000))
|
|
175
|
+
* job = await snaptrude.program.layout.getState()
|
|
176
|
+
* }
|
|
177
|
+
* if (job?.status === "pendingReview") {
|
|
178
|
+
* console.log(`${job.totalSolutions} candidate layouts`)
|
|
179
|
+
* await snaptrude.program.layout.applySolution(1) // commit the second one
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
public abstract applySolution(
|
|
184
|
+
index: number,
|
|
185
|
+
): PluginApiReturn<PluginProgramLayoutApplyResult>
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Stack the program across **every storey** of the building — the product's
|
|
189
|
+
* *Pack in envelope* / auto-stack.
|
|
190
|
+
*
|
|
191
|
+
* Splits the building envelope massing into per-storey envelope slices, then
|
|
192
|
+
* packs each storey's departments into its slice, applying the whole
|
|
193
|
+
* multi-storey result as **one undoable edit**.
|
|
194
|
+
*
|
|
195
|
+
* Unlike {@linkcode PluginProgramLayoutApi.arrange} /
|
|
196
|
+
* {@linkcode PluginProgramLayoutApi.pack}, this **is not** the async-job
|
|
197
|
+
* model: `await` it and it resolves when the stack is done — there is no
|
|
198
|
+
* `getState` polling. It operates on the whole active model (no id / envelope
|
|
199
|
+
* arguments): it auto-discovers the departments and envelope on each storey.
|
|
200
|
+
*
|
|
201
|
+
* Storeys that have departments but **no envelope** are reported in
|
|
202
|
+
* `skippedStoreys` (nothing was packed there). A storey's departments must
|
|
203
|
+
* already be on that storey — `stack` does not move departments between
|
|
204
|
+
* floors, it lays out each floor's program into that floor's envelope.
|
|
205
|
+
*
|
|
206
|
+
* @returns A {@linkcode PluginProgramLayoutStackResult} — `success: true`
|
|
207
|
+
* with the (possibly empty) `skippedStoreys` when the stack was applied, or
|
|
208
|
+
* `success: false` with an `error` when the run failed (e.g. the adjacency
|
|
209
|
+
* service was unreachable).
|
|
210
|
+
* @throws When the project is not on a Pro plan.
|
|
211
|
+
* @throws When plugin writes are disabled.
|
|
212
|
+
* @throws When an `arrange` / `pack` run, or another `stack`, is already in
|
|
213
|
+
* flight, or arrange solutions are pending review (finish, apply, or
|
|
214
|
+
* `cancel` first).
|
|
215
|
+
*
|
|
216
|
+
* @examplePrompt Stack the program across all floors
|
|
217
|
+
* @examplePrompt Auto-stack the departments into the envelope on every storey
|
|
218
|
+
* @examplePrompt Pack the whole building's program into its envelope
|
|
219
|
+
*
|
|
220
|
+
* # Example
|
|
221
|
+
* ```ts
|
|
222
|
+
* const { success, skippedStoreys, error } = await snaptrude.program.layout.stack()
|
|
223
|
+
* if (!success) throw new Error(error)
|
|
224
|
+
* if (skippedStoreys.length)
|
|
225
|
+
* console.warn(`No envelope on storeys: ${skippedStoreys.join(", ")}`)
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
public abstract stack(): PluginApiReturn<PluginProgramLayoutStackResult>
|
|
229
|
+
|
|
121
230
|
/**
|
|
122
231
|
* Get the state of the layout run.
|
|
123
232
|
*
|
|
@@ -130,6 +239,10 @@ export abstract class PluginProgramLayoutApi {
|
|
|
130
239
|
* | `"running"` | A run is in flight — keep polling |
|
|
131
240
|
* | `"active"` | The run finished and its layout is applied to the model |
|
|
132
241
|
* | `"inactive"` | A run finished without applying a layout (the solver failed or found no solution) |
|
|
242
|
+
* | `"pendingReview"` | An `arrange({ autoCommit: false })` run finished and its candidates await {@linkcode PluginProgramLayoutApi.applySolution} / {@linkcode PluginProgramLayoutApi.cancel} |
|
|
243
|
+
*
|
|
244
|
+
* While `status` is `"pendingReview"` the state also carries
|
|
245
|
+
* `totalSolutions` — the number of candidate layouts to pick from.
|
|
133
246
|
*
|
|
134
247
|
* @returns A {@linkcode PluginProgramLayoutStateResult} with the run
|
|
135
248
|
* `status`, or `null` when no run result is available (never ran or was
|
|
@@ -150,11 +263,13 @@ export abstract class PluginProgramLayoutApi {
|
|
|
150
263
|
/**
|
|
151
264
|
* Cancel the in-flight layout run.
|
|
152
265
|
*
|
|
153
|
-
* Aborts the backend job and discards any pending solution.
|
|
154
|
-
*
|
|
266
|
+
* Aborts the backend job and discards any pending solution. Also discards
|
|
267
|
+
* a finished run's **pending-review** solutions (after
|
|
268
|
+
* `arrange({ autoCommit: false })`) without applying one. A no-op (returns
|
|
269
|
+
* `false`) when nothing is running and nothing is pending.
|
|
155
270
|
*
|
|
156
|
-
* @returns `true` when a run was cancelled
|
|
157
|
-
*
|
|
271
|
+
* @returns `true` when a run was cancelled or pending solutions were
|
|
272
|
+
* discarded, `false` when there was nothing to cancel.
|
|
158
273
|
* @throws When plugin writes are disabled.
|
|
159
274
|
*
|
|
160
275
|
* @examplePrompt Cancel the arrange
|
|
@@ -180,11 +295,13 @@ export abstract class PluginProgramLayoutApi {
|
|
|
180
295
|
* | `spaceIds` | `string[] \| undefined` | Component ids of the Room masses to lay out |
|
|
181
296
|
* | `departmentIds` | `string[] \| undefined` | Component ids of the Department masses to lay out |
|
|
182
297
|
* | `envelopeId` | `string \| undefined` | The envelope to fit into — a mass component id or a buildable-envelope handle (`be_…`); omit to auto-detect the single envelope on the active storey |
|
|
298
|
+
* | `autoCommit` | `boolean \| undefined` | `arrange` only — `true` / omitted (default) auto-commits the first candidate solution; `false` holds the candidates for review via {@linkcode PluginProgramLayoutApi.applySolution}. Ignored by `pack` (it applies its single result directly) |
|
|
183
299
|
*/
|
|
184
300
|
export const PluginProgramLayoutRunArgs = z.object({
|
|
185
301
|
spaceIds: z.array(z.string()).optional(),
|
|
186
302
|
departmentIds: z.array(z.string()).optional(),
|
|
187
303
|
envelopeId: z.string().optional(),
|
|
304
|
+
autoCommit: z.boolean().optional(),
|
|
188
305
|
})
|
|
189
306
|
export type PluginProgramLayoutRunArgs = z.infer<
|
|
190
307
|
typeof PluginProgramLayoutRunArgs
|
|
@@ -217,11 +334,13 @@ export type PluginProgramLayoutRunResult = z.infer<
|
|
|
217
334
|
* | `"running"` | A run is in flight — keep polling |
|
|
218
335
|
* | `"active"` | The run finished and its layout is applied to the model |
|
|
219
336
|
* | `"inactive"` | A run finished without applying a layout (the solver failed or found no solution) |
|
|
337
|
+
* | `"pendingReview"` | An `arrange({ autoCommit: false })` run finished and its candidate solutions await {@linkcode PluginProgramLayoutApi.applySolution} / {@linkcode PluginProgramLayoutApi.cancel} |
|
|
220
338
|
*/
|
|
221
339
|
export const PluginProgramLayoutJobStatus = z.enum([
|
|
222
340
|
"running",
|
|
223
341
|
"active",
|
|
224
342
|
"inactive",
|
|
343
|
+
"pendingReview",
|
|
225
344
|
])
|
|
226
345
|
export type PluginProgramLayoutJobStatus = z.infer<
|
|
227
346
|
typeof PluginProgramLayoutJobStatus
|
|
@@ -232,10 +351,12 @@ export type PluginProgramLayoutJobStatus = z.infer<
|
|
|
232
351
|
*
|
|
233
352
|
* | Property | Type | Description |
|
|
234
353
|
* |---|---|---|
|
|
235
|
-
* | `status` | {@linkcode PluginProgramLayoutJobStatus} | `"running"` \| `"active"` \| `"inactive"` |
|
|
354
|
+
* | `status` | {@linkcode PluginProgramLayoutJobStatus} | `"running"` \| `"active"` \| `"inactive"` \| `"pendingReview"` |
|
|
355
|
+
* | `totalSolutions` | `number \| undefined` | Number of candidate solutions awaiting review — present only while `status` is `"pendingReview"` |
|
|
236
356
|
*/
|
|
237
357
|
export const PluginProgramLayoutJobState = z.object({
|
|
238
358
|
status: PluginProgramLayoutJobStatus,
|
|
359
|
+
totalSolutions: z.number().int().optional(),
|
|
239
360
|
})
|
|
240
361
|
export type PluginProgramLayoutJobState = z.infer<
|
|
241
362
|
typeof PluginProgramLayoutJobState
|
|
@@ -250,3 +371,52 @@ export const PluginProgramLayoutStateResult =
|
|
|
250
371
|
export type PluginProgramLayoutStateResult = z.infer<
|
|
251
372
|
typeof PluginProgramLayoutStateResult
|
|
252
373
|
>
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Arguments for {@linkcode PluginProgramLayoutApi.applySolution}.
|
|
377
|
+
*
|
|
378
|
+
* | Property | Type | Description |
|
|
379
|
+
* |---|---|---|
|
|
380
|
+
* | `index` | `number` | 0-based index of the pending solution to apply (`0 ≤ index < totalSolutions`) |
|
|
381
|
+
*/
|
|
382
|
+
export const PluginProgramLayoutApplySolutionArgs = z.object({
|
|
383
|
+
index: z.number().int().min(0),
|
|
384
|
+
})
|
|
385
|
+
export type PluginProgramLayoutApplySolutionArgs = z.infer<
|
|
386
|
+
typeof PluginProgramLayoutApplySolutionArgs
|
|
387
|
+
>
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Result of {@linkcode PluginProgramLayoutApi.applySolution}.
|
|
391
|
+
*
|
|
392
|
+
* | Property | Type | Description |
|
|
393
|
+
* |---|---|---|
|
|
394
|
+
* | `success` | `boolean` | Whether the chosen solution was applied |
|
|
395
|
+
* | `error` | `string \| undefined` | Failure reason when `success` is `false` |
|
|
396
|
+
*/
|
|
397
|
+
export const PluginProgramLayoutApplyResult = z.object({
|
|
398
|
+
success: z.boolean(),
|
|
399
|
+
error: z.string().optional(),
|
|
400
|
+
})
|
|
401
|
+
export type PluginProgramLayoutApplyResult = z.infer<
|
|
402
|
+
typeof PluginProgramLayoutApplyResult
|
|
403
|
+
>
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Result of {@linkcode PluginProgramLayoutApi.stack} — reports whether the
|
|
407
|
+
* cross-storey stack was applied and which storeys were skipped.
|
|
408
|
+
*
|
|
409
|
+
* | Property | Type | Description |
|
|
410
|
+
* |---|---|---|
|
|
411
|
+
* | `success` | `boolean` | Whether the stack was applied |
|
|
412
|
+
* | `skippedStoreys` | `number[]` | Storey values that had departments but no envelope, so nothing was packed there |
|
|
413
|
+
* | `error` | `string \| undefined` | Failure reason when `success` is `false` |
|
|
414
|
+
*/
|
|
415
|
+
export const PluginProgramLayoutStackResult = z.object({
|
|
416
|
+
success: z.boolean(),
|
|
417
|
+
skippedStoreys: z.array(z.number()),
|
|
418
|
+
error: z.string().optional(),
|
|
419
|
+
})
|
|
420
|
+
export type PluginProgramLayoutStackResult = z.infer<
|
|
421
|
+
typeof PluginProgramLayoutStackResult
|
|
422
|
+
>
|
package/src/api/program/site.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { PluginAreaUnit } from "./metrics"
|
|
|
6
6
|
* Program site — read the planning context of the project's site/plot.
|
|
7
7
|
*
|
|
8
8
|
* The **site** is the set of plot/parcel footprints the program is planned
|
|
9
|
-
* against: their total area, per-parcel footprints (
|
|
10
|
-
*
|
|
9
|
+
* against: their total area, per-parcel footprints (world XZ plan coordinates
|
|
10
|
+
* in Snaptrude units — the same plan space as a space's `planPoints`), and —
|
|
11
|
+
* when the project is geo-located on terrain — their geographic
|
|
11
12
|
* (latitude/longitude) rings. This is the program-planning view of the site;
|
|
12
13
|
* zoning numbers (setbacks, FAR/FSI, height limits) live in the site-analysis
|
|
13
14
|
* sheet and are not read here.
|
|
@@ -64,7 +65,8 @@ export abstract class PluginProgramSiteApi {
|
|
|
64
65
|
public abstract getArea(): PluginApiReturn<PluginProgramSiteAreaResult>
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
|
-
* List the site parcels with their footprints (
|
|
68
|
+
* List the site parcels with their footprints (world XZ plan coordinates,
|
|
69
|
+
* Snaptrude units).
|
|
68
70
|
*
|
|
69
71
|
* @returns A {@linkcode PluginProgramSiteListPolygonsResult} with each parcel's
|
|
70
72
|
* id, area, label, and 2D footprint (XZ ground-plane points). Empty when the
|
|
@@ -88,7 +90,7 @@ export abstract class PluginProgramSiteApi {
|
|
|
88
90
|
*
|
|
89
91
|
* Only available when the project is geo-located on terrain; returns `[]` (no
|
|
90
92
|
* rings) otherwise. Use {@linkcode PluginProgramSiteApi.listPolygons} for the
|
|
91
|
-
*
|
|
93
|
+
* world-coordinate footprints that are always available.
|
|
92
94
|
*
|
|
93
95
|
* @returns A {@linkcode PluginProgramSiteListGeoPolygonsResult} with one ring
|
|
94
96
|
* of `{ lat, lng, alt }` points per parcel.
|
|
@@ -187,13 +189,14 @@ export abstract class PluginProgramSiteApi {
|
|
|
187
189
|
}
|
|
188
190
|
|
|
189
191
|
/**
|
|
190
|
-
* A 2D ground-plane point of a site parcel footprint, in
|
|
191
|
-
* (
|
|
192
|
+
* A 2D ground-plane point of a site parcel footprint, in world XZ plan
|
|
193
|
+
* coordinates (Snaptrude units) — the same plan space as a space's
|
|
194
|
+
* `planPoints`, so site parcels overlay space footprints directly.
|
|
192
195
|
*
|
|
193
196
|
* | Property | Type | Description |
|
|
194
197
|
* |---|---|---|
|
|
195
|
-
* | `x` | `number` | X coordinate (
|
|
196
|
-
* | `z` | `number` | Z coordinate (
|
|
198
|
+
* | `x` | `number` | X coordinate (world, Snaptrude units) |
|
|
199
|
+
* | `z` | `number` | Z coordinate (world, Snaptrude units) |
|
|
197
200
|
*/
|
|
198
201
|
export const PluginSiteFootprintPoint = z.object({
|
|
199
202
|
x: z.number(),
|
|
@@ -23,7 +23,8 @@ import { PluginAreaUnit } from "./metrics"
|
|
|
23
23
|
*
|
|
24
24
|
* Plus dataset reads ({@linkcode PluginProgramSpreadsheetApi.getProgram} /
|
|
25
25
|
* {@linkcode PluginProgramSpreadsheetApi.getTakeoff} — the data the render* methods
|
|
26
|
-
* draw
|
|
26
|
+
* draw — and {@linkcode PluginProgramSpreadsheetApi.getMaterialTakeoff}, surface area
|
|
27
|
+
* per material), sheet reads ({@linkcode PluginProgramSpreadsheetApi.listSheets} /
|
|
27
28
|
* {@linkcode PluginProgramSpreadsheetApi.getSheetData}), charts + emphasis
|
|
28
29
|
* ({@linkcode PluginProgramSpreadsheetApi.addChart} /
|
|
29
30
|
* {@linkcode PluginProgramSpreadsheetApi.highlightCells}), workbook file export
|
|
@@ -128,13 +129,15 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
128
129
|
* A specialization of the render* family: the **host pulls and projects the
|
|
129
130
|
* current takeoff dataset itself** — the plugin supplies only the target
|
|
130
131
|
* `sheetName`, an optional `title`, and an optional `filter`; there is **no
|
|
131
|
-
* data argument**.
|
|
132
|
+
* data argument**. The `filter` is applied host-side to the projected rows
|
|
133
|
+
* before rendering. Returns the same rendered-artifact record as
|
|
132
134
|
* {@linkcode PluginProgramSpreadsheetApi.render}.
|
|
133
135
|
* _(Authored ahead — optional via the `spreadsheet?` mount until the host
|
|
134
136
|
* round-trip is live.)_
|
|
135
137
|
*
|
|
136
|
-
* @param options - Optional `sheetName`, `title`, and `filter`
|
|
137
|
-
*
|
|
138
|
+
* @param options - Optional `sheetName`, `title`, and `filter` — a
|
|
139
|
+
* case-insensitive substring kept when any of a row's cell values contains
|
|
140
|
+
* it (a {@linkcode PluginProgramSpreadsheetRenderDatasetArgs}).
|
|
138
141
|
* @returns A {@linkcode PluginProgramSpreadsheetRenderResult} with the written
|
|
139
142
|
* ranges and counts.
|
|
140
143
|
* @throws If the takeoff cannot be rendered.
|
|
@@ -149,9 +152,11 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
149
152
|
* await snaptrude.program.spreadsheet.renderTakeoff({ sheetName: "Takeoff" })
|
|
150
153
|
* ```
|
|
151
154
|
*/
|
|
152
|
-
public abstract renderTakeoff(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
public abstract renderTakeoff(options?: {
|
|
156
|
+
sheetName?: string
|
|
157
|
+
title?: string
|
|
158
|
+
filter?: string
|
|
159
|
+
}): PluginApiReturn<PluginProgramSpreadsheetRenderResult>
|
|
155
160
|
|
|
156
161
|
/**
|
|
157
162
|
* Render the area program onto a sheet.
|
|
@@ -159,13 +164,15 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
159
164
|
* A specialization of the render* family: the **host pulls and projects the
|
|
160
165
|
* current program dataset itself** (departments with area targets vs allocated)
|
|
161
166
|
* — the plugin supplies only the target `sheetName`, an optional `title`, and an
|
|
162
|
-
* optional `filter`; there is **no data argument**.
|
|
167
|
+
* optional `filter`; there is **no data argument**. The `filter` is applied
|
|
168
|
+
* host-side to the projected rows before rendering. Returns the same
|
|
163
169
|
* rendered-artifact record as {@linkcode PluginProgramSpreadsheetApi.render}.
|
|
164
170
|
* _(Authored ahead — optional via the `spreadsheet?` mount until the host
|
|
165
171
|
* round-trip is live.)_
|
|
166
172
|
*
|
|
167
|
-
* @param options - Optional `sheetName`, `title`, and `filter`
|
|
168
|
-
*
|
|
173
|
+
* @param options - Optional `sheetName`, `title`, and `filter` — a
|
|
174
|
+
* case-insensitive substring kept when any of a row's cell values contains
|
|
175
|
+
* it (a {@linkcode PluginProgramSpreadsheetRenderDatasetArgs}).
|
|
169
176
|
* @returns A {@linkcode PluginProgramSpreadsheetRenderResult} with the written
|
|
170
177
|
* ranges and counts.
|
|
171
178
|
* @throws If the program cannot be rendered.
|
|
@@ -180,20 +187,27 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
180
187
|
* await snaptrude.program.spreadsheet.renderProgram({ sheetName: "Program" })
|
|
181
188
|
* ```
|
|
182
189
|
*/
|
|
183
|
-
public abstract renderProgram(
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
public abstract renderProgram(options?: {
|
|
191
|
+
sheetName?: string
|
|
192
|
+
title?: string
|
|
193
|
+
filter?: string
|
|
194
|
+
}): PluginApiReturn<PluginProgramSpreadsheetRenderResult>
|
|
186
195
|
|
|
187
196
|
/**
|
|
188
|
-
* Export the
|
|
197
|
+
* Export the report workbook to a file (xlsx, pdf, or csv).
|
|
189
198
|
*
|
|
190
199
|
* Returns the file content as base64 so the plugin can download, upload, or
|
|
191
200
|
* attach it. This is the workbook **file** export; to read cell **values** back
|
|
192
201
|
* as data, use {@linkcode PluginProgramSpreadsheetApi.getSheetData} instead.
|
|
193
202
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
203
|
+
* `xlsx` and `pdf` export the **whole** workbook. `csv` is inherently
|
|
204
|
+
* single-sheet: it serializes one sheet's used range — pass `options.sheetName`
|
|
205
|
+
* to choose which sheet, or omit it to serialize the active sheet.
|
|
206
|
+
*
|
|
207
|
+
* @param format - The file format to export to.
|
|
208
|
+
* @param options - Optional `fileName` (without extension; a default is used
|
|
209
|
+
* when omitted) and `sheetName` — the sheet to serialize for `csv`
|
|
210
|
+
* (ignored by `xlsx`/`pdf`, which always export the whole workbook).
|
|
197
211
|
* @returns A {@linkcode PluginProgramSpreadsheetExportResult} with the file's
|
|
198
212
|
* `fileName`, `mimeType`, and base64 `dataBase64`.
|
|
199
213
|
* @throws If the workbook cannot be serialized to the requested format.
|
|
@@ -202,16 +216,20 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
202
216
|
* @examplePrompt Download the whole workbook as a PDF
|
|
203
217
|
* @examplePrompt Export the program workbook to xlsx
|
|
204
218
|
* @examplePrompt Save the report as a csv file
|
|
219
|
+
* @examplePrompt Export the Takeoff sheet as CSV
|
|
205
220
|
*
|
|
206
221
|
* # Example
|
|
207
222
|
* ```ts
|
|
208
223
|
* const file = await snaptrude.program.spreadsheet.export("xlsx")
|
|
209
224
|
* // file.fileName, file.mimeType, file.dataBase64
|
|
225
|
+
*
|
|
226
|
+
* // CSV of a specific sheet:
|
|
227
|
+
* const csv = await snaptrude.program.spreadsheet.export("csv", { sheetName: "Takeoff" })
|
|
210
228
|
* ```
|
|
211
229
|
*/
|
|
212
230
|
public abstract export(
|
|
213
231
|
format: PluginSpreadsheetExportFormat,
|
|
214
|
-
options?: { fileName?: string },
|
|
232
|
+
options?: { fileName?: string; sheetName?: string },
|
|
215
233
|
): PluginApiReturn<PluginProgramSpreadsheetExportResult>
|
|
216
234
|
|
|
217
235
|
/**
|
|
@@ -378,6 +396,38 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
378
396
|
*/
|
|
379
397
|
public abstract getTakeoff(): PluginApiReturn<PluginProgramSpreadsheetGetTakeoffResult>
|
|
380
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Read the material take-off dataset (surface area per material, per element type).
|
|
401
|
+
*
|
|
402
|
+
* The native "Material Take-Off" quantities — the same figures the BIM Take-Off's
|
|
403
|
+
* *Material Take-Off* sheet lists — as render-ready rows: for each material applied
|
|
404
|
+
* to a wall/floor/ceiling/slab/roof family, its rolled-up **surface area** in the
|
|
405
|
+
* project's display units. This is the material-centric complement to
|
|
406
|
+
* {@linkcode PluginProgramSpreadsheetApi.getTakeoff} (which rolls up by element
|
|
407
|
+
* family). A read only — nothing is written and no file is downloaded.
|
|
408
|
+
*
|
|
409
|
+
* When no materials are applied (or the model is empty) the result is simply an
|
|
410
|
+
* empty `rows` array — not an error.
|
|
411
|
+
*
|
|
412
|
+
* @returns A {@linkcode PluginProgramSpreadsheetGetMaterialTakeoffResult} with the
|
|
413
|
+
* material take-off `rows`, a `rowCount`, and the `generatedAt` timestamp.
|
|
414
|
+
*
|
|
415
|
+
* @examplePrompt Get the material take-off
|
|
416
|
+
* @examplePrompt How much of each material is used?
|
|
417
|
+
* @examplePrompt Read the surface area by material
|
|
418
|
+
* @examplePrompt Give me the material quantities before I render them
|
|
419
|
+
* @examplePrompt What's in the material take-off right now?
|
|
420
|
+
*
|
|
421
|
+
* # Example
|
|
422
|
+
* ```ts
|
|
423
|
+
* const mto = await snaptrude.program.spreadsheet.getMaterialTakeoff()
|
|
424
|
+
* for (const row of mto.rows) {
|
|
425
|
+
* console.log(row.objectType, row.family, row.material, row.quantity, row.unit)
|
|
426
|
+
* }
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
public abstract getMaterialTakeoff(): PluginApiReturn<PluginProgramSpreadsheetGetMaterialTakeoffResult>
|
|
430
|
+
|
|
381
431
|
// --- Sheet construction (lower-level cell writes; render is the high-level path) ---
|
|
382
432
|
|
|
383
433
|
/**
|
|
@@ -597,9 +647,9 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
597
647
|
* await snaptrude.program.spreadsheet.recalculate()
|
|
598
648
|
* ```
|
|
599
649
|
*/
|
|
600
|
-
public abstract recalculate(
|
|
601
|
-
|
|
602
|
-
): PluginApiReturn<PluginProgramSpreadsheetRecalculateResult>
|
|
650
|
+
public abstract recalculate(options?: {
|
|
651
|
+
sheetName?: string
|
|
652
|
+
}): PluginApiReturn<PluginProgramSpreadsheetRecalculateResult>
|
|
603
653
|
|
|
604
654
|
/**
|
|
605
655
|
* Run a sequence of sheet operations as one atomic, undoable transaction.
|
|
@@ -689,9 +739,9 @@ export abstract class PluginProgramSpreadsheetApi {
|
|
|
689
739
|
* const { entries } = await snaptrude.program.spreadsheet.getAuditLog({ limit: 10 })
|
|
690
740
|
* ```
|
|
691
741
|
*/
|
|
692
|
-
public abstract getAuditLog(
|
|
693
|
-
|
|
694
|
-
): PluginApiReturn<PluginProgramSpreadsheetGetAuditLogResult>
|
|
742
|
+
public abstract getAuditLog(options?: {
|
|
743
|
+
limit?: number
|
|
744
|
+
}): PluginApiReturn<PluginProgramSpreadsheetGetAuditLogResult>
|
|
695
745
|
|
|
696
746
|
/**
|
|
697
747
|
* Ping the program-mode spreadsheet bridge to check it is reachable.
|
|
@@ -839,9 +889,9 @@ export abstract class PluginProgramSpreadsheetBindingsApi {
|
|
|
839
889
|
* await snaptrude.program.spreadsheet.bindings.refresh({ name: "takeoff" })
|
|
840
890
|
* ```
|
|
841
891
|
*/
|
|
842
|
-
public abstract refresh(
|
|
843
|
-
|
|
844
|
-
): PluginApiReturn<PluginProgramSpreadsheetBindingsRefreshResult>
|
|
892
|
+
public abstract refresh(options?: {
|
|
893
|
+
name?: string
|
|
894
|
+
}): PluginApiReturn<PluginProgramSpreadsheetBindingsRefreshResult>
|
|
845
895
|
|
|
846
896
|
/**
|
|
847
897
|
* List all data bindings in the workbook.
|
|
@@ -977,7 +1027,7 @@ export type PluginProgramSpreadsheetRenderResult = z.infer<
|
|
|
977
1027
|
* |---|---|---|
|
|
978
1028
|
* | `sheetName` | `string?` | Target sheet name (a default is used when omitted) |
|
|
979
1029
|
* | `title` | `string?` | Optional title rendered above the table |
|
|
980
|
-
* | `filter` | `string?` |
|
|
1030
|
+
* | `filter` | `string?` | Case-insensitive substring — a row is kept when any of its cell values contains it (blank/omitted keeps every row). Not a query language. |
|
|
981
1031
|
*/
|
|
982
1032
|
export const PluginProgramSpreadsheetRenderDatasetArgs = z.object({
|
|
983
1033
|
sheetName: z.string().optional(),
|
|
@@ -999,12 +1049,14 @@ export type PluginSpreadsheetExportFormat = z.infer<
|
|
|
999
1049
|
*
|
|
1000
1050
|
* | Property | Type | Description |
|
|
1001
1051
|
* |---|---|---|
|
|
1002
|
-
* | `format` | `"xlsx" \| "pdf" \| "csv"` | The file format to export
|
|
1052
|
+
* | `format` | `"xlsx" \| "pdf" \| "csv"` | The file format to export to |
|
|
1003
1053
|
* | `fileName` | `string?` | Desired file name (without extension); a default is used when omitted |
|
|
1054
|
+
* | `sheetName` | `string?` | For `csv`: the sheet to serialize (the active sheet when omitted). Ignored by `xlsx`/`pdf`. |
|
|
1004
1055
|
*/
|
|
1005
1056
|
export const PluginProgramSpreadsheetExportArgs = z.object({
|
|
1006
1057
|
format: PluginSpreadsheetExportFormat,
|
|
1007
1058
|
fileName: z.string().optional(),
|
|
1059
|
+
sheetName: z.string().optional(),
|
|
1008
1060
|
})
|
|
1009
1061
|
export type PluginProgramSpreadsheetExportArgs = z.infer<
|
|
1010
1062
|
typeof PluginProgramSpreadsheetExportArgs
|
|
@@ -1286,6 +1338,50 @@ export type PluginProgramSpreadsheetGetTakeoffResult = z.infer<
|
|
|
1286
1338
|
typeof PluginProgramSpreadsheetGetTakeoffResult
|
|
1287
1339
|
>
|
|
1288
1340
|
|
|
1341
|
+
/**
|
|
1342
|
+
* One row in the material take-off dataset. The take-off is grouped by element
|
|
1343
|
+
* object type + family + applied material, so each row is a rolled-up surface
|
|
1344
|
+
* area for that material on that family.
|
|
1345
|
+
*
|
|
1346
|
+
* | Property | Type | Description |
|
|
1347
|
+
* |---|---|---|
|
|
1348
|
+
* | `objectType` | `string` | Element object type the material sits on (`"wall"`, `"floor"`, `"ceiling"`, `"slab"`, `"roof"`) |
|
|
1349
|
+
* | `family` | `string` | Element family the quantity is aggregated under |
|
|
1350
|
+
* | `material` | `string` | Applied material name |
|
|
1351
|
+
* | `quantity` | `number` | Rolled-up surface area in `unit` |
|
|
1352
|
+
* | `unit` | `string` | Area unit (e.g. `"sq.ft"` or `"sq.m"`) |
|
|
1353
|
+
*/
|
|
1354
|
+
export const PluginSpreadsheetMaterialTakeoffRow = z.object({
|
|
1355
|
+
objectType: z.string(),
|
|
1356
|
+
family: z.string(),
|
|
1357
|
+
material: z.string(),
|
|
1358
|
+
quantity: z.number(),
|
|
1359
|
+
unit: z.string(),
|
|
1360
|
+
})
|
|
1361
|
+
export type PluginSpreadsheetMaterialTakeoffRow = z.infer<
|
|
1362
|
+
typeof PluginSpreadsheetMaterialTakeoffRow
|
|
1363
|
+
>
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* Result of {@linkcode PluginProgramSpreadsheetApi.getMaterialTakeoff} — the native
|
|
1367
|
+
* material take-off dataset (surface area per material). Empty when no materials are
|
|
1368
|
+
* applied.
|
|
1369
|
+
*
|
|
1370
|
+
* | Property | Type | Description |
|
|
1371
|
+
* |---|---|---|
|
|
1372
|
+
* | `rows` | {@linkcode PluginSpreadsheetMaterialTakeoffRow}`[]` | One row per object-type/family/material group |
|
|
1373
|
+
* | `rowCount` | `number` | Number of rows |
|
|
1374
|
+
* | `generatedAt` | `string` | ISO timestamp of when the dataset was read |
|
|
1375
|
+
*/
|
|
1376
|
+
export const PluginProgramSpreadsheetGetMaterialTakeoffResult = z.object({
|
|
1377
|
+
rows: z.array(PluginSpreadsheetMaterialTakeoffRow),
|
|
1378
|
+
rowCount: z.number(),
|
|
1379
|
+
generatedAt: z.string(),
|
|
1380
|
+
})
|
|
1381
|
+
export type PluginProgramSpreadsheetGetMaterialTakeoffResult = z.infer<
|
|
1382
|
+
typeof PluginProgramSpreadsheetGetMaterialTakeoffResult
|
|
1383
|
+
>
|
|
1384
|
+
|
|
1289
1385
|
// --- createSheet -----------------------------------------------------------
|
|
1290
1386
|
|
|
1291
1387
|
/** Behaviour when {@linkcode PluginProgramSpreadsheetApi.createSheet} targets an existing sheet name. */
|