@ngis/plugin-ui 0.4.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 (79) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +25 -0
  3. package/dist/index.cjs +71 -0
  4. package/dist/index.d.ts +114 -0
  5. package/dist/index.mjs +69 -0
  6. package/dist/src/api/analysis.d.ts +140 -0
  7. package/dist/src/api/resources.d.ts +530 -0
  8. package/dist/src/api/scenes.d.ts +251 -0
  9. package/dist/src/api/users.d.ts +22 -0
  10. package/dist/src/api/workflows.d.ts +191 -0
  11. package/dist/src/components/plugin-ui/AttributeTable.d.ts +26 -0
  12. package/dist/src/components/plugin-ui/BatchTable.d.ts +47 -0
  13. package/dist/src/components/plugin-ui/ChartCanvas.d.ts +14 -0
  14. package/dist/src/components/plugin-ui/ExtentPicker.d.ts +22 -0
  15. package/dist/src/components/plugin-ui/FieldSelect.d.ts +23 -0
  16. package/dist/src/components/plugin-ui/Flow.d.ts +256 -0
  17. package/dist/src/components/plugin-ui/ModelSelect.d.ts +36 -0
  18. package/dist/src/components/plugin-ui/ParamForm.d.ts +63 -0
  19. package/dist/src/components/plugin-ui/PickerField.d.ts +52 -0
  20. package/dist/src/components/plugin-ui/ResourceSelect.d.ts +37 -0
  21. package/dist/src/components/plugin-ui/ResultActions.d.ts +48 -0
  22. package/dist/src/components/plugin-ui/RunButton.d.ts +49 -0
  23. package/dist/src/components/plugin-ui/StatChart.d.ts +66 -0
  24. package/dist/src/components/plugin-ui/TaskChrome.d.ts +35 -0
  25. package/dist/src/components/plugin-ui/TaskList.d.ts +29 -0
  26. package/dist/src/components/plugin-ui/TaskStatus.d.ts +55 -0
  27. package/dist/src/components/plugin-ui/batch-model.d.ts +442 -0
  28. package/dist/src/components/plugin-ui/flow-inputs.d.ts +61 -0
  29. package/dist/src/components/plugin-ui/flow-model.d.ts +303 -0
  30. package/dist/src/components/plugin-ui/flow-ports.d.ts +155 -0
  31. package/dist/src/components/plugin-ui/param-form-data.d.ts +122 -0
  32. package/dist/src/components/plugin-ui/param-form-model.d.ts +187 -0
  33. package/dist/src/components/plugin-ui/param-widgets.d.ts +88 -0
  34. package/dist/src/components/plugin-ui/picker-data.d.ts +141 -0
  35. package/dist/src/components/plugin-ui/picker-model.d.ts +150 -0
  36. package/dist/src/components/plugin-ui/recipe-model.d.ts +320 -0
  37. package/dist/src/components/plugin-ui/result-data.d.ts +112 -0
  38. package/dist/src/components/plugin-ui/result-model.d.ts +96 -0
  39. package/dist/src/components/plugin-ui/run-data.d.ts +118 -0
  40. package/dist/src/components/plugin-ui/run-model.d.ts +179 -0
  41. package/dist/src/components/plugin-ui/stat-chart-model.d.ts +168 -0
  42. package/dist/src/components/plugin-ui/validation-messages.d.ts +18 -0
  43. package/dist/src/components/plugin-ui/w2-contracts.d.ts +151 -0
  44. package/dist/src/components/plugin-ui/w3-contracts.d.ts +328 -0
  45. package/dist/src/components/plugin-ui/w4-contracts.d.ts +510 -0
  46. package/dist/src/components/ui/button.d.ts +12 -0
  47. package/dist/src/components/ui/checkbox.d.ts +4 -0
  48. package/dist/src/components/ui/column-resize-handle.d.ts +23 -0
  49. package/dist/src/components/ui/dropdown-menu.d.ts +25 -0
  50. package/dist/src/components/ui/input.d.ts +3 -0
  51. package/dist/src/components/ui/label.d.ts +4 -0
  52. package/dist/src/components/ui/popover.d.ts +10 -0
  53. package/dist/src/components/ui/select.d.ts +15 -0
  54. package/dist/src/components/ui/switch.d.ts +6 -0
  55. package/dist/src/domain/map/types.d.ts +128 -0
  56. package/dist/src/features/gis/components/GisAttributeTable.d.ts +56 -0
  57. package/dist/src/features/gis/hooks/useDatasetFeatureWindow.d.ts +51 -0
  58. package/dist/src/lib/api-error.d.ts +81 -0
  59. package/dist/src/lib/api.d.ts +82 -0
  60. package/dist/src/lib/auth-session.d.ts +22 -0
  61. package/dist/src/lib/hooks/useColumnResize.d.ts +57 -0
  62. package/dist/src/lib/raster-color-layer/RasterColorLayer.d.ts +48 -0
  63. package/dist/src/lib/raster-color-layer/TileGrid.d.ts +31 -0
  64. package/dist/src/lib/raster-color-layer/colorRamp.d.ts +18 -0
  65. package/dist/src/lib/raster-color-layer/shaders/raster-color.frag.d.ts +2 -0
  66. package/dist/src/lib/raster-color-layer/shaders/raster-color.vert.d.ts +2 -0
  67. package/dist/src/lib/raster-color-layer/zoomInterpolate.d.ts +2 -0
  68. package/dist/src/lib/utils.d.ts +2 -0
  69. package/dist/src/sdk/facets/types.d.ts +370 -0
  70. package/dist/src/sdk/host-api.d.ts +256 -0
  71. package/dist/src/sdk/map-api.d.ts +288 -0
  72. package/dist/src/sdk/panels.d.ts +130 -0
  73. package/dist/src/types/analysis.d.ts +205 -0
  74. package/dist/src/types/common.d.ts +17 -0
  75. package/dist/src/types/extensions.d.ts +560 -0
  76. package/dist/src/types/gis.d.ts +242 -0
  77. package/dist/src/types/market-social.d.ts +378 -0
  78. package/dist/src/types/workflow.d.ts +83 -0
  79. package/package.json +59 -0
