@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.
- package/LICENSE +13 -0
- package/README.md +25 -0
- package/dist/index.cjs +71 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.mjs +69 -0
- package/dist/src/api/analysis.d.ts +140 -0
- package/dist/src/api/resources.d.ts +530 -0
- package/dist/src/api/scenes.d.ts +251 -0
- package/dist/src/api/users.d.ts +22 -0
- package/dist/src/api/workflows.d.ts +191 -0
- package/dist/src/components/plugin-ui/AttributeTable.d.ts +26 -0
- package/dist/src/components/plugin-ui/BatchTable.d.ts +47 -0
- package/dist/src/components/plugin-ui/ChartCanvas.d.ts +14 -0
- package/dist/src/components/plugin-ui/ExtentPicker.d.ts +22 -0
- package/dist/src/components/plugin-ui/FieldSelect.d.ts +23 -0
- package/dist/src/components/plugin-ui/Flow.d.ts +256 -0
- package/dist/src/components/plugin-ui/ModelSelect.d.ts +36 -0
- package/dist/src/components/plugin-ui/ParamForm.d.ts +63 -0
- package/dist/src/components/plugin-ui/PickerField.d.ts +52 -0
- package/dist/src/components/plugin-ui/ResourceSelect.d.ts +37 -0
- package/dist/src/components/plugin-ui/ResultActions.d.ts +48 -0
- package/dist/src/components/plugin-ui/RunButton.d.ts +49 -0
- package/dist/src/components/plugin-ui/StatChart.d.ts +66 -0
- package/dist/src/components/plugin-ui/TaskChrome.d.ts +35 -0
- package/dist/src/components/plugin-ui/TaskList.d.ts +29 -0
- package/dist/src/components/plugin-ui/TaskStatus.d.ts +55 -0
- package/dist/src/components/plugin-ui/batch-model.d.ts +442 -0
- package/dist/src/components/plugin-ui/flow-inputs.d.ts +61 -0
- package/dist/src/components/plugin-ui/flow-model.d.ts +303 -0
- package/dist/src/components/plugin-ui/flow-ports.d.ts +155 -0
- package/dist/src/components/plugin-ui/param-form-data.d.ts +122 -0
- package/dist/src/components/plugin-ui/param-form-model.d.ts +187 -0
- package/dist/src/components/plugin-ui/param-widgets.d.ts +88 -0
- package/dist/src/components/plugin-ui/picker-data.d.ts +141 -0
- package/dist/src/components/plugin-ui/picker-model.d.ts +150 -0
- package/dist/src/components/plugin-ui/recipe-model.d.ts +320 -0
- package/dist/src/components/plugin-ui/result-data.d.ts +112 -0
- package/dist/src/components/plugin-ui/result-model.d.ts +96 -0
- package/dist/src/components/plugin-ui/run-data.d.ts +118 -0
- package/dist/src/components/plugin-ui/run-model.d.ts +179 -0
- package/dist/src/components/plugin-ui/stat-chart-model.d.ts +168 -0
- package/dist/src/components/plugin-ui/validation-messages.d.ts +18 -0
- package/dist/src/components/plugin-ui/w2-contracts.d.ts +151 -0
- package/dist/src/components/plugin-ui/w3-contracts.d.ts +328 -0
- package/dist/src/components/plugin-ui/w4-contracts.d.ts +510 -0
- package/dist/src/components/ui/button.d.ts +12 -0
- package/dist/src/components/ui/checkbox.d.ts +4 -0
- package/dist/src/components/ui/column-resize-handle.d.ts +23 -0
- package/dist/src/components/ui/dropdown-menu.d.ts +25 -0
- package/dist/src/components/ui/input.d.ts +3 -0
- package/dist/src/components/ui/label.d.ts +4 -0
- package/dist/src/components/ui/popover.d.ts +10 -0
- package/dist/src/components/ui/select.d.ts +15 -0
- package/dist/src/components/ui/switch.d.ts +6 -0
- package/dist/src/domain/map/types.d.ts +128 -0
- package/dist/src/features/gis/components/GisAttributeTable.d.ts +56 -0
- package/dist/src/features/gis/hooks/useDatasetFeatureWindow.d.ts +51 -0
- package/dist/src/lib/api-error.d.ts +81 -0
- package/dist/src/lib/api.d.ts +82 -0
- package/dist/src/lib/auth-session.d.ts +22 -0
- package/dist/src/lib/hooks/useColumnResize.d.ts +57 -0
- package/dist/src/lib/raster-color-layer/RasterColorLayer.d.ts +48 -0
- package/dist/src/lib/raster-color-layer/TileGrid.d.ts +31 -0
- package/dist/src/lib/raster-color-layer/colorRamp.d.ts +18 -0
- package/dist/src/lib/raster-color-layer/shaders/raster-color.frag.d.ts +2 -0
- package/dist/src/lib/raster-color-layer/shaders/raster-color.vert.d.ts +2 -0
- package/dist/src/lib/raster-color-layer/zoomInterpolate.d.ts +2 -0
- package/dist/src/lib/utils.d.ts +2 -0
- package/dist/src/sdk/facets/types.d.ts +370 -0
- package/dist/src/sdk/host-api.d.ts +256 -0
- package/dist/src/sdk/map-api.d.ts +288 -0
- package/dist/src/sdk/panels.d.ts +130 -0
- package/dist/src/types/analysis.d.ts +205 -0
- package/dist/src/types/common.d.ts +17 -0
- package/dist/src/types/extensions.d.ts +560 -0
- package/dist/src/types/gis.d.ts +242 -0
- package/dist/src/types/market-social.d.ts +378 -0
- package/dist/src/types/workflow.d.ts +83 -0
- package/package.json +59 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<ParamForm>`'s pure half (Stage 14 Y3 — **F14.9**, F14.8, F14.2).
|
|
3
|
+
*
|
|
4
|
+
* Nothing here imports React, a store or an API client. That is the same rule
|
|
5
|
+
* Y2's `picker-model.ts` keeps, and it matters more here: F14.9 freezes a
|
|
6
|
+
* **four-phase lifecycle** whose hardest requirement — *a repopulate never
|
|
7
|
+
* overwrites a field whose `altered` is `true`* — is a rule about state
|
|
8
|
+
* transitions, and a rule spread across `useEffect` bodies cannot be asserted
|
|
9
|
+
* without a DOM. So every phase is a total function from the UI schema plus the
|
|
10
|
+
* current state to the next state, and `ParamForm.tsx` only renders the result.
|
|
11
|
+
*
|
|
12
|
+
* The four phase names are `w2-contracts.ts`'s `NgisParamFormPhase`, verbatim,
|
|
13
|
+
* for the reason the kickoff froze them: they are ArcGIS's (design-v2 App. E),
|
|
14
|
+
* not invented here, and a fifth phase would be a contract change.
|
|
15
|
+
*
|
|
16
|
+
* ## What each phase is responsible for
|
|
17
|
+
*
|
|
18
|
+
* | phase | function | rule it carries |
|
|
19
|
+
* |---|---|---|
|
|
20
|
+
* | `initialize` | {@link initializeParamForm} | seed from `default_value`; `altered: false`, `hasBeenValidated: false` |
|
|
21
|
+
* | `mutate` | {@link mutateParamForm} | `depends_on` visibility, then repopulation — **never clobbering `altered`** |
|
|
22
|
+
* | `validate-client` | {@link validateParamFormClient} | `required`, `value_type`, `choices`, `minimum`/`maximum` — errors block submit |
|
|
23
|
+
* | `validate-server` | `param-form-data.ts` | `host.models.validate`, debounced 400 ms |
|
|
24
|
+
*
|
|
25
|
+
* `mutate` runs **before** validation, always. Validating first would report a
|
|
26
|
+
* `required` error on a field the very next repopulate is about to hide.
|
|
27
|
+
*
|
|
28
|
+
* ## Hidden is not disabled, and a hidden field does not submit
|
|
29
|
+
*
|
|
30
|
+
* F14.10 forbids a `disabled` prop anywhere in plugin-ui, and F14.9's
|
|
31
|
+
* `depends_on` is *visibility*. A field the schema says is not applicable is
|
|
32
|
+
* therefore absent from client validation and absent from the submission — not
|
|
33
|
+
* present-and-empty. `NgisFieldState.visible` is the flag; nothing here ever
|
|
34
|
+
* produces a `disabled`.
|
|
35
|
+
*/
|
|
36
|
+
import type { NgisToolUiParam, NgisToolUiSchema } from "../../types/analysis";
|
|
37
|
+
import { type NgisFieldState, type NgisParamValue, type NgisParamValues, type NgisRunSubmission } from "./w2-contracts";
|
|
38
|
+
/**
|
|
39
|
+
* A schema-shaped defect the form found in its own inputs — an unresolvable
|
|
40
|
+
* `depends_on`, a dependency cycle, an override naming a param that does not
|
|
41
|
+
* exist. **Surfaced, never masked** (the `ExtensionSettingsForm` rule): the
|
|
42
|
+
* form still renders, and the reason is rendered beside it.
|
|
43
|
+
*/
|
|
44
|
+
export interface NgisParamFormDefect {
|
|
45
|
+
readonly kind: "unknown-dependency" | "dependency-cycle" | "unknown-hide" | "unknown-widget-override";
|
|
46
|
+
/** The param the defect is attached to, or the offending override key. */
|
|
47
|
+
readonly subject: string;
|
|
48
|
+
/** The other end of the relation, when there is one. */
|
|
49
|
+
readonly detail: string | null;
|
|
50
|
+
}
|
|
51
|
+
export interface NgisParamFormState {
|
|
52
|
+
/** Keyed by `NgisToolUiParam.name`. Every param of the schema is present. */
|
|
53
|
+
readonly fields: Readonly<Record<string, NgisFieldState>>;
|
|
54
|
+
/** The last phase that ran. Diagnostic; the form never branches on it. */
|
|
55
|
+
readonly phase: "initialize" | "mutate" | "validate-client";
|
|
56
|
+
/**
|
|
57
|
+
* Values kept because their field is `altered` even though the current option
|
|
58
|
+
* list no longer offers them (F14.9). Keyed by param name. Rendered as a
|
|
59
|
+
* notice; never a reason to clear the value.
|
|
60
|
+
*/
|
|
61
|
+
readonly stale: Readonly<Record<string, string>>;
|
|
62
|
+
readonly defects: readonly NgisParamFormDefect[];
|
|
63
|
+
}
|
|
64
|
+
/** An author's per-param overrides. Unknown keys **survive and are surfaced**. */
|
|
65
|
+
export interface NgisParamFormOverrides {
|
|
66
|
+
/** Param names the author renders elsewhere (already bound by a flow port). */
|
|
67
|
+
readonly hide?: readonly string[];
|
|
68
|
+
/** Param name → widget key. Selects `textarea`/`extent`/`field-select`. */
|
|
69
|
+
readonly widgets?: Readonly<Record<string, NgisToolUiParam["widget"]>>;
|
|
70
|
+
}
|
|
71
|
+
export interface NgisParamFormInit extends NgisParamFormOverrides {
|
|
72
|
+
/**
|
|
73
|
+
* Wire-shaped seed values (F14.8's preset `params`, or a saved recipe's
|
|
74
|
+
* bindings). Applied over `default_value`, and coerced through
|
|
75
|
+
* `fromWireValue` so a form value and the value the server will see cannot
|
|
76
|
+
* disagree.
|
|
77
|
+
*/
|
|
78
|
+
readonly seed?: Readonly<Record<string, string>>;
|
|
79
|
+
/** Option lists a widget resolves at runtime — `field-select`'s field names. */
|
|
80
|
+
readonly optionLists?: Readonly<Record<string, readonly string[]>>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The spelling a `depends_on.equals[]` entry is compared against, and the one
|
|
84
|
+
* `toWireParams` will send. **A boolean parent is compared as its wire
|
|
85
|
+
* spelling** (`"true"`), which is why the authored probe pins
|
|
86
|
+
* `REFINE_PASSES.depends_on[0].equals === ["true"]` rather than a JSON `true`.
|
|
87
|
+
*/
|
|
88
|
+
export declare function wireSpelling(value: NgisParamValue): string;
|
|
89
|
+
/**
|
|
90
|
+
* **initialize** (F14.9). Every field seeded from `default_value` — or from a
|
|
91
|
+
* preset/recipe seed — with `altered: false` and `hasBeenValidated: false`.
|
|
92
|
+
*
|
|
93
|
+
* `altered` stays `false` even for a seeded field, because F14.9's text is
|
|
94
|
+
* explicit and `altered` means *the user edited this*. The consequence is real
|
|
95
|
+
* and deliberate: a preset value in a field whose option list repopulates can
|
|
96
|
+
* be dropped by `mutate`, exactly as a `default_value` can. A launch that must
|
|
97
|
+
* not lose a preset value hides that param instead (`hide`), which is what
|
|
98
|
+
* F14.22's `hide={["ELEV"]}` is for.
|
|
99
|
+
*
|
|
100
|
+
* `mutate` is run immediately, so the state this returns already has correct
|
|
101
|
+
* visibility — a form is never rendered with a field the schema says is not
|
|
102
|
+
* applicable.
|
|
103
|
+
*/
|
|
104
|
+
export declare function initializeParamForm(schema: NgisToolUiSchema, init?: NgisParamFormInit): NgisParamFormState;
|
|
105
|
+
/**
|
|
106
|
+
* **mutate** (F14.9). Runs after every interaction and **before** validation.
|
|
107
|
+
*
|
|
108
|
+
* Two steps, in this order:
|
|
109
|
+
*
|
|
110
|
+
* 1. **Visibility** from `depends_on` — see {@link resolveVisibility}.
|
|
111
|
+
* 2. **Repopulation.** A value the current option list no longer offers is
|
|
112
|
+
* dropped **only when the field is not `altered`**; an altered value is kept
|
|
113
|
+
* and reported in `stale` so the form can say so. That is F14.9's one hard
|
|
114
|
+
* rule, and it is the same decision Y2's `reconcileFieldValue` makes for
|
|
115
|
+
* `FieldSelect` — stated once, here, for every widget with a list.
|
|
116
|
+
*
|
|
117
|
+
* A multi-valued field (`multiple`) is repopulated **per member**: the members
|
|
118
|
+
* the new list still offers survive, and the ones it does not are dropped from
|
|
119
|
+
* an unaltered field or kept-and-reported on an altered one. Dropping the whole
|
|
120
|
+
* selection because one member went away would be a clobber by another name.
|
|
121
|
+
*/
|
|
122
|
+
export declare function mutateParamForm(schema: NgisToolUiSchema, state: NgisParamFormState, optionLists?: Readonly<Record<string, readonly string[]>>): NgisParamFormState;
|
|
123
|
+
/** Record the user's edit. Sets `altered`, which `mutate` must then respect. */
|
|
124
|
+
export declare function setParamValue(schema: NgisToolUiSchema, state: NgisParamFormState, name: string, value: NgisParamValue, optionLists?: Readonly<Record<string, readonly string[]>>): NgisParamFormState;
|
|
125
|
+
/**
|
|
126
|
+
* The client-side rules, and **only** the rules F14.9 names: `required`,
|
|
127
|
+
* `value_type`, `choices` membership, `minimum`/`maximum`. Every one of them is
|
|
128
|
+
* read off the UI schema; none is inferred, and none duplicates a server rule
|
|
129
|
+
* the server is authoritative for (that is `validate-server`).
|
|
130
|
+
*
|
|
131
|
+
* A message is a **key under `GIS.pluginUi.form`** plus its placeholders,
|
|
132
|
+
* resolved by the component — not a sentence. Keeping the copy out of here is
|
|
133
|
+
* what lets this run in a node test with no `next-intl` provider.
|
|
134
|
+
*/
|
|
135
|
+
export interface NgisParamFormError {
|
|
136
|
+
readonly param: string;
|
|
137
|
+
readonly rule: "required" | "value-type" | "choices" | "minimum" | "maximum";
|
|
138
|
+
readonly bound: number | null;
|
|
139
|
+
}
|
|
140
|
+
/** Hidden fields are skipped: either `depends_on` or the caller's `hide` override. */
|
|
141
|
+
export declare function validateParamFormClient(schema: NgisToolUiSchema, state: NgisParamFormState, hidden?: readonly string[]): readonly NgisParamFormError[];
|
|
142
|
+
/** Fold client errors back onto the fields, marking them `hasBeenValidated`. */
|
|
143
|
+
export declare function applyClientErrors(state: NgisParamFormState, errors: readonly NgisParamFormError[], render: (error: NgisParamFormError) => string): NgisParamFormState;
|
|
144
|
+
export declare function valuesOf(state: NgisParamFormState): NgisParamValues;
|
|
145
|
+
/**
|
|
146
|
+
* The Y3 → Y4 data contract (`NgisRunSubmission`), split by **role** exactly as
|
|
147
|
+
* `validate-execution` takes it: `params` is option-role only, `bindings` is
|
|
148
|
+
* input-role resource ports, `outputNames` is the `output-name` widgets.
|
|
149
|
+
* Merging them here would force Y4 to re-split with a second copy of the role
|
|
150
|
+
* rules — the class of duplication this stage exists to remove.
|
|
151
|
+
*
|
|
152
|
+
* A hidden or empty field contributes nothing. `multiple` inputs are split on
|
|
153
|
+
* `,`, which is the spelling F14.2 fixes for a comma-joined file-id list.
|
|
154
|
+
*/
|
|
155
|
+
export declare function toSubmission(schema: NgisToolUiSchema, state: NgisParamFormState, hidden?: readonly string[]): NgisRunSubmission;
|
|
156
|
+
/**
|
|
157
|
+
* The params the visible fields would submit, in the wire shape
|
|
158
|
+
* `validate-execution` and the task API both take. Y3's pre-flight and Y4's
|
|
159
|
+
* submit go through `toWireParams` — this only chooses *which* keys.
|
|
160
|
+
*/
|
|
161
|
+
export declare function visibleParamNames(schema: NgisToolUiSchema, state: NgisParamFormState): readonly string[];
|
|
162
|
+
/**
|
|
163
|
+
* F14.8's launch resolution. **A `$context:` reference resolving to `null`,
|
|
164
|
+
* `undefined` or `""` refuses the launch, naming the key** — it is never
|
|
165
|
+
* submitted as an empty string, because an empty string is a value the server
|
|
166
|
+
* would accept and act on.
|
|
167
|
+
*
|
|
168
|
+
* `$$` escapes a literal `$` (`parsePresetValue`, frozen at the kickoff so the
|
|
169
|
+
* rail launcher and a recipe reader parse alike).
|
|
170
|
+
*
|
|
171
|
+
* Keys are visited in **sorted order** so that a stanza with two unresolvable
|
|
172
|
+
* references always names the same one. A refusal message that changed between
|
|
173
|
+
* runs would be untriageable.
|
|
174
|
+
*/
|
|
175
|
+
export type NgisPresetResolution = {
|
|
176
|
+
readonly kind: "resolved";
|
|
177
|
+
readonly params: Readonly<Record<string, string>>;
|
|
178
|
+
} | {
|
|
179
|
+
readonly kind: "refused";
|
|
180
|
+
/** The context key that resolved to nothing. */
|
|
181
|
+
readonly key: string;
|
|
182
|
+
/** The preset param that referenced it. */
|
|
183
|
+
readonly param: string;
|
|
184
|
+
};
|
|
185
|
+
/** What a context read can return — F13.2's `NgisContextValue` shape, widened. */
|
|
186
|
+
export type NgisPresetContextValue = string | number | boolean | null | readonly (string | number)[] | undefined;
|
|
187
|
+
export declare function resolvePresetParams(params: Readonly<Record<string, string>>, read: (key: string) => NgisPresetContextValue): NgisPresetResolution;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The widget registry (Stage 14 Y3 — **F14.2 / F14.9 / YD35**).
|
|
3
|
+
*
|
|
4
|
+
* **Total over `NgisWidgetKey`, with no fallback widget.** The type is
|
|
5
|
+
* `NgisWidgetRegistry<NgisParamWidget>` from `w2-contracts.ts`, i.e.
|
|
6
|
+
* `{ readonly [K in NgisWidgetKey]: T }` — so a key F14.2 grows and this file
|
|
7
|
+
* does not cover is a **compile** error, not a runtime `undefined` that renders
|
|
8
|
+
* nothing. That is the whole reason the registry is not a `Partial` plus a
|
|
9
|
+
* default text input: a silently-degraded control is indistinguishable from a
|
|
10
|
+
* control that works, and F14.2 says an unknown widget is a render-time error
|
|
11
|
+
* surfaced in place.
|
|
12
|
+
*
|
|
13
|
+
* YB1 emits only seven of the twelve keys in v1 (`field-select`, `extent`,
|
|
14
|
+
* `textarea`, `multi-select` and `resource-multi` are never emitted — `V-45`
|
|
15
|
+
* and `src/types/analysis.ts`'s own note). The other five are reachable through
|
|
16
|
+
* an author's `widgets` override and a recipe's promoted inputs, and they are
|
|
17
|
+
* exercised by `src/sdk/__fixtures__/ui-schema/authored/w2-dependency-probe.json`.
|
|
18
|
+
*
|
|
19
|
+
* ## Four of the twelve are Y2's pickers, not new controls
|
|
20
|
+
*
|
|
21
|
+
* `resource-select`, `resource-multi`, `field-select` and `extent` delegate to
|
|
22
|
+
* `ResourceSelect` / `FieldSelect` / `ExtentPicker`. Rebuilding those controls
|
|
23
|
+
* would give the form a second, subtly different notion of type widening, of
|
|
24
|
+
* field repopulation and of the two extent sources. They are rendered with
|
|
25
|
+
* **no `label`**, because the form's own field chrome carries the label — the
|
|
26
|
+
* picker's `PickerField` then contributes only its notice slot, which is where
|
|
27
|
+
* F14.1's widening and F14.9's kept-but-absent field surface.
|
|
28
|
+
*
|
|
29
|
+
* ## No `disabled`, anywhere
|
|
30
|
+
*
|
|
31
|
+
* F14.10: enablement is derived from port satisfaction and nothing else, and no
|
|
32
|
+
* plugin-ui component accepts a `disabled` prop. A widget with nothing to offer
|
|
33
|
+
* renders the reason instead of a dead control.
|
|
34
|
+
*/
|
|
35
|
+
import type { ReactNode } from "react";
|
|
36
|
+
import type { NgisHostAPI } from "../../sdk/host-api";
|
|
37
|
+
import type { NgisBounds } from "../../sdk/map-api";
|
|
38
|
+
import type { NgisToolUiParam, NgisToolUiSchema } from "../../types/analysis";
|
|
39
|
+
import type { NgisFieldState, NgisParamValue, NgisParamValues, NgisWidgetRegistry } from "./w2-contracts";
|
|
40
|
+
/** Already-translated host copy a widget may render. Keys are `GIS.pluginUi.form`. */
|
|
41
|
+
export interface NgisParamWidgetLabels {
|
|
42
|
+
/** A `select` / `multi-select` whose schema carries no `choices`. */
|
|
43
|
+
noChoices: string;
|
|
44
|
+
/** Suffix hint on an `output-name` field. Receives `output_extension`. */
|
|
45
|
+
outputExtension: (extension: string) => string;
|
|
46
|
+
/** Clear control on a single-value list. */
|
|
47
|
+
clear: string;
|
|
48
|
+
/** Placeholder on a closed list. */
|
|
49
|
+
placeholder: string;
|
|
50
|
+
}
|
|
51
|
+
export interface NgisParamWidgetProps {
|
|
52
|
+
/** The 0.4 facade — always the one `createGisPluginHostFactory` minted. */
|
|
53
|
+
host: NgisHostAPI;
|
|
54
|
+
/** The whole schema: `field-select` needs to resolve its parent param. */
|
|
55
|
+
schema: NgisToolUiSchema;
|
|
56
|
+
param: NgisToolUiParam;
|
|
57
|
+
field: NgisFieldState;
|
|
58
|
+
/**
|
|
59
|
+
* Every field's current value. Only `field-select` reads it — it follows a
|
|
60
|
+
* *sibling* param's value (QGIS's `parentLayerParameterName`) — but it is on
|
|
61
|
+
* all twelve props rather than smuggled in through a module-level slot,
|
|
62
|
+
* because a widget is rendered by React later than the form's render pass and
|
|
63
|
+
* anything ambient would be stale by then.
|
|
64
|
+
*/
|
|
65
|
+
values: NgisParamValues;
|
|
66
|
+
/** `<label for>` target. Seeded from the form's `id` plus the param name. */
|
|
67
|
+
controlId: string;
|
|
68
|
+
/** Class for portalled `<Select>` content — Radix lands on `document.body`. */
|
|
69
|
+
contentClassName?: string;
|
|
70
|
+
/** Exact layer selected from a duplicate-named resource choice, if any. */
|
|
71
|
+
onSameNamedLayerSelect?: (layerId: string) => void;
|
|
72
|
+
/** Records the edit. Sets `altered`, which F14.9's *mutate* must respect. */
|
|
73
|
+
onChange: (value: NgisParamValue) => void;
|
|
74
|
+
labels: NgisParamWidgetLabels;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A widget is a React component, so it may hold hooks — `ResourceSelect` and
|
|
78
|
+
* `FieldSelect` do. The registry stores components and `ParamForm` renders them
|
|
79
|
+
* as `<Widget …/>`; nothing calls one as a plain function.
|
|
80
|
+
*/
|
|
81
|
+
export type NgisParamWidget = (props: NgisParamWidgetProps) => ReactNode;
|
|
82
|
+
/** `[west, south, east, north]` round-tripped through the comma-joined wire form. */
|
|
83
|
+
export declare function parseBounds(value: NgisParamValue): NgisBounds | null;
|
|
84
|
+
/**
|
|
85
|
+
* **Total over `NgisWidgetKey`. There is no fallback entry, and adding one would
|
|
86
|
+
* be a contract change** (F14.2, YD35).
|
|
87
|
+
*/
|
|
88
|
+
export declare const NGIS_PARAM_WIDGETS: NgisWidgetRegistry<NgisParamWidget>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host reads behind the four W1 pickers (Stage 14 Y2).
|
|
3
|
+
*
|
|
4
|
+
* Every function here takes the 0.4 facade and returns plain data. Keeping them
|
|
5
|
+
* out of the components is what lets the wave's real exit criterion — "the
|
|
6
|
+
* pickers work **through `createGisPluginHostFactory`**" — be asserted offline:
|
|
7
|
+
* a node test builds the real, scope-enforced facade and calls these, so a
|
|
8
|
+
* scope refusal or a facet stub surfaces here exactly as it would in the
|
|
9
|
+
* browser. A facade assembled anywhere else is an ungated 0.4 surface every
|
|
10
|
+
* unit test calls green, and this stage has already hit that once.
|
|
11
|
+
*
|
|
12
|
+
* **`ModelSelect` reads `host.models.list`, not `host.models.search`.** F14.3
|
|
13
|
+
* adds the `search` leg and F14.24 ships it as a stub that *throws* until Y4
|
|
14
|
+
* implements it in W2 — deliberately, so a missing implementation cannot read
|
|
15
|
+
* as an empty result. `list` is the F13.2 surface that exists today, and its
|
|
16
|
+
* `query` filters client-side on name/description. The server-side
|
|
17
|
+
* `inputTypes`/`outputTypes` facets `search` will bring are therefore not
|
|
18
|
+
* expressible here; that is a W2 upgrade, not a W1 gap to paper over.
|
|
19
|
+
*/
|
|
20
|
+
import type { NgisHostAPI } from "../../sdk/host-api";
|
|
21
|
+
import type { NgisDataType, NgisModelSearchRequest, NgisResourceField, NgisResourceType } from "../../sdk/facets/types";
|
|
22
|
+
import type { NgisBounds } from "../../sdk/map-api";
|
|
23
|
+
import { type NgisFieldReconcileResult, type NgisPickerOption, type NgisTypeWidening } from "./picker-model";
|
|
24
|
+
export interface NgisResourceLoad {
|
|
25
|
+
options: readonly NgisPickerOption[];
|
|
26
|
+
/** F14.1 — rendered beneath the control, never swallowed. */
|
|
27
|
+
widenings: readonly NgisTypeWidening[];
|
|
28
|
+
/** Cached metadata could not be refreshed; retry is meaningful. */
|
|
29
|
+
unavailableCount: number;
|
|
30
|
+
/** The scene references a Dataset that no longer exists. */
|
|
31
|
+
missingCount: number;
|
|
32
|
+
}
|
|
33
|
+
export declare function loadResourceOptions(host: NgisHostAPI, types?: readonly NgisDataType[], options?: {
|
|
34
|
+
refresh?: boolean;
|
|
35
|
+
}): Promise<NgisResourceLoad>;
|
|
36
|
+
export interface NgisModelFilter {
|
|
37
|
+
provider?: string;
|
|
38
|
+
category?: string;
|
|
39
|
+
modelboxId?: string;
|
|
40
|
+
query?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function loadModelOptions(host: NgisHostAPI, filter?: NgisModelFilter): Promise<readonly NgisPickerOption[]>;
|
|
43
|
+
/**
|
|
44
|
+
* `host.models.search` — the F14.3 leg, wired in W2 and reached from
|
|
45
|
+
* `ModelSelect` from W4 (**YD54**, the upgrade YD46 deferred out of W3).
|
|
46
|
+
*
|
|
47
|
+
* **It is a second leg, not a replacement, and the reason is a capability `search`
|
|
48
|
+
* does not have.** `GET /api/analysis/tools/search` declares no `category` and no
|
|
49
|
+
* `modelbox_id` filter — only `modelbox_path` — so `NgisModelSearchRequest`
|
|
50
|
+
* (`facets/types.ts:241-250`) has no member for either, while
|
|
51
|
+
* `NgisModelsFacet.list`'s filter has both and `ModelSelect` takes both as props.
|
|
52
|
+
* Routing everything through `search` would therefore have silently dropped two
|
|
53
|
+
* filters, which is worse than a picker that cannot filter by data type. The
|
|
54
|
+
* component keeps `list` for the catalog-narrowing path and reaches this one for
|
|
55
|
+
* the facet path, and the two arms are **mutually exclusive by type** so no author
|
|
56
|
+
* can write the combination that would have to drop something.
|
|
57
|
+
*
|
|
58
|
+
* One more asymmetry, recorded because it is invisible: `search` is **capped**.
|
|
59
|
+
* `limit` defaults to 10 server-side and the server maximum is 50
|
|
60
|
+
* (`facets/types.ts:243-244`), so a search hit list is a ranked top-N and never the
|
|
61
|
+
* catalog. `list` is unpaged. A caller that wants "every tool" wants `list`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function loadModelSearchOptions(host: NgisHostAPI, request: NgisModelSearchRequest): Promise<readonly NgisPickerOption[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Why this is a union rather than an option list plus a boolean: each arm is a
|
|
66
|
+
* state the author has to be able to tell apart, and collapsing "no parent
|
|
67
|
+
* chosen" into "no fields" is the exact silent-empty-state failure the stage's
|
|
68
|
+
* stub rule exists to prevent.
|
|
69
|
+
*/
|
|
70
|
+
export type NgisFieldLoad =
|
|
71
|
+
/** No parent value bound yet. */
|
|
72
|
+
{
|
|
73
|
+
kind: "no-parent";
|
|
74
|
+
}
|
|
75
|
+
/** The parent's file id matches no resource in this scene. */
|
|
76
|
+
| {
|
|
77
|
+
kind: "unresolved";
|
|
78
|
+
fileId: string;
|
|
79
|
+
}
|
|
80
|
+
/** Resolved, but fields are vector-only (`NgisResourceDetail.fields`). */
|
|
81
|
+
| {
|
|
82
|
+
kind: "not-vector";
|
|
83
|
+
type: NgisResourceType;
|
|
84
|
+
} | {
|
|
85
|
+
kind: "ready";
|
|
86
|
+
options: readonly NgisPickerOption[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* `FieldSelect` follows a **resource port**, whose value is a *file* id
|
|
90
|
+
* (F14.5), while `host.resources.get` takes a *scene-resource* id. The join is
|
|
91
|
+
* `NgisResourceSummary.fileId`, so this resolves the parent through
|
|
92
|
+
* `resources.list()` first. Reported as `unresolved` rather than guessed: a
|
|
93
|
+
* file id that is not in the scene is a real state (the resource was removed),
|
|
94
|
+
* and treating it as "no fields" would hide it.
|
|
95
|
+
*/
|
|
96
|
+
export declare function loadFieldOptions(host: NgisHostAPI, parentFileId: string | null): Promise<NgisFieldLoad>;
|
|
97
|
+
/** The live state `FieldSelect` carries across a repopulate (F14.9). */
|
|
98
|
+
export interface NgisFieldSelection {
|
|
99
|
+
value: string | null;
|
|
100
|
+
/** `true` once the user has picked. Never reset by a repopulate. */
|
|
101
|
+
altered: boolean;
|
|
102
|
+
}
|
|
103
|
+
/** The fields a load actually produced; `[]` for every not-ready arm. */
|
|
104
|
+
export declare function fieldsOf(load: NgisFieldLoad): readonly NgisResourceField[];
|
|
105
|
+
/**
|
|
106
|
+
* **The whole of `FieldSelect`'s parent-change decision, in one function.**
|
|
107
|
+
*
|
|
108
|
+
* F14.9 asks for two things that pull against each other — repopulate on parent
|
|
109
|
+
* change, and never clobber a value the user altered — so the decision lives
|
|
110
|
+
* here rather than inside a `useEffect`: a rule spread across an effect body
|
|
111
|
+
* cannot be asserted without a DOM, and a rule that cannot be asserted is a rule
|
|
112
|
+
* that regresses. `FieldSelect` calls exactly this and renders the result, so
|
|
113
|
+
* the test and the component agree by construction rather than by resemblance.
|
|
114
|
+
*
|
|
115
|
+
* `load === null` means the new parent's fields are still in flight and
|
|
116
|
+
* **nothing is decided yet**: the value is passed through untouched. Reconciling
|
|
117
|
+
* against an empty list mid-load would clear an unaltered selection and then
|
|
118
|
+
* restore nothing, which reads as a flicker and is indistinguishable from a
|
|
119
|
+
* parent that genuinely has no fields.
|
|
120
|
+
*/
|
|
121
|
+
export declare function reconcileFieldLoad(load: NgisFieldLoad | null, selection: NgisFieldSelection): NgisFieldReconcileResult;
|
|
122
|
+
export type NgisExtentMode = "draw" | "viewport";
|
|
123
|
+
/**
|
|
124
|
+
* Both modes ride the **ungated** 0.3 surface (F14.18), so neither needs a
|
|
125
|
+
* scope and neither can be refused by consent.
|
|
126
|
+
*
|
|
127
|
+
* `draw` is `host.api.draw.snapshot()`. It returned `[]` in every shipping host
|
|
128
|
+
* until this session widened `GisMapHandle` with `getDrawSnapshot()` — the
|
|
129
|
+
* producer (`DrawController`) and the SDK-side delegation (`map-api.ts`) both
|
|
130
|
+
* already existed; only the composed handle never surfaced it.
|
|
131
|
+
*
|
|
132
|
+
* `viewport` is `host.api.getMap()?.getBounds()`. **Not `camera.getView()`** —
|
|
133
|
+
* that returns `{ center, zoom, pitch, bearing }` and no extent can be derived
|
|
134
|
+
* from it without the viewport size the facade does not expose.
|
|
135
|
+
*
|
|
136
|
+
* `null` means "no extent available right now" and the caller must say which of
|
|
137
|
+
* the two reasons applies; it is never rendered as an empty bbox.
|
|
138
|
+
*/
|
|
139
|
+
export declare function readExtent(host: NgisHostAPI, mode: NgisExtentMode): NgisBounds | null;
|
|
140
|
+
/** Whether a raw map is bound at all — the two `null`s of {@link readExtent}. */
|
|
141
|
+
export declare function hasBoundMap(host: NgisHostAPI): boolean;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pure projections behind the four W1 pickers (Stage 14 Y2 — F14.1, F14.18).
|
|
3
|
+
*
|
|
4
|
+
* Nothing here imports React, a store or an API client: every function is a
|
|
5
|
+
* total mapping from data the host already has to data a picker renders. That
|
|
6
|
+
* is what keeps the components **host-renderable from declarative data** — the
|
|
7
|
+
* property Stage 15's worker tier depends on — and it is what makes the four
|
|
8
|
+
* behaviours that actually matter (type widening, field repopulation, the two
|
|
9
|
+
* extent sources) testable offline without a DOM.
|
|
10
|
+
*
|
|
11
|
+
* `src/components/` rather than `src/sdk/`: these read the SDK's frozen types
|
|
12
|
+
* but they are host UI, and `src/sdk/` is the module set `@ngis/plugin-sdk` is
|
|
13
|
+
* extracted from. `@ngis/plugin-ui` re-exports the components from here instead
|
|
14
|
+
* (F14.14 — "the components' runtime lives in the host bundle").
|
|
15
|
+
*/
|
|
16
|
+
import { type NgisDataType, type NgisModelSearchResult, type NgisModelSummary, type NgisResourceField, type NgisResourceSummary, type NgisResourceType } from "../../sdk/facets/types";
|
|
17
|
+
import type { NgisBounds } from "../../sdk/map-api";
|
|
18
|
+
/** One row of any of the four pickers. Data only — no node, no callback. */
|
|
19
|
+
export interface NgisPickerOption {
|
|
20
|
+
/**
|
|
21
|
+
* Stable UI identity. Resource-layer rows use a layer id here while keeping
|
|
22
|
+
* `value` as the file id a tool parameter requires.
|
|
23
|
+
*/
|
|
24
|
+
id?: string;
|
|
25
|
+
/** Concrete scene-layer identity, absent for the legacy resource fallback. */
|
|
26
|
+
sceneLayerId?: string;
|
|
27
|
+
/** The port value this row binds. */
|
|
28
|
+
value: string;
|
|
29
|
+
/** Display text. Never a message key: resource/tool/field names are data. */
|
|
30
|
+
label: string;
|
|
31
|
+
/** Secondary line (type, status, provider). `null` when there is nothing to add. */
|
|
32
|
+
hint: string | null;
|
|
33
|
+
/** Listed but not ready — greyed, still selectable, never hidden. */
|
|
34
|
+
muted: boolean;
|
|
35
|
+
/** A scene layer is currently hidden but remains a valid data input. */
|
|
36
|
+
hidden?: boolean;
|
|
37
|
+
/** Present only when another eligible layer has the same visible name. */
|
|
38
|
+
sameName?: boolean;
|
|
39
|
+
/** Group path, or a stable layer id when the layer has no group. */
|
|
40
|
+
disambiguation?: string;
|
|
41
|
+
}
|
|
42
|
+
/** One requested {@link NgisDataType} and the resource types it actually lists. */
|
|
43
|
+
export interface NgisTypeWidening {
|
|
44
|
+
requested: NgisDataType;
|
|
45
|
+
listed: readonly NgisResourceType[];
|
|
46
|
+
}
|
|
47
|
+
export interface NgisResourceTypeFilter {
|
|
48
|
+
/** What `host.resources.list({ types })` is asked for; `null` means no filter. */
|
|
49
|
+
resourceTypes: readonly NgisResourceType[] | null;
|
|
50
|
+
/** Empty when every requested type resolves to itself. */
|
|
51
|
+
widenings: readonly NgisTypeWidening[];
|
|
52
|
+
}
|
|
53
|
+
export declare function widenDataTypes(types?: readonly NgisDataType[]): NgisResourceTypeFilter;
|
|
54
|
+
/**
|
|
55
|
+
* **The value is the file id, not the scene-resource id** (F14.2's
|
|
56
|
+
* `resource-select`, F14.5's `resource` port kind): every dataset API and every
|
|
57
|
+
* tool binding takes `effectiveFileId`. `NgisResourceSummary` carries both, so
|
|
58
|
+
* this is a choice rather than a limitation, and it is the contract's choice.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resourceOptions(summaries: readonly NgisResourceSummary[]): NgisPickerOption[];
|
|
61
|
+
/**
|
|
62
|
+
* Project a file-typed resource input onto the scene layers a person actually
|
|
63
|
+
* recognises. The submitted value remains the resource's `effectiveFileId`;
|
|
64
|
+
* `id` is the layer identity used only by the picker UI. This intentionally
|
|
65
|
+
* keeps every layer when several render the same file.
|
|
66
|
+
*
|
|
67
|
+
* A source that predates the optional `summary.layers` projection falls back
|
|
68
|
+
* to the old resource row. A source that supplies `layers: []` has stated that
|
|
69
|
+
* the resource has no scene layer, so it is not selectable here.
|
|
70
|
+
*/
|
|
71
|
+
export declare function resourceLayerOptions(summaries: readonly NgisResourceSummary[]): NgisPickerOption[];
|
|
72
|
+
/** A disabled tool stays listed and greyed — never hidden (the XD12 posture). */
|
|
73
|
+
export declare function modelOptions(models: readonly NgisModelSummary[]): NgisPickerOption[];
|
|
74
|
+
/**
|
|
75
|
+
* `host.models.search`'s hits, as options (Stage 14 Y7 — **YD54**, the `ModelSelect`
|
|
76
|
+
* upgrade YD46 deferred out of W3).
|
|
77
|
+
*
|
|
78
|
+
* **Two things `search` cannot tell us that `list` can, stated where they are
|
|
79
|
+
* lost.** `NgisModelSearchResult` (`src/sdk/facets/types.ts:253-277`) is an
|
|
80
|
+
* allowlist projection of `ToolSearchResult` and carries **no `enabled` flag** and
|
|
81
|
+
* **no `category`** — so on this path:
|
|
82
|
+
*
|
|
83
|
+
* - **`muted` is always `false`.** XD12's posture ("a disabled tool is listed
|
|
84
|
+
* and greyed, never hidden") cannot be honoured, because the search projection
|
|
85
|
+
* does not report enablement. Recovering it would mean one `models.get` per
|
|
86
|
+
* hit, which is the N+1 XD7 already refused for `resources.types`. Recorded as
|
|
87
|
+
* `V-287` rather than papered over with a guess.
|
|
88
|
+
* - **`hint` falls back to `modelboxPath`**, which `list` does not carry at all,
|
|
89
|
+
* so the two legs' hints differ in kind. That is honest: a search hit really is
|
|
90
|
+
* located by its modelbox path, and printing a `category` the projection never
|
|
91
|
+
* received would be an invention.
|
|
92
|
+
*
|
|
93
|
+
* Order is the server's — `search` ranks by `score` and the ranking *is* the
|
|
94
|
+
* answer, so re-sorting here would discard the only thing the facet added over
|
|
95
|
+
* `list`.
|
|
96
|
+
*/
|
|
97
|
+
export declare function modelSearchOptions(results: readonly NgisModelSearchResult[]): NgisPickerOption[];
|
|
98
|
+
export declare function fieldOptions(fields: readonly NgisResourceField[]): NgisPickerOption[];
|
|
99
|
+
export interface NgisFieldReconcileInput {
|
|
100
|
+
/** The repopulated field list for the *new* parent. */
|
|
101
|
+
fields: readonly NgisResourceField[];
|
|
102
|
+
value: string | null;
|
|
103
|
+
/** `true` once the user has picked. F14.9's `altered` flag. */
|
|
104
|
+
altered: boolean;
|
|
105
|
+
}
|
|
106
|
+
export interface NgisFieldReconcileResult {
|
|
107
|
+
value: string | null;
|
|
108
|
+
/**
|
|
109
|
+
* The altered value that survived a repopulate without being present in the
|
|
110
|
+
* new list. Non-`null` means "render the mismatch"; it is never a reason to
|
|
111
|
+
* clear the value.
|
|
112
|
+
*/
|
|
113
|
+
missing: string | null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* QGIS's `parentLayerParameterName` behaviour, plus F14.9's one hard rule: **a
|
|
117
|
+
* repopulate never overwrites a field whose `altered` is `true`.**
|
|
118
|
+
*
|
|
119
|
+
* So an altered value that the new parent does not carry is *kept and
|
|
120
|
+
* surfaced*, not silently cleared — the `ExtensionSettingsForm` rule ("refusals
|
|
121
|
+
* and approximations are surfaced, not masked"). Clearing it would look to the
|
|
122
|
+
* author like the host discarding their input; blocking on it is Y3's
|
|
123
|
+
* validation phase and Y5's enablement, not this component's call.
|
|
124
|
+
*
|
|
125
|
+
* A value the user never touched carries no such claim, so a repopulate clears
|
|
126
|
+
* it when the new parent cannot honour it.
|
|
127
|
+
*/
|
|
128
|
+
export declare function reconcileFieldValue(input: NgisFieldReconcileInput): NgisFieldReconcileResult;
|
|
129
|
+
/**
|
|
130
|
+
* `NgisBounds` = `[west, south, east, north]` over every position in a raw
|
|
131
|
+
* Terra Draw snapshot, or `null` when the snapshot holds no usable coordinate.
|
|
132
|
+
*
|
|
133
|
+
* The snapshot is typed `unknown[]` all the way from
|
|
134
|
+
* `host.api.draw.snapshot()`, so this walks the coordinate tree structurally
|
|
135
|
+
* rather than trusting a GeoJSON type — a draw session can hold any geometry
|
|
136
|
+
* kind and F14 does not restrict which.
|
|
137
|
+
*/
|
|
138
|
+
export declare function boundsOfDrawSnapshot(features: readonly unknown[]): NgisBounds | null;
|
|
139
|
+
/**
|
|
140
|
+
* A MapLibre `LngLatBounds` → `NgisBounds`.
|
|
141
|
+
*
|
|
142
|
+
* **CORRECTION carried from F14.18:** `camera.getView()` returns
|
|
143
|
+
* `{ center, zoom, pitch, bearing }`, **not** an extent, so viewport mode
|
|
144
|
+
* cannot be built from it. It needs the raw map's `getBounds()`, which the
|
|
145
|
+
* ungated `getMap()` already provides. Duck-typed so the projection stays
|
|
146
|
+
* testable without a GL context.
|
|
147
|
+
*/
|
|
148
|
+
export declare function boundsFromLngLatBounds(value: unknown): NgisBounds | null;
|
|
149
|
+
/** Six decimals ≈ 0.1 m — enough to read, short enough to fit the control. */
|
|
150
|
+
export declare function formatBounds(bounds: NgisBounds): string;
|