@@ -0,0 +1,29 @@
1
+ import type { NgisHostAPI } from "../../sdk/host-api";
2
+ import { type NgisTaskVariant } from "./TaskStatus";
3
+ export interface TaskListProps {
4
+ host: NgisHostAPI;
5
+ /** The flow port scope id (F14.5). Also seeds the DOM id. */
6
+ id?: string;
7
+ /** Plugin-authored; rendered **literally** (F13.11). */
8
+ label?: string;
9
+ /**
10
+ * The tasks to show. Empty renders a reason, not a blank panel.
11
+ *
12
+ * Inside a `<Flow>`, **one** entry may be a reference (`"@run.taskId"`): F14.5
13
+ * gives this component a single `taskId` in port, and a bound port contributes a
14
+ * one-element list, so the resolved value joins the literal ids. A second
15
+ * reference has no port to bind to and is surfaced rather than watched.
16
+ */
17
+ taskIds: readonly string[];
18
+ /** Defaults to `full` — the point of the list is the detail. */
19
+ variant?: NgisTaskVariant;
20
+ /**
21
+ * Hide rows whose lifecycle has finished. **`SUCCESS` while integration is
22
+ * still pending is not finished** ({@link isTerminalTaskState}), so such a row
23
+ * survives this filter — collapsing it would be the `complete`/`integrated`
24
+ * conflation the whole facet is built to prevent.
25
+ */
26
+ activeOnly?: boolean;
27
+ className?: string;
28
+ }
29
+ export declare function TaskList({ host, id, label, taskIds: taskIdsProp, variant, activeOnly, className, }: TaskListProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,55 @@
1
+ import type { NgisHostAPI } from "../../sdk/host-api";
2
+ import type { NgisTaskState } from "../../sdk/facets/types";
3
+ export type NgisTaskVariant = "compact" | "full";
4
+ export interface NgisWatchedTasks {
5
+ /** Keyed by task id; absent until the first update for that id arrives. */
6
+ readonly states: Readonly<Record<string, NgisTaskState>>;
7
+ /** A `watch` that threw synchronously — a scope refusal, most likely. */
8
+ readonly error: unknown;
9
+ }
10
+ /**
11
+ * One watcher per id, opened on mount and closed on change or unmount.
12
+ *
13
+ * `watch` is synchronous and returns the watcher, so a scope refusal
14
+ * (`tasks:read`) throws *here* rather than rejecting later — caught and reported,
15
+ * because an unhandled throw in an effect takes the whole panel down and tells the
16
+ * author nothing.
17
+ *
18
+ * The dependency is the **joined** id list: `taskIds` is typically a fresh array
19
+ * literal every render, and depending on its identity would tear every watcher
20
+ * down and rebuild it on each keystroke elsewhere in the panel.
21
+ */
22
+ export declare function useWatchedTaskStates(host: NgisHostAPI, taskIds: readonly string[]): NgisWatchedTasks;
23
+ export interface TaskStateViewProps {
24
+ host: NgisHostAPI;
25
+ state: NgisTaskState;
26
+ variant: NgisTaskVariant;
27
+ className?: string;
28
+ }
29
+ /**
30
+ * The presentation of one `NgisTaskState`, shared by both surfaces so
31
+ * `<TaskList>` is genuinely `<TaskStatus>` repeated rather than a second
32
+ * rendering of the same facts. Not on `@ngis/plugin-ui`'s export table — it is an
33
+ * internal of this pair.
34
+ */
35
+ export declare function TaskStateView({ host, state, variant, className }: TaskStateViewProps): import("react/jsx-runtime").JSX.Element;
36
+ export interface TaskStatusProps {
37
+ host: NgisHostAPI;
38
+ /** The flow port scope id (F14.5). Also seeds the DOM id. */
39
+ id?: string;
40
+ /** Plugin-authored; rendered **literally** (F13.11). */
41
+ label?: string;
42
+ /**
43
+ * The bound `taskId` port value. `null` renders a reason, not an empty box.
44
+ *
45
+ * Inside a `<Flow>` this may be a **reference** — F14.22 writes
46
+ * `taskId="@run.taskId"` — which is resolved through the `taskId` in port.
47
+ * Outside a scope, or for a string that is not a reference, it is the task id
48
+ * itself; `"@@"` opens a literal.
49
+ */
50
+ taskId: string | null;
51
+ variant?: NgisTaskVariant;
52
+ onStateChange?: (state: NgisTaskState) => void;
53
+ className?: string;
54
+ }
55
+ export declare function TaskStatus({ host, id, label, taskId: taskIdProp, variant, onStateChange, className, }: TaskStatusProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,442 @@
1
+ /**
2
+ * `<BatchTable>`'s pure half (Stage 14 Y7 — **F14.21**, F14.9, F14.4).
3
+ *
4
+ * The seam this stage has now used five times — `picker-model`/`picker-data`,
5
+ * `param-form-model`, `run-model`, `flow-model`, and here. Nothing below imports
6
+ * React, a host, an API client or the DOM, and for batch that is load-bearing
7
+ * rather than stylistic: **two of F14.21's three hard rules are statements about
8
+ * scheduling**, and a rule that lives in a `useEffect` cannot be asserted.
9
+ *
10
+ * | F14.21 rule | where it lives here |
11
+ * |---|---|
12
+ * | one `host.tasks.run` per row | {@link runBatchQueue}, one `submit` call per row id |
13
+ * | a **concurrency cap of 3** | {@link batchQueueDispatch} + {@link NGIS_BATCH_CONCURRENCY} |
14
+ * | **a failed row does not cancel the rest** | {@link settleBatchQueueRow} — see below |
15
+ * | one row per run, same generated widgets | {@link batchColumns} + one {@link NgisParamFormState} per row |
16
+ * | JSON-saveable | {@link toBatchConfig} / {@link parseBatchConfig} / {@link fromBatchConfig} |
17
+ *
18
+ * **"A failed row does not cancel the rest" is expressed as an absence.** The
19
+ * queue has no notion of success or failure at all: {@link settleBatchQueueRow}
20
+ * moves a row from `running` to `settled` and takes no outcome, so there is no
21
+ * arm in which it could stop. A queue that read the outcome and *chose* to
22
+ * continue would be one edit away from choosing not to; a queue that cannot see
23
+ * the outcome cannot regress. {@link runBatchQueue} therefore catches everything
24
+ * `submit` can do — resolve, reject, or throw synchronously — and turns each into
25
+ * a per-row result rather than a rejected batch.
26
+ *
27
+ * **The cap is not a tuning knob** (F14.21, and the seam says so again at
28
+ * `w4-contracts.ts:614-621`): the task fabric and the `UsageLimiter` windows are
29
+ * shared and nothing below this line bounds concurrency. {@link runBatchQueue}
30
+ * measures its own {@link NgisBatchRunReport.peakInFlight} so the cap is
31
+ * assertable from the runner's own report rather than from a test's
32
+ * instrumentation of the callback it passed in.
33
+ *
34
+ * ## Each row is a whole `ParamForm` lifecycle, not a row of raw strings
35
+ *
36
+ * F14.21's *"the same generated widgets per cell"* means the cell values are
37
+ * subject to the same four phases as a single-run form (F14.9), including the one
38
+ * hard rule — *a repopulate never overwrites a field whose `altered` is `true`* —
39
+ * and including `depends_on` visibility, which is **per row**: two rows of one
40
+ * tool can legitimately disagree about whether a parameter applies. So a row
41
+ * holds an {@link NgisParamFormState} and every mutation goes through
42
+ * `param-form-model.ts`. Nothing here re-implements a phase.
43
+ *
44
+ * ## Expression-driven row generation is OUT for v1
45
+ *
46
+ * F14.21, verbatim. {@link fillBatchColumnDown} is *not* that: it copies the
47
+ * first row's value into the others, which is QGIS's own "fill down" and involves
48
+ * no expression, no grammar and no new vocabulary. Anything that computed a value
49
+ * would need a third grammar, which F14.4 forbids outright.
50
+ */
51
+ import type { NgisToolUiParam, NgisToolUiSchema } from "../../types/analysis";
52
+ import { type NgisParamFormError, type NgisParamFormState } from "./param-form-model";
53
+ import type { NgisRunOutcome } from "./run-data";
54
+ import type { NgisParamValue, NgisRunSubmission } from "./w2-contracts";
55
+ import { type NgisBatchConfig, type NgisRecipe } from "./w4-contracts";
56
+ /**
57
+ * The kickoff seam's rows, re-exported here so the barrels take them from this
58
+ * module and `w4-contracts.ts` stays a wave artifact — the same rule
59
+ * `flow-model.ts` keeps for `w3-contracts.ts` (and `w4-contracts.ts:26-31` states
60
+ * for itself). Nothing is re-declared: these are the seam's own definitions.
61
+ *
62
+ * **`recipeColumns` is deliberately NOT re-exported here — `recipe-model.ts`
63
+ * publishes it, and this module only imports it.** Found at the W4 merge, and it
64
+ * is the shape of defect the merge exists to catch: it is the one seam function
65
+ * *both* W4 sessions read, so each re-exported it from its own labelled hunk in
66
+ * the host barrel, the two hunks are disjoint so the merge was textually clean,
67
+ * and the result was `error TS2300: Duplicate identifier 'recipeColumns'` that
68
+ * **neither branch could produce alone**. The rule the kickoff should have
69
+ * carved and did not: a *shared* seam row is published by exactly one owner, and
70
+ * for a recipe function that owner is the session that owns recipes. Y7's own
71
+ * `recipeBatchColumns` — which composes it with the batch's column projection —
72
+ * is unaffected and is genuinely Y7's.
73
+ */
74
+ export { NGIS_BATCH_CONCURRENCY, NGIS_BATCH_VERSION, ngisBatchCellId, } from "./w4-contracts";
75
+ export type { NgisBatchConfig } from "./w4-contracts";
76
+ /**
77
+ * Something the table found in its own inputs. **Surfaced, never masked** — the
78
+ * `ExtensionSettingsForm` rule that F14.9 already applies to an author's
79
+ * `widgets`/`hide` overrides, applied to a saved config and to a recipe's
80
+ * promoted inputs.
81
+ *
82
+ * None of these is a refusal. The only refusal is an unknown `batchVersion`, and
83
+ * it is an arm of {@link NgisBatchConfigParse} rather than a defect, because
84
+ * F14.21 carries F14.2's rule verbatim: a reader that does not know the version
85
+ * **refuses**; it never best-efforts.
86
+ */
87
+ export interface NgisBatchDefect {
88
+ readonly kind:
89
+ /** A column that is not a parameter of the loaded schema. */
90
+ "unknown-column"
91
+ /** The config was authored against a different tool. */
92
+ | "tool-mismatch"
93
+ /** Same tool, different `tool_version`. */
94
+ | "version-mismatch"
95
+ /**
96
+ * A saved value F14.9's *mutate* replaced on load — off the parameter's
97
+ * current `choices`, or uncoercible to its `value_type`.
98
+ *
99
+ * **This is the one silent data loss a batch config can suffer, and finding
100
+ * it is why the defect exists.** `initializeParamForm` seeds with
101
+ * `altered: false` (F14.9's text is explicit), and *mutate* drops an
102
+ * unaltered value the current option list no longer offers — so a config
103
+ * carrying `MODE: "legacy"` for a tool whose choices are now
104
+ * `simple|advanced|expert` loads as `"simple"` with nothing on screen. The
105
+ * rule is right and is not changed here; what was missing was anybody saying
106
+ * so. `subject` is the parameter, `detail` the value that was dropped.
107
+ */
108
+ | "dropped-value";
109
+ readonly subject: string;
110
+ readonly detail: string | null;
111
+ }
112
+ /** One run. */
113
+ export interface NgisBatchRow {
114
+ /**
115
+ * Stable for the row's whole life, minted from {@link
116
+ * NgisBatchTableState.nextRowId} and **never reused** — it is the React key,
117
+ * and a reused key would carry one row's widget state onto another.
118
+ *
119
+ * Deliberately *not* the cell-id seed: {@link ngisBatchCellId} takes a **row
120
+ * index**, and that spelling is the seam's (CORRECTION 10). See
121
+ * {@link batchCellId}.
122
+ */
123
+ readonly id: string;
124
+ /** F14.9's state for this row, in full. */
125
+ readonly form: NgisParamFormState;
126
+ /**
127
+ * Values from a loaded config whose keys name no parameter of the current
128
+ * schema. Carried verbatim so a load-then-save cannot silently delete an
129
+ * author's data — the same reason F14.9 keeps unknown override keys.
130
+ */
131
+ readonly extras: Readonly<Record<string, string>>;
132
+ }
133
+ export interface NgisBatchTableState {
134
+ readonly toolId: string;
135
+ readonly toolVersion: number;
136
+ /** UI-schema param names, in display order (F14.21). */
137
+ readonly columns: readonly string[];
138
+ readonly rows: readonly NgisBatchRow[];
139
+ readonly outputMode: "ADD_LAYER" | "UPDATE_RESOURCE";
140
+ readonly sceneId: string | null;
141
+ readonly defects: readonly NgisBatchDefect[];
142
+ /** Next row-id ordinal. Monotonic, so ids are unique across removals. */
143
+ readonly nextRowId: number;
144
+ }
145
+ export interface NgisBatchInit {
146
+ /** How many empty rows to open with. Clamped to at least one. */
147
+ readonly rows?: number;
148
+ /**
149
+ * The column order to prefer over the schema's own — a published recipe's
150
+ * promoted inputs (F14.21, via {@link recipeColumns}), or a saved config's
151
+ * columns. Names the schema does not know become `unknown-column` defects.
152
+ */
153
+ readonly columns?: readonly string[];
154
+ readonly outputMode?: "ADD_LAYER" | "UPDATE_RESOURCE";
155
+ readonly sceneId?: string | null;
156
+ /** Wire-shaped seed applied to every opening row. */
157
+ readonly seed?: Readonly<Record<string, string>>;
158
+ }
159
+ export interface NgisBatchColumns {
160
+ readonly columns: readonly string[];
161
+ /** Preferred names the schema does not declare. Reported, never dropped. */
162
+ readonly unknown: readonly string[];
163
+ }
164
+ /**
165
+ * The columns, and which requested names the tool does not have.
166
+ *
167
+ * With no `preferred`, the order is the schema's own — which is F14.21's
168
+ * "display order" and is the order the server served. With a `preferred` list,
169
+ * the known names lead in *that* order and the remaining parameters follow, so a
170
+ * recipe's or a config's ordering is honoured without ever hiding a parameter
171
+ * the tool actually takes. A parameter absent from the table is a parameter that
172
+ * silently submits its `default_value` on every row, which is the batch version
173
+ * of the `V-224` failure.
174
+ */
175
+ export declare function batchColumns(schema: NgisToolUiSchema, preferred?: readonly string[]): NgisBatchColumns;
176
+ /**
177
+ * A published recipe's batch columns (F14.21), through the seam's own function.
178
+ *
179
+ * Thin on purpose: {@link recipeColumns} is the one function both W4 sessions
180
+ * read, so the recipe → column mapping exists once. What this adds is the
181
+ * *reconciliation* — a recipe input id that is not a parameter of the published
182
+ * tool's UI schema becomes a defect here rather than a missing column nobody
183
+ * mentions.
184
+ */
185
+ export declare function recipeBatchColumns(schema: NgisToolUiSchema, recipe: NgisRecipe): NgisBatchColumns;
186
+ export declare function initializeBatchTable(schema: NgisToolUiSchema, init?: NgisBatchInit): NgisBatchTableState;
187
+ export declare function addBatchRow(schema: NgisToolUiSchema, state: NgisBatchTableState, seed?: Readonly<Record<string, string>>): NgisBatchTableState;
188
+ /**
189
+ * Copy a row, values and all.
190
+ *
191
+ * The copy's fields keep the source's `altered` flags, because the values really
192
+ * were chosen by a user and F14.9's repopulation rule protects exactly that. A
193
+ * duplicate whose fields claimed `altered: false` would have its values dropped
194
+ * by the next `mutate` that repopulated a list.
195
+ */
196
+ export declare function duplicateBatchRow(state: NgisBatchTableState, rowId: string): NgisBatchTableState;
197
+ /** Removing the last row leaves the table empty; it does not re-seed one. A
198
+ * batch with no rows is a real state and the caller says so. */
199
+ export declare function removeBatchRow(state: NgisBatchTableState, rowId: string): NgisBatchTableState;
200
+ /**
201
+ * One cell edit, through F14.9's `setParamValue` — which sets `altered` and
202
+ * re-runs *mutate* for that row only.
203
+ *
204
+ * `optionLists` is per row for the same reason visibility is: `field-select`
205
+ * follows a sibling resource cell, and two rows pointing at different datasets
206
+ * have different field lists.
207
+ */
208
+ export declare function setBatchCell(schema: NgisToolUiSchema, state: NgisBatchTableState, rowId: string, name: string, value: NgisParamValue, optionLists?: Readonly<Record<string, readonly string[]>>): NgisBatchTableState;
209
+ /**
210
+ * QGIS's fill-down: the first row's value for one column, copied into every
211
+ * other row.
212
+ *
213
+ * **Not expression-driven row generation** (F14.21 puts that out of v1) — no
214
+ * value is computed, and the source is a value a user already typed. It goes
215
+ * through {@link setBatchCell}, so each target row runs its own *mutate* and a
216
+ * column whose value the target row's option list does not offer is handled by
217
+ * F14.9's rule rather than by a second one written here.
218
+ */
219
+ export declare function fillBatchColumnDown(schema: NgisToolUiSchema, state: NgisBatchTableState, name: string): NgisBatchTableState;
220
+ export declare function setBatchOutput(state: NgisBatchTableState, output: {
221
+ readonly outputMode?: "ADD_LAYER" | "UPDATE_RESOURCE";
222
+ readonly sceneId?: string | null;
223
+ }): NgisBatchTableState;
224
+ /**
225
+ * A cell's node/DOM id — **the seam's spelling, never a local one**
226
+ * (`ngisBatchCellId`, CORRECTION 10).
227
+ *
228
+ * Four of the twelve widgets delegate to components that are themselves flow
229
+ * nodes keyed by their `id` prop, and the flow registry is last-wins on node id,
230
+ * so N rows rendering one parameter under one id collapse to a single node and
231
+ * N−1 cells bind to nothing.
232
+ *
233
+ * **It takes a row *index*, not a row id, and that is worth stating.** Removing a
234
+ * row therefore renumbers every cell below it, and the surviving rows'
235
+ * widget-level nodes re-register under their new ids. That is correct — the
236
+ * registry keys on the id it is given and a vanished id unregisters — but it also
237
+ * means a cell id is not a durable handle for anything outside one render. Use
238
+ * {@link NgisBatchRow.id} for identity and this for the DOM.
239
+ */
240
+ export declare function batchCellId(scopeId: string, rowIndex: number, name: string): string;
241
+ export interface NgisBatchGate {
242
+ /** Row ids whose client validation passed. Submitted, in this order. */
243
+ readonly ready: readonly string[];
244
+ /** Row id → its client errors. Never submitted; a reason is rendered instead. */
245
+ readonly blocked: Readonly<Record<string, readonly NgisParamFormError[]>>;
246
+ }
247
+ /**
248
+ * F14.9's *validate (client)*, per row.
249
+ *
250
+ * Blocked rows are **partitioned out before anything is submitted**, rather than
251
+ * being enqueued and refused later. Both would honour F14.9, but a fifty-row
252
+ * batch where six rows are incomplete should say "six rows can't run yet" before
253
+ * it spends the other forty-four's worth of task-fabric budget — and a blocked
254
+ * row that occupied a concurrency slot for the duration of a refusal would make
255
+ * the cap of 3 mean something slightly different from what F14.21 says.
256
+ */
257
+ export declare function gateBatchRows(schema: NgisToolUiSchema, state: NgisBatchTableState): NgisBatchGate;
258
+ /**
259
+ * Fold the client errors back onto every row's fields, marking them
260
+ * `hasBeenValidated` — F14.9's `applyClientErrors`, applied row-wise so each
261
+ * cell can render its own message.
262
+ */
263
+ export declare function applyBatchClientErrors(schema: NgisToolUiSchema, state: NgisBatchTableState, render: (error: NgisParamFormError) => string): NgisBatchTableState;
264
+ /** The `NgisRunSubmission` for one row — `toSubmission`, unchanged. */
265
+ export declare function batchRowSubmission(schema: NgisToolUiSchema, row: NgisBatchRow): NgisRunSubmission;
266
+ /** Whether a cell applies to its row at all (`depends_on`, F14.9). Per row. */
267
+ export declare function batchCellVisible(row: NgisBatchRow, name: string): boolean;
268
+ export type NgisBatchRowPhase =
269
+ /** Never submitted. */
270
+ "idle"
271
+ /** Waiting for a concurrency slot. */
272
+ | "queued"
273
+ /** Submitted; the task is in flight. */
274
+ | "running"
275
+ /** Client validation, or the server's pre-flight verdict, refused it. */
276
+ | "blocked"
277
+ /** Submitted successfully — there is a task id. */
278
+ | "submitted"
279
+ /** The validate or the run call itself rejected. */
280
+ | "failed";
281
+ export interface NgisBatchRowResult {
282
+ readonly phase: "blocked" | "submitted" | "failed";
283
+ readonly taskId: string | null;
284
+ /**
285
+ * Why, on this row. F14.21 says a failed row does not cancel the rest, so this
286
+ * is the only per-row signal there is — which is why the caller resolves it
287
+ * through `readApiErrorMessage` (F14.15) rather than off `Error.message`.
288
+ */
289
+ readonly messages: readonly string[];
290
+ }
291
+ /**
292
+ * One row's `NgisRunOutcome`, projected.
293
+ *
294
+ * The three arms map one-for-one and deliberately do not collapse: `blocked` is
295
+ * *the server answered and said no*, `failed` is *we could not ask* (a scope
296
+ * refusal, a transport failure, a facet stub). Those are different things to tell
297
+ * an author, and `run-data.ts:121-124` keeps them apart for the same reason.
298
+ *
299
+ * `message` is the caller's already-extracted server message — `null` when the
300
+ * error carried none, in which case the caller renders its own generic string
301
+ * (F14.15). This module never touches `ApiError`, which is what keeps it pure.
302
+ */
303
+ export declare function batchRowResultOf(outcome: NgisRunOutcome, message: string | null): NgisBatchRowResult;
304
+ /** A row refused before any host call, from its client errors. */
305
+ export declare function blockedBatchRowResult(messages: readonly string[]): NgisBatchRowResult;
306
+ export interface NgisBatchQueueState {
307
+ readonly pending: readonly string[];
308
+ readonly running: readonly string[];
309
+ readonly settled: readonly string[];
310
+ }
311
+ export declare function startBatchQueue(rowIds: readonly string[]): NgisBatchQueueState;
312
+ /**
313
+ * The whole of F14.21's concurrency rule: which rows may start **now**.
314
+ *
315
+ * `concurrency` is a parameter only so the property can be tested at other
316
+ * values; every call site passes {@link NGIS_BATCH_CONCURRENCY} and no prop
317
+ * exposes it. A value below 1 is clamped to 1 rather than deadlocking the queue.
318
+ */
319
+ export declare function batchQueueDispatch(queue: NgisBatchQueueState, concurrency?: number): {
320
+ readonly queue: NgisBatchQueueState;
321
+ readonly start: readonly string[];
322
+ };
323
+ /**
324
+ * A row left `running`. **Takes no outcome, on purpose.**
325
+ *
326
+ * F14.21's *"a failed row does not cancel the rest"* is implemented as an
327
+ * absence: this function cannot see whether the row succeeded, so there is no
328
+ * arm in which it could drain `pending`. A queue that inspected the outcome and
329
+ * chose to continue would be one edit away from choosing not to.
330
+ */
331
+ export declare function settleBatchQueueRow(queue: NgisBatchQueueState, rowId: string): NgisBatchQueueState;
332
+ export declare function batchQueueDone(queue: NgisBatchQueueState): boolean;
333
+ export interface NgisBatchRunReport {
334
+ readonly results: Readonly<Record<string, NgisBatchRowResult>>;
335
+ /**
336
+ * The most submissions the runner ever had in flight at once. Reported by the
337
+ * runner rather than measured by the caller, so *"the cap of 3 is respected"*
338
+ * is a property of the code under test and not of the test's own bookkeeping.
339
+ */
340
+ readonly peakInFlight: number;
341
+ readonly submitted: readonly string[];
342
+ readonly blocked: readonly string[];
343
+ readonly failed: readonly string[];
344
+ }
345
+ /**
346
+ * Rows whose last submission failed before a task existed, or whose submitted
347
+ * task later reached a failed/cancelled lifecycle. Successful and still-active
348
+ * rows are deliberately excluded so a retry cannot duplicate healthy work.
349
+ */
350
+ export declare function retryableBatchRowIds(rowIds: readonly string[], results: Readonly<Record<string, NgisBatchRowResult>>, taskStages: Readonly<Record<string, string | undefined>>): readonly string[];
351
+ export declare const NGIS_BATCH_COLUMN_DEFAULT_WIDTH = 192;
352
+ export declare const NGIS_BATCH_COLUMN_MIN_WIDTH = 160;
353
+ export declare const NGIS_BATCH_COLUMN_MAX_WIDTH = 480;
354
+ export declare const NGIS_BATCH_COLUMN_KEYBOARD_STEP = 16;
355
+ /** Keep pointer and keyboard resizing inside the table's readable range. */
356
+ export declare function clampBatchColumnWidth(width: number): number;
357
+ export interface NgisBatchRunOptions {
358
+ readonly concurrency?: number;
359
+ readonly onStart?: (rowId: string) => void;
360
+ readonly onSettle?: (rowId: string, result: NgisBatchRowResult) => void;
361
+ }
362
+ /**
363
+ * Drive N rows through `submit` at most {@link NGIS_BATCH_CONCURRENCY} at a time,
364
+ * and report every row.
365
+ *
366
+ * `submit` is injected rather than called through a host, which is what keeps
367
+ * this module React- and host-free while still being *the* implementation the
368
+ * component runs: `BatchTable` passes a closure over
369
+ * `runSubmission(host, submission, options)` and the offline proof passes a
370
+ * deferred stub. One scheduler, two callers — the alternative is a scheduler in a
371
+ * `useEffect` and a second one in a test, which is the shape that let `V-224`
372
+ * ship.
373
+ *
374
+ * **Every way `submit` can fail is a per-row `failed`, never a rejected batch:**
375
+ * a rejected promise, a synchronous throw, and a resolved `failed` result all
376
+ * land in `results`. The returned promise resolves once every row has settled and
377
+ * does not reject.
378
+ */
379
+ export declare function runBatchQueue(rowIds: readonly string[], submit: (rowId: string) => Promise<NgisBatchRowResult>, options?: NgisBatchRunOptions): Promise<NgisBatchRunReport>;
380
+ /**
381
+ * F14.21's JSON, from the current table.
382
+ *
383
+ * Two decisions worth naming:
384
+ *
385
+ * 1. **A cell that is currently hidden still saves.** `toSubmission` drops a
386
+ * hidden field, because F14.9 says a parameter the schema declares
387
+ * inapplicable must not be submitted — but a *config* is the author's
388
+ * document, and a value that vanished because a sibling cell was toggled and
389
+ * did not come back when it was toggled again would be data loss with a very
390
+ * confusing cause.
391
+ * 2. **`extras` are re-emitted.** Keys a load could not place are written back
392
+ * exactly as they arrived, so round-tripping a config authored against a newer
393
+ * tool version is lossless.
394
+ */
395
+ export declare function toBatchConfig(state: NgisBatchTableState): NgisBatchConfig;
396
+ export type NgisBatchConfigParse = {
397
+ readonly kind: "ok";
398
+ readonly config: NgisBatchConfig;
399
+ }
400
+ /** F14.21 carries F14.2's rule: an unknown version **refuses**. */
401
+ | {
402
+ readonly kind: "unsupported-version";
403
+ readonly version: number;
404
+ } | {
405
+ readonly kind: "malformed";
406
+ readonly field: string;
407
+ };
408
+ /**
409
+ * Parse a saved config out of `unknown`.
410
+ *
411
+ * Separate from {@link fromBatchConfig} because the two failures are different
412
+ * kinds: this one is *the document is not a batch config we understand*, which is
413
+ * a refusal; the other is *this config was written for a different tool*, which is
414
+ * a defect the author can look at and act on. Collapsing them would make a
415
+ * version bump and a typo'd tool id read the same on screen.
416
+ *
417
+ * The version check comes **first**, before any field is inspected. A v2 config
418
+ * whose `columns` moved would otherwise be reported as malformed, which names the
419
+ * wrong problem.
420
+ */
421
+ export declare function parseBatchConfig(raw: unknown): NgisBatchConfigParse;
422
+ /**
423
+ * A parsed config, against the schema actually loaded.
424
+ *
425
+ * A mismatched `toolId` or `toolVersion` is a **defect, not a refusal**: the
426
+ * server re-resolves and overwrites a pinned tool version at publish
427
+ * (`w4-contracts.ts:166-173`), so a config authored a version ago is the normal
428
+ * case rather than an error, and refusing it would make every republished tool
429
+ * orphan its saved batches. The values load, the mismatch is on screen, and the
430
+ * author decides.
431
+ *
432
+ * Every row's cells are seeded through F14.9's *initialize*, so `default_value`
433
+ * fills any column the config omitted and `fromWireValue` coerces the strings —
434
+ * which is what keeps a saved config and a form value from disagreeing about how
435
+ * `false` is spelled.
436
+ */
437
+ export declare function fromBatchConfig(schema: NgisToolUiSchema, config: NgisBatchConfig): NgisBatchTableState;
438
+ /** A column's header text — the parameter's `label`, F14.10's provenance chain
439
+ * (`x-display-name` → `title` → `name`). A plugin string, rendered literally. */
440
+ export declare function batchColumnParams(schema: NgisToolUiSchema, state: NgisBatchTableState): readonly NgisToolUiParam[];
441
+ /** The values of one row, for a caller that wants them flat. */
442
+ export declare function batchRowValues(row: NgisBatchRow): Readonly<Record<string, NgisParamValue>>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * `RunButton`'s `toolId` + `inputs` → the one {@link NgisRunSubmission}
3
+ * (Stage 14 Y5b, **F14.4 / F14.5**).
4
+ *
5
+ * ## Additive over the same submit path, not a second one
6
+ *
7
+ * W2 shipped `RunButton` taking an **already-resolved** `submission`, deliberately:
8
+ * `"@dem"` is a reference form only a `<Flow>` scope can resolve, and taking
9
+ * `inputs` before `<Flow>` existed would have shipped a prop that silently did
10
+ * nothing. W3 adds the pair, and it lands *here* rather than in `run-data.ts`
11
+ * because everything downstream is unchanged: `runSubmission` still validates then
12
+ * submits, and `toWireParams` is still the single coercion. **A differing coercion
13
+ * is exactly what makes a validate pass and the run fail**, so there is not a
14
+ * second one.
15
+ *
16
+ * ## The role split is Y3's, reused rather than copied
17
+ *
18
+ * A tool's params are `input` (→ `bindings`), `output` (→ `outputNames`) or
19
+ * `option` (→ `params`), and `toSubmission` already owns those rules. So resolved
20
+ * port values are turned into **wire-shaped seed values** and handed to
21
+ * `initializeParamForm` → `toSubmission`: the same two functions a rendered
22
+ * `<ParamForm>` goes through, which is why a flow-bound run and a form-driven run
23
+ * cannot disagree about how a boolean or a multi-valued input is spelled. A second
24
+ * role-splitter here would be the `toWireParams` lesson in a new place.
25
+ *
26
+ * A consequence worth stating: seeding through `initializeParamForm` also applies
27
+ * each param's `default_value`, so a tool option the author did not bind is
28
+ * submitted with its declared default rather than omitted. That is what a
29
+ * generated dialog does, and a flow that behaved differently would run a different
30
+ * tool invocation than the dialog for the same graph.
31
+ */
32
+ import type { NgisToolUiSchema } from "../../types/analysis";
33
+ import type { NgisRunSubmission } from "./w2-contracts";
34
+ import { type NgisResolvedValue } from "./w3-contracts";
35
+ /** Resolved in-port values, by member name. */
36
+ export type NgisFlowInputValues = Readonly<Record<string, NgisResolvedValue>>;
37
+ /**
38
+ * One resolved port value in the wire spelling the seed takes.
39
+ *
40
+ * `null` means "not a scalar a param can carry" — a `record`, which is a spread
41
+ * source rather than a value, and is flattened by the caller before it gets here.
42
+ * A `resources` list and an `extent` both comma-join, because that is what
43
+ * `toSubmission` splits an `input` param on and what F14.2's `extent` widget
44
+ * produces.
45
+ */
46
+ export declare function flowValueToWire(value: NgisResolvedValue): string | null;
47
+ /**
48
+ * Flattens one node's satisfied in-port values: every spread's record contents,
49
+ * then the explicitly-bound ports written over them.
50
+ *
51
+ * F14.4: **later explicit keys win over spread keys**, which is why the spreads
52
+ * are laid down first. Both kinds of key live in the same resolution map, because
53
+ * `NgisFlowNode.inputs` holds both.
54
+ */
55
+ export declare function flattenFlowInputs(values: NgisFlowInputValues): NgisFlowInputValues;
56
+ /** The submission a flow-bound `RunButton` submits. */
57
+ export declare function submissionFromFlowInputs(schema: NgisToolUiSchema, values: NgisFlowInputValues): NgisRunSubmission;
58
+ /** `inputs` keys that name an in port, i.e. everything but a spread directive. */
59
+ export declare function flowInputNames(inputs: Readonly<Record<string, unknown>> | undefined): readonly string[];
60
+ /** `inputs` keys the tool's schema does not know — surfaced, never dropped. */
61
+ export declare function unknownFlowInputNames(schema: NgisToolUiSchema | null, names: readonly string[]): readonly string[];