@aiquants/enrichment-react 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -48
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +27 -11
- package/dist/index.d.ts +27 -11
- package/dist/index.js +3 -3
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -6,13 +6,15 @@ React UI components for storage metadata AI enrichment: the ingest console, the
|
|
|
6
6
|
|
|
7
7
|
- Node.js >= 18.0.0
|
|
8
8
|
- React >= 19.0.0 and React DOM >= 19.0.0 (peer dependencies)
|
|
9
|
-
- `@aiquants/
|
|
10
|
-
- `@aiquants/
|
|
9
|
+
- `@aiquants/auth-core` >= 0.8.0 (peer dependency — `accessFailureKindOfStatus`, the one rule by which the package tells a 401 and a 403 from other failures, and the presenter type the root holds (`AccessFailurePresenter`); the host and the package share one copy of the module)
|
|
10
|
+
- `@aiquants/console-ui` >= 0.7.0 (peer dependency — the console root and its stylesheet, the root's presenter of access failures (`accessFailure`) with the parts that hand a failure to it (`FailureMessage`, `ResourceFailed`), the unmeasured label, `Measured` (every count drawn as a value, durations in ms included, and every value slot that was not measured in the components that write the root's figures), `RowButton`, the count rule (`formatCount`), the instant and text-width formats, and the contrast computation and its AAA bars come from it)
|
|
11
|
+
- `@aiquants/enrichment-core` >= 0.14.0 (peer dependency — every pipeline step, flow, gate, record shape, and search bound the components draw comes from it)
|
|
12
|
+
- `@aiquants/plugin-settings` >= 0.1.0 (peer dependency — the settings fields a step's descriptor declares (`SettingsFieldInput`), the options of a closed field and the names of its values (`PluginOptionsProvider`, `useOptionLabelOf` and the option batches, from `@aiquants/plugin-settings/react`), the words of a step's abilities (`abilityTermsOf`) and the labels of the name rule (`ruleOfIssue`) come from it)
|
|
11
13
|
|
|
12
14
|
## Installation
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
pnpm add @aiquants/enrichment-react @aiquants/enrichment-core @aiquants/console-ui
|
|
17
|
+
pnpm add @aiquants/enrichment-react @aiquants/enrichment-core @aiquants/console-ui @aiquants/plugin-settings @aiquants/auth-core
|
|
16
18
|
```
|
|
17
19
|
|
|
18
20
|
## Design Rules
|
|
@@ -32,12 +34,19 @@ pnpm add @aiquants/enrichment-react @aiquants/enrichment-core @aiquants/console-
|
|
|
32
34
|
The root must be `locale="ja"` and `formatLocale="ja-JP"`: the package's own text is Japanese and its instants are written in `ja-JP` (`RecordedInstant`), so under any other root the root's words and digit grouping would sit inside Japanese sentences beside `ja-JP` times. Every component that reads the root throws `RangeError`, naming the root's `locale` and `formatLocale`, before drawing anything under any other root.
|
|
33
35
|
|
|
34
36
|
```tsx
|
|
35
|
-
<ConsoleUiRoot locale="ja" formatLocale="ja-JP" timeZone={displayTimeZone} testId="console">
|
|
37
|
+
<ConsoleUiRoot locale="ja" formatLocale="ja-JP" timeZone={displayTimeZone} accessFailure={accessFailure} testId="console">
|
|
36
38
|
<InfrastructureHealthMonitor health={health} />
|
|
37
39
|
<QdrantStorageCard overview={qdrant} />
|
|
38
40
|
</ConsoleUiRoot>
|
|
39
41
|
```
|
|
40
42
|
|
|
43
|
+
`accessFailure` is the host's presenter of access failures (`AccessFailurePresenter<ReactNode>` of `@aiquants/auth-core`, required by the root; see the next rule and `@aiquants/console-ui`'s README under "Wrapping a console").
|
|
44
|
+
- **Access failures are the root's presenter's.** A 401 (`unauthenticated`) or a 403 (`forbidden`), as `accessFailureKindOfStatus` of `@aiquants/auth-core` reads the status, is never a failed sentence of this package: every component hands it to the root's presenter (`accessFailure`) through `@aiquants/console-ui`'s `FailureMessage` and `ResourceFailed`, and the package draws no title, sentence or action of its own for one: the notice is the presenter's, and a component passes it only what the operator may not do.
|
|
45
|
+
The presenter receives the occurrence's place and retry. The place is `read` for a read (a first read, a re-read, a later page, a check of the work, and the reads an operator presses — a binding trial, a version's structure, a step's whole input or output saved to a file) and `write` for a command.
|
|
46
|
+
The retry is the operation itself where the notice takes the place of the control that would redo it, or where no such control exists — a read's reload, a step's `もう一度読む`, a check's `もう一度確かめる`, an editor's read again after a publish — and `null` where the pressed control stays (a command, a pressed read); auth-core's view offers it after a 401 only.
|
|
47
|
+
For a 403 the presenter receives the component's denied sentence (each component's `…_REFUSAL` / `…_FORBIDDEN_SENTENCE`) followed by the cause the route declared. A first read's 401 or 403 replaces the content with the notice in place of the reload (`ResourceFailed`); a re-read's 403 withdraws the shown value as the first read's does (console-ui's `keepLastGood`), and a re-read's 401 keeps the value beside the presenter's notice, whose retry reads again (`RefreshFailureMessage`, the components' `…-refresh-failed`).
|
|
48
|
+
A later page answered 401 or 403 re-reads the list's first page, whose 403 withdraws the list and whose 401 keeps the rows beside that notice. When a notice whose retry held focus leaves (its read answered, or a new failure replaced the notice), focus moves to the target the reload's rescue names (`useFocusRescue`), never to `<body>`.
|
|
49
|
+
|
|
41
50
|
- **Unmeasured is not zero.** A figure the source could not measure renders as the root's unmeasured label (`未測定` under `locale="ja"`), never as `0`. In `InfrastructureHealthMonitor`, `PipelineFlowViewer`, `PipelineRunFlowViewer`, `DocumentHistoryInspector`, `QdrantStorageCard`, `SyncStatusMonitor` and `OntologyStatusCard`, every value slot that holds one is `@aiquants/console-ui`'s `Measured` (a count, or a formatted text with its `keep`), so `data-measured="false"` marks every unmeasured value slot there.
|
|
42
51
|
A run's step report in the history inspector is the one place an unmeasured figure has no slot of its own: a report field that was not measured is named in the step's `未測定:` line instead (see `DocumentHistoryInspector`), and only a page pair with one half measured keeps both `Measured` slots.
|
|
43
52
|
The other components keep their own words for a missing value: `DocumentIngestConsole` writes a missing revision as `N/A` (it reads the root for its instants and its byte format only), `MetadataSearchWorkbench` a document absent from one of the ranked lists as `ベクトルの列に無い` / `語句の列に無い` / `グラフの列に無い` and an empty column as `無し`.
|
|
@@ -161,25 +170,29 @@ Each row lays out as every `DescriptionList` row does (the term a third of the w
|
|
|
161
170
|
|
|
162
171
|
### 5. `MetadataSearchWorkbench`
|
|
163
172
|
|
|
164
|
-
The document search of the search tab (the public API's `GET /ai/search/documents`). Props: `tenantId`, `variantSets: readonly VariantSetView[]` (the tenant's variant sets, `VariantSetList.variant_sets`), `onSearch(params, signal)` and the optional `initialParams: Partial<DocumentSearchParams>`, which fills the query, the strategy, its controls, the variant set and the filters.
|
|
173
|
+
The document search of the search tab (the public API's `GET /ai/search/documents`). Props: `tenantId`, `variantSets: readonly VariantSetView[]` (the tenant's variant sets, `VariantSetList.variant_sets`), `onSearch(params, signal)` and the optional `initialParams: Partial<DocumentSearchParams>`, which fills the query, the strategy, its controls, the variant set, the rerank choice and the filters.
|
|
165
174
|
The host owns the route and the transport: `onSearch` answers a `DocumentSearchAnswer`, or rejects with an `Error` whose message the workbench shows as it is (`search-failure`, announced again when the same failure repeats and removed by the next answer), and it should stop when `signal` aborts.
|
|
166
175
|
|
|
167
176
|
- **Query card** (`search-query-card`, with `data-mode` and `data-running`): the query (`search-query`), the strategy (`search-mode`, a segmented control of the core's `SEARCH_MODES` worded by `SEARCH_MODE_LABELS`, `HYBRID` unless `initialParams` names another, its description in `search-mode-description`) and the page size (`search-limit`).
|
|
168
177
|
Only the controls the chosen strategy reads are drawn and sent: the similarity floor for `DENSE` (`search-threshold`, starting at the midpoint of its bounds, since no floor is the request's own default), the fusion (`search-fusion`, `rrf` or `linear` by `SEARCH_FUSION_LABELS`) and its `k` (`search-rrf-k`) for `HYBRID`, and the vector weight `α` (`search-alpha`) for a linear fusion. The numeric bounds and defaults come from `SEARCH_PARAM_LIMITS`.
|
|
169
178
|
Beside the fusion, `HYBRID` also draws who fuses the dense and sparse rankings and where (`search-dense-sparse-fusion`, the core's `DENSE_SPARSE_FUSIONS` worded by `DENSE_SPARSE_FUSION_LABELS`): `機関 (組の全体で融合・同点はチャンクの順)` (`engine`, the API's default `DEFAULT_DENSE_SPARSE_FUSION`, never sent) or `ストア (コレクションごとに融合・同点の順は要求ごと)` (`store`, sent as `dense_sparse_fusion`).
|
|
170
179
|
The engine merges each kind across the searched collections and fuses the two merged rankings once, deciding an exact tie by the chunk, so the same request always answers the same; the store fuses each collection's rankings itself, the collections are merged by rank, and exact ties fall anew on every request. The run trace names it on the fusion line (`融合: RRF (k=60) / 密と疎の融合: 機関 (組の全体で融合・同点はチャンクの順)`), the API's default when the search sent none.
|
|
171
|
-
For a strategy with a vector tier (`SPARSE`, `DENSE`, `HYBRID`; `
|
|
180
|
+
For a strategy with a vector tier (`SPARSE`, `DENSE`, `HYBRID`; the core's `modeReadsVectors`), the embedding variant set the vector tiers read (`search-variant`): `本番 (default)` first, then the active sets in key order, each named with its projected share (`variantSetOptionLabel`: `eg2-v1 (投影済み 70.0%)`, or `(対象の文書なし)` for a set whose rows count no document). Production is the API's default and is never sent; any other set travels as `variant_key`. A chosen set that leaves the active list reads as production again.
|
|
172
181
|
A set that holds less than every document says so in a note (`search-variant-partial`: `組 <key> はテナントの文書の 70.0% (7 / 10 件) を投影しています。…`), since a document it lacks cannot be found through its vector tiers. The run trace names the set (`変種の組: …`), and so does the results card's description (`· 組: …`).
|
|
182
|
+
The same strategies draw whether a cross-encoder reorders the vector tier's chunks (`search-rerank-choice`, `RERANK_CHOICES` worded by `RERANK_CHOICE_LABELS`): `既定 (テナントの設定)` (`default`, the tenant's default for the mode, never sent), `使う` (`on`, sent as `rerank: true`) or `使わない` (`off`, sent as `rerank: false`).
|
|
183
|
+
It starts at the default unless `initialParams.rerank` names one. A strategy without a vector tier draws no choice and sends no `rerank`, since the API refuses the key with it (`false` too); a choice made before moving there is sent again on coming back.
|
|
173
184
|
- **Filters** behind the `詳しい条件` disclosure (`search-filters`): the confidentiality level (`search-confidentiality`, `全ての区分` or one of the core's `FILTERABLE_CONFIDENTIALITY_LEVELS` worded by `CONFIDENTIALITY_LEVEL_LABELS`, so `RESTRICTED` is never offered), the department id (`search-department`), the MIME type (`search-mime-type`, a contains match) and the tag (`search-tag`, an exact match). A filter is sent only when given, trimmed.
|
|
174
185
|
- **Developer presets** behind the `開発者のプリセット` disclosure (`search-presets`): each of `SEARCH_PRESETS` (`search-preset-${id}-apply`) sets the strategy and the page size, and the floor, the fusion or who fuses the dense and sparse rankings only where the preset names them (`balanced-hybrid` names the engine); applying one is announced.
|
|
175
186
|
- **Checked before sending:** the query (1–500 characters after trimming), the department (empty, or a positive integer) and the text filters (at most 100 characters after trimming). Nothing is sent while a field is unacceptable, and each field says why only once a send has been attempted.
|
|
176
187
|
- **One search at a time:** the submit button (`search-submit`) is busy while a search runs and a second submit is not taken. A search the workbench leaves behind (unmounted) is aborted through its signal, and its late answer or failure is not drawn.
|
|
177
|
-
- **Results** (`search-results`, described `<n> 件 · <ms> ms · 品質: <quality>`): the run (`search-run`: a pill per tier, `search-tier-${tier}` with `data-ran
|
|
188
|
+
- **Results** (`search-results`, described `<n> 件 · <ms> ms · 品質: <quality>`): the run (`search-run`: a pill per tier, `search-tier-${tier}` with `data-ran`, then whether the cross-encoder reordered the answer, `search-rerank` with `data-ran` from `search_metadata.reranked`, `並べ直し した` or `並べ直し しなかった`; the answering worker's breakers `search-breakers` by `BREAKER_STATE_LABELS`; the row scope `search-row-scope`; the column scope with the names of the columns it hid, `search-column-scope`) and a master–detail (336 px master, 544 px detail minimum).
|
|
189
|
+
A reranked answer is noted between the two (`search-rerank-note`: `並びは並べ直しの値の順です。表のベクトルの値は層の値です。`): the rows stand in the reranker's order, while each vector value the detail shows is the tier's.
|
|
178
190
|
The master is the documents (`search-hits`, rows `search-hit-row` with `data-rank`): the rank and the title, and the fused value as a meter (`search-hit-${rank}-fused`). The first row is selected when an answer arrives, and the number found is announced.
|
|
179
191
|
The detail (`search-hit-detail`) shows the selected document's values (`search-hit-scores`: the fused value as a meter; the vector value by `vectorScoreText`, a cosine as a percentage of 1 and BM25 or a mixed value as a plain number; the lexical and graph rank values), its fields (`search-hit-fields`, the update time in the root's zone under `search-hit-mtime-value`, the tags as pills), its graph relations (`search-hit-relations`) and its structured data (`search-hit-structured`, a scrolling code block).
|
|
180
192
|
- **Scopes:** a column the caller's scope hides reads `HIDDEN_FIELD_TEXT` (`非表示 (列のスコープ)`), and a document's relations are withheld while a row scope applies (their targets have not passed the row check) or the column scope hides the body (a heading path is part of the body and an entity is named from it); the detail and the graph trace name whichever reason holds.
|
|
181
193
|
- **Degraded answers** draw `DegradedSearchBanner` (`search-degraded`) between the card and the results.
|
|
182
194
|
- **Developer inspector** behind the `開発者の点検` disclosure (`search-inspector`): a segmented control (`search-inspector-view`) of the request as sent, the response, the run trace and the graph trace, drawn in a code block (`search-inspector-code`). Before any search every view says `まだ検索していません。`; after one, the request view keeps what was sent even when the controls move.
|
|
195
|
+
The run trace's tier line ends with the rerank (`走った層: 語句 ✓ / 疎 ✓ / 密 – / グラフ – / 並べ直し ✓`, `–` for a tier that did not run and for an answer the cross-encoder did not reorder).
|
|
183
196
|
The copy button (`search-inspector-copy`) writes the shown view to the clipboard and announces it; a copy that fails says why (`search-inspector-copy-failure`).
|
|
184
197
|
|
|
185
198
|
A fused value outside [0, 1] (the meter's range) or a search time that is not a non-negative safe integer throws `RangeError` instead of being drawn.
|
|
@@ -227,7 +240,8 @@ The card (`pipeline-flow-viewer`, `data-flow-key`, `data-flow-version`) is title
|
|
|
227
240
|
- **Flow tabs**: the console's `PanelTabs` (named `流れ`, `pipeline-flow`, tabs `pipeline-flow-tab-<key>`, panel `pipeline-flow-panel`), one tab per flow of the catalogue, labelled by its `title.ja`: first the document flows that name document kinds, ordered by their first kind in the document-kind vocabulary's order (not the catalogue's), then the document flows that name none, then the child flows, both in catalogue order. `defaultFlowKeyOf(catalog)` names the leftmost tab.
|
|
228
241
|
The ARIA tabs pattern: only the selected tab is in the Tab order; ArrowLeft / ArrowRight (wrapping), Home and End move focus and select, and other keys do nothing; every tab is a 44 px target. Choosing a tab calls `onSelectFlow(flowKey)` and nothing else.
|
|
229
242
|
- **Version**: a `Select` named `版` (`pipeline-flow-version`) over the selected flow's `versions`, newest first, the current one written `版 <v> (今の版)`, drawn even for a flow with one version; choosing one calls `onSelectVersion(version)`, `null` for the current one. The panel names what it draws as `流れ: <title> (<key> 版 <v>)` (`flow-identity`).
|
|
230
|
-
`figure` (`FlowVersionFigure`) carries what the host holds for that choice: `{ kind: "current" }` draws the catalogue's nodes, `{ kind: "version", shape }` the shape the host read for an older version,
|
|
243
|
+
`figure` (`FlowVersionFigure`) carries what the host holds for that choice: `{ kind: "current" }` draws the catalogue's nodes, `{ kind: "version", shape }` the shape the host read for an older version,
|
|
244
|
+
and `{ kind: "version_unread", version, failure }` draws no figure and no hint and looks up no node, only why (`pipeline-flow-version-unread`): the root's presenter's notice of a read for `{ kind: "forbidden" }` (stating `この版の図を読む権限がありません。`) and for `{ kind: "unauthenticated" }` (an upstream that no longer accepts the reader's session, with `onReload` as the retry; focus on it moves to the card's heading when the notice leaves),
|
|
231
245
|
or `この版の図を読めませんでした (HTTP <status>)。` (an `AlertMessage`; without a status, no parentheses) for `{ kind: "unavailable", status }` (`FlowShapeReadFailure`, the shape of `@aiquants/enrichment-react-router`'s `PipelineFlowCatalogFailure`).
|
|
232
246
|
A `version` shape of another flow, and a `version` or `version_unread` figure naming the current version or a version the flow's `versions` does not list, throws `RangeError` (the host gives the current version as `{ kind: "current" }`).
|
|
233
247
|
- **Figure** (`flow-svg`, inside `flow-figure` with its hint): `@aiquants/console-ui`'s figure system, a `group` `Figure` (`role="group"` named `<flow title> 版 <v> の図`, so its node buttons stay in the accessibility tree) drawn at its natural size inside the figure's horizontal scroll frame (`flow-svg-frame`, which takes no Tab stop), under the visible hint `flow-scroll-hint`, which is read before the figure and describes the tab panel: `図は実寸 (幅 <width> px) で描きます。表示幅に収まらないときは横にスクロールしてください。節の間は Tab のほか、矢印の鍵 (→・←・↓・↑) と Home・End でも移れます (移った節が見える位置まで動きます)。`
|
|
@@ -265,7 +279,8 @@ The card (`pipeline-flow-viewer`, `data-flow-key`, `data-flow-version`) is title
|
|
|
265
279
|
The copy dialog (`CopyFlowDialog`, a modal `Dialog` titled `流れを写して作る`) is drawn only while open, and closes when the list stops being read or the right is withdrawn. It takes the new key's part after `custom.` and the two titles, and states on the spot a malformed key, a key the list holds and a blank or overlong title.
|
|
266
280
|
It writes the copy through `editorHost.writeFlowDraft(key, { expected_row_version: null, title, content: { kind: "copy", source } })`: a copy made is announced (`自前の流れ <key> を作りました。`) and its key handed to `onEditFlow`; a 412 (another copy took the key first) becomes the key field's error `この鍵は使われています。ほかの鍵にしてください。` and calls `onRereadCustomFlows()`. Without `canUpdate` the viewer offers neither operation.
|
|
267
281
|
|
|
268
|
-
The viewer is controlled, and every prop is required: `catalog`, `featureFlags`, `metrics` (matched by `flowKey`, `flowVersion` and `nodeId`), `metricSampleWindow` (the number of newest step records per flow version and node the host aggregated into each metric; a positive integer, otherwise `RangeError`), `selectedFlowKey` with `onSelectFlow(flowKey)`, `figure` with `onSelectVersion(version | null)
|
|
282
|
+
The viewer is controlled, and every prop is required: `catalog`, `featureFlags`, `metrics` (matched by `flowKey`, `flowVersion` and `nodeId`), `metricSampleWindow` (the number of newest step records per flow version and node the host aggregated into each metric; a positive integer, otherwise `RangeError`), `selectedFlowKey` with `onSelectFlow(flowKey)`, `figure` with `onSelectVersion(version | null)` and `onReload()` (the host's re-read of the shape a `version_unread` figure names, for example its loader's revalidation),
|
|
283
|
+
`selectedNodeId` (`string | null`) with `onSelectNode(nodeId | null)`, `onOpenFlow(flowKey, version | null)` (a child flow's link) and `headingRef`,
|
|
269
284
|
and the custom flows' `customFlows` (`CustomFlowsView`), `canUpdate` (the reader's `storage_admin:update` limited to neither rows nor columns), `onEditFlow(flowKey)` (the host moves to the edit view), `editorHost` (a `PipelineEditorHost`; the viewer calls its `writeFlowDraft` alone) and `onRereadCustomFlows()`.
|
|
270
285
|
A `selectedFlowKey` the catalogue does not hold throws `RangeError` naming the keys in tab order. A host that could not read the catalogue states why under the viewer's title (`PIPELINE_FLOW_TITLE`, `取り込みパイプライン`) instead of drawing it.
|
|
271
286
|
|
|
@@ -273,7 +288,7 @@ A `selectedFlowKey` the catalogue does not hold throws `RangeError` naming the k
|
|
|
273
288
|
<PipelineFlowViewer
|
|
274
289
|
catalog={flowCatalog} featureFlags={flags} metrics={stepMetrics} metricSampleWindow={stepMetricWindow}
|
|
275
290
|
selectedFlowKey={flowKey} onSelectFlow={(key) => openFlow(key, null)}
|
|
276
|
-
figure={versionFigure} onSelectVersion={(version) => openFlow(flowKey, version)}
|
|
291
|
+
figure={versionFigure} onSelectVersion={(version) => openFlow(flowKey, version)} onReload={revalidate}
|
|
277
292
|
selectedNodeId={nodeId} onSelectNode={setNodeId} onOpenFlow={openFlow} headingRef={flowHeadingRef}
|
|
278
293
|
customFlows={customFlows} canUpdate={canUpdatePipeline} onEditFlow={openEditor} editorHost={pipelineEditorHost} onRereadCustomFlows={rereadCustomFlows}
|
|
279
294
|
/>
|
|
@@ -335,10 +350,11 @@ and the variant section's `variantSets: readonly VariantSetView[]`, `variantHost
|
|
|
335
350
|
one row `<body>-line` per line with `data-line-kind`, in the foundation's 28 px compact rows, `rowSize="row-compact"`: a read-only line table, whose cells hold no control and no focus target): the line numbers (end-aligned) and the sign (`−` / `+`) in the mono face, and the text in the mono face with its spaces kept (`Text space="preserve"`), its removed and added pieces `InlineChange` fragments (`<del>` / `<ins>`, `<view>-removed` / `<view>-added`); a hunk with no line says `差分の行はありません。` instead.
|
|
336
351
|
Side by side applies from the width at which the side-by-side table shows without scrolling (`tableFrameMinInlinePx` of its six columns: the table's minimum, the rule `DataTable` lays out by, plus the table frame's 4 px on both sides; every fixed column is measured by `fixedColumnPx` from its name in the header's caption step and its mono samples: each side's line-number column, the largest line number's digits, the 48 px sign column, and a flexible text column of 40 mono characters, 336 px; `data-split-min-px`: 856 px up to 2-digit line numbers, 920 px for 6 digits);
|
|
337
352
|
narrower, the view keeps one column and says `幅が足りないため 1 列で表示しています` in a visible sentence, and the change view announces it once through the root's announcer, however many diffs it holds. It measures its width with `ResizeObserver`. Each line table is named after its facet and hunk (`本文 45 行目 (p.3) +3 −1`, the table's hidden caption); side-by-side rows are paired page by page (never across a page boundary) and keyed by their line numbers, as are one-column rows, so a page read later only appends rows and `LoadMore` focuses its first row.
|
|
338
|
-
- **Failures
|
|
339
|
-
- **Manual capture:** with `captureState`, `今の状態を記録` appears while the newest readable run has no state; the outcome is announced (`記録しました` / `前の記録から変化はありません`) and the history is read again.
|
|
353
|
+
- **Failures**: a 401 or a 403 is the root's presenter's (see "Access failures are the root's presenter's"): a 403 states `文書の履歴を閲覧する権限がありません。<原因>。` (`HISTORY_REFUSAL`) and withdraws a history already shown, and a re-read's 401 keeps the history beside the notice, whose retry reads it again (`history-refresh-failed`); any other failure is worded by `labels.failureSentence`, `文書の履歴を読めませんでした (<理由>)。` (`比較`, `差分の行` for the other reads) with a reload. A document with no record says so in a `role="status"` sentence.
|
|
354
|
+
- **Manual capture:** with `captureState`, `今の状態を記録` appears while the newest readable run has no state; the outcome is announced (`記録しました` / `前の記録から変化はありません`) and the history is read again.
|
|
355
|
+
`canSendCommands` (required) says whether the operator may send it: when it is `false`, the control is unavailable from the first render and never busy, described by one note under the panel's heading (the card's description) drawn only while the control is (`history-forbidden-note`, `CAPTURE_FORBIDDEN_SENTENCE`, the same sentence the presenter's notice of a 403 answer states). A failed capture is `文書の状態を記録できませんでした (<理由>)。` (`history-capture-failed`), and its 401 or 403 the presenter's notice of a write without a retry (`今の状態を記録` stays).
|
|
340
356
|
- **Nothing to select:** a history with restricted marks only says `選べる記録はありません。` (`role="status"`) in the detail instead of prompting a pick. The revision groups' open state belongs to the document: re-targeting another document starts again from the defaults.
|
|
341
|
-
- **Focus:** only the `h2` and the detail `h3` take focus (both `tabIndex={-1}`); pressing the row already selected moves focus to the `h3` too. When `今の状態を記録` disappears while holding focus (the recorded state was read back), focus moves to the detail `h3`, or the `h2` when nothing is selected; when a re-read's 403 withdraws content that held focus, focus moves to the `h2`. A refresh failure that repeats with the same words is announced again (its `AlertMessage` occurrence counts the failures).
|
|
357
|
+
- **Focus:** only the `h2` and the detail `h3` take focus (both `tabIndex={-1}`); pressing the row already selected moves focus to the `h3` too. When `今の状態を記録` disappears while holding focus (the recorded state was read back), focus moves to the detail `h3`, or the `h2` when nothing is selected; when a re-read's 403 withdraws content that held focus, or the notice of a re-read's 401 leaves while holding it, focus moves to the `h2`. A refresh failure that repeats with the same words is announced again (its `AlertMessage` occurrence counts the failures).
|
|
342
358
|
The `h2` takes it on mount and whenever `openRequest` changes, recording the element outside the panel that held focus as the opener; an item picked in the panel's own timeline moves focus to the `h3`; a load settling moves nothing. A selected item inside a closed revision group opens the group. Pinning and unpinning move focus to the control that replaced the one holding it. Escape pressed inside (the card's `onEscape`: not during IME composition, nor in a text field holding a value) and the close button call `onClose`;
|
|
343
359
|
on unmount the panel itself returns focus to the opener while it is still in the document, otherwise to `returnFocusFallback()`.
|
|
344
360
|
|
|
@@ -370,8 +386,8 @@ The card asks `@aiquants/console-ui`'s `formatCount` to judge every figure, keep
|
|
|
370
386
|
Each collection's `points_count` and `vectors_count` is checked before it is summed, so a broken row (`-1` and `1001`) never hides inside a total that looks valid (`1,000`).
|
|
371
387
|
The collections are a `CardSection` (`qdrant-collections`, its `h3` コレクション一覧 over the collection count). A list that could not be read is its reason in a warning `Notice` (`qdrant-probe-failure`); otherwise the collections are drawn under one hook, `qdrant-collections-list`, whose empty text is 登録されているコレクションはありません。 (`qdrant-collections-list-empty`).
|
|
372
388
|
Without `selection` they are a read-only `DataTable` named コレクション一覧, in its focusable scroll frame (`qdrant-collections-list-frame`, a region of the same name): rows `collection-row` with `data-collection-name`, the name column as wide as the longest name (`collection-name-${collection_name}`), so a name is not broken while a narrow card scrolls the table instead,
|
|
373
|
-
the point counts end-aligned with their header, and the named-vector tags (`vector-tag-dense-${collection_name}`, `vector-tag-sparse-${collection_name}` as `Sparse` or `Sparse (<MODIFIER>)`, `vector-tag-image-${collection_name}`), neutral `Pill`s that wrap between one another in a `Cluster` (`vector-tags-${collection_name}`, absent for a collection without a named vector).
|
|
374
|
-
With `selection` (`{ selectedCollectionName, onSelectCollection, detailId }`, one value, so a host cannot pass the selected name without the handler or the detail region) they are `@aiquants/console-ui`'s `SelectableList` named コレクション一覧: each row is one `RowButton` (`collection-select` with `data-collection-name`) holding the name and a phrasing `Cluster` (`as="span"`, `collection-facts-${collection_name}`, as a button's content holds only phrasing content) of the
|
|
389
|
+
the domains (the collection's `domain_keys`, the keys of the domains whose points it holds, joined by `・` in the order the host gives them, so a collection several domains share names each of them), the point counts end-aligned with their header, and the named-vector tags (`vector-tag-dense-${collection_name}`, `vector-tag-sparse-${collection_name}` as `Sparse` or `Sparse (<MODIFIER>)`, `vector-tag-image-${collection_name}`), neutral `Pill`s that wrap between one another in a `Cluster` (`vector-tags-${collection_name}`, absent for a collection without a named vector).
|
|
390
|
+
With `selection` (`{ selectedCollectionName, onSelectCollection, detailId }`, one value, so a host cannot pass the selected name without the handler or the detail region) they are `@aiquants/console-ui`'s `SelectableList` named コレクション一覧: each row is one `RowButton` (`collection-select` with `data-collection-name`) holding the name and a phrasing `Cluster` (`as="span"`, `collection-facts-${collection_name}`, as a button's content holds only phrasing content) of the domains (`ドメイン: <keys>` as the table writes them), the point count and the tags, so its accessible name reads all of them;
|
|
375
391
|
`data-selected` and `aria-expanded` say whether it is `selectedCollectionName`, and `aria-controls` names `detailId`, the id of the host's region that shows the selected collection (render it while the card is drawn). One press of a row (Enter, Space or a click anywhere in it) selects once, and Tab moves from row to row.
|
|
376
392
|
The console stylesheet draws the rows' focus ring (2 px of the `focus` token, 2 px out: 5.25:1 on the row's surface and 4.82:1 on the selected one in the light scheme, 6.76:1 and 5.60:1 in the dark one)
|
|
377
393
|
and the selected look: the `info-tint` surface, which is only 1.09:1 (dark: 1.21:1) against the row's surface, and a 4 px `info-accent` bar at the start edge (4.82:1 on the tint, dark: 5.60:1), so the selection is not shown by colour alone, and the bar is redrawn in `Highlight` under forced colours. `tests/colorContrast.spec.tsx` recomputes these four ratios in both schemes from `@aiquants/console-ui`'s `TOKENS` with its `contrastRatio`.
|
|
@@ -397,7 +413,7 @@ The recent document changes (S1 §3.3.5-4), a full-width `Card` `直近の文書
|
|
|
397
413
|
|
|
398
414
|
- A row (`change-feed-row`, `data-row-kind`) shows the arriving state's time, the document (name and URI), the revisions (`r4 → r5` or `r4 (同じ版)`), the cause, the operator, the changed facets as badges and `開く`, which selects the arriving state and names it to assistive technology (`開く doc-9.pdf r4 → r5 の変化`, the file name and the revisions in `VisuallyHidden`). No storage figure is shown (V5).
|
|
399
415
|
- A restricted mark (V11) is one row of the same table with its time and `隔離 (RESTRICTED) の文書` only; its React key is its position (`changeFeedRowKey`).
|
|
400
|
-
- A failed re-read or later page keeps the rows shown and says why (a failed re-read in `change-feed-refresh-failed`, announced again when the same failure repeats); a later page's 403 re-reads the first page
|
|
416
|
+
- A failed re-read or later page keeps the rows shown and says why (a failed re-read in `change-feed-refresh-failed`, announced again when the same failure repeats); a later page's 401 or 403 re-reads the first page: a 403 there withdraws the list (the presenter's notice of `文書の履歴を閲覧する権限がありません。<原因>。`), and a 401 there keeps the rows beside the presenter's notice, whose retry reads the first page again (`change-feed-refresh-failed`).
|
|
401
417
|
|
|
402
418
|
### 13. `ProcessingObjectBrowser`
|
|
403
419
|
|
|
@@ -415,7 +431,7 @@ Props: `host: ProcessingObjectHost` (`{ loadPage(filter, cursor, signal) }`, `pr
|
|
|
415
431
|
A document's status is its sync status badge (`SYNC_STATUS_LABELS`, `syncStatusTone`) or `取り込みの記録なし`, and the error of a failure; a node's is `根の実行` with its root's sync status and `読み: <step> <status> (<skip reason>)` (`nodeReadingText`, `読みの記録なし` when the root's latest run did not read it).
|
|
416
432
|
`履歴` opens the document's history (`文書の履歴`), and a node's opens its root's (`根の履歴`); the button names its object to assistive technology.
|
|
417
433
|
- A restricted mark is one row with `隔離 (RESTRICTED) の文書`, its sync status and its times only, keyed by its position. A list narrowed by name holds no mark (the host's contract).
|
|
418
|
-
- A failed re-read or later page keeps the rows shown and says why (`processing-objects-refresh-failed`); a later page's 403 re-reads the first page
|
|
434
|
+
- A failed re-read or later page keeps the rows shown and says why (`processing-objects-refresh-failed`); a later page's 401 or 403 re-reads the first page: a 403 there withdraws the list (the presenter's notice of `処理オブジェクトを閲覧する権限がありません。<原因>。`), and a 401 there keeps the rows beside the presenter's notice, whose retry reads the first page again.
|
|
419
435
|
|
|
420
436
|
### 14. `ChildRunList`
|
|
421
437
|
|
|
@@ -425,17 +441,17 @@ Props: `rootRunId`, `read: ChildRunPageReader` (`(rootRunId, after, signal) => P
|
|
|
425
441
|
|
|
426
442
|
- A row (`<testId>-row`, `data-run-id`, `data-status`) shows the node the run ran for as the processing-objects list names a node (its place, `treePathLabel` and `#<row id>`; its name, `sourceName` or `名前なし` (`UNNAMED_NODE_TEXT`)), the flow (`pipelineFlowLabel`), the status badge (`PIPELINE_RUN_STATUS_PRESENTATION` with `PIPELINE_RUN_STATUS_TONES`, so a running run waiting for its retry reads `再試行待ち`), the step it stopped at (`ledgerStepLabel`, or `—`) and its start and finish times.
|
|
427
443
|
- The host answers only the child runs of nodes the viewer may read, never a mark; an empty page reads `読める子の実行はありません。`.
|
|
428
|
-
- A failed re-read or later page keeps the rows shown and says why (`<testId>-refresh-failed`); a later page's 403 re-reads the first page
|
|
444
|
+
- A failed re-read or later page keeps the rows shown and says why (`<testId>-refresh-failed`); a later page's 401 or 403 re-reads the first page: a 403 there withdraws the list (the presenter's notice of `子の実行を閲覧する権限がありません。<原因>。`, `CHILD_RUNS_REFUSAL`), and a 401 there keeps the rows beside the presenter's notice, whose retry reads the first page again.
|
|
429
445
|
|
|
430
446
|
### 15. `IngestionQueueHealthCard`
|
|
431
447
|
|
|
432
448
|
The health screen's card of the deployment's ingestion queue for the tenant (`IngestionQueueHealth` of `@aiquants/enrichment-core`, the API's `GET /ai/enrichment/admin/queue` measured once by the database's clock).
|
|
433
|
-
Props: `reading: IngestionQueueHealthReading` (`{ kind: "measured", health }`, `{ kind: "forbidden" }` for an operator the upstream refuses, or `{ kind: "unavailable", status }` for a read that answered nothing usable, `status` `null` without one).
|
|
449
|
+
Props: `reading: IngestionQueueHealthReading` (`{ kind: "measured", health }`, `{ kind: "forbidden" }` for an operator the upstream refuses, `{ kind: "unauthenticated" }` for an operator whose session the upstream no longer accepts (no token to send it, or a token it refused), or `{ kind: "unavailable", status }` for a read that answered nothing usable, `status` `null` without one) and `onReload()` (the host's re-read of the queue, for example its loader's revalidation).
|
|
434
450
|
|
|
435
451
|
- The counts (`ingestion-queue-counts`): the due jobs (`取り出しを待つ仕事`), the oldest due job's wait in seconds and since when (`最も古い待ち`, `なし` while nothing is due), the jobs waiting for a retry (`再試行の待ち`), the running jobs (`実行中`), those asked to stop (`取り消しを求めた実行中`), those whose lease ran out (`持ち分の切れた実行中`) and when it was measured (`測った時刻`), every count a `Measured` in the root's format and every time a `RecordedInstant` in the root's zone.
|
|
436
452
|
- While a running job's lease has run out, a warning names how many and that the patrol reaps them (`ingestion-queue-expired-leases`).
|
|
437
453
|
- The holders (`ingestion-queue-holders`, a row per owner with `data-owner`): the owner, how many running jobs it holds and its newest heartbeat; with none, `今、仕事を持つワーカーはありません (ワーカーは走らせる仕事を通してだけ見えます)。`, since an idle worker leaves no row.
|
|
438
|
-
- In place of the counts, a refusal
|
|
454
|
+
- In place of the counts, a refusal and an ended session are the root's presenter's notice of a read (`ingestion-queue-health-access-failure`; a 403 states `取り込みの列の様子を読む権限がありません。`, `INGESTION_QUEUE_HEALTH_FORBIDDEN_SENTENCE`, and a 401 offers `onReload` as the retry, whose focus moves to the card's heading when the notice leaves), and an unreadable queue reads `取り込みの列の様子を読めませんでした (HTTP <status>)。` (`ingestionQueueHealthUnavailableSentence`, an `AlertMessage`).
|
|
439
455
|
|
|
440
456
|
### 16. `IngestionJobBoard`
|
|
441
457
|
|
|
@@ -449,7 +465,8 @@ Also `canSendCommands` (whether the operator may send a cancel at all; when fals
|
|
|
449
465
|
- 取り消す (`aria-expanded`, `aria-controls`) opens the section's confirmation above its table (`<section>-confirm`, a named group) with `ingestionJobCancelSentence` and focus on 取り消しを確かめる (`danger`), which calls `onCancel`; やめる closes it and returns focus to 取り消す. No table cell holds an unavailable control: the confirmation's button tells why it cannot send (`他の送信の答えを待っています`, `別の仕事の取り消しの答えを待っています`) and is busy (`取り消しを送っています…`) while its own cancel is in flight.
|
|
450
466
|
- Each new `cancelAnswer` is applied once in place (a job that ended leaves its section; a running job whose stop was asked shows `取り消しを求めた実行中` and keeps its document) and announced (`ingestionJobCancelAnnouncement`); an answer equal to the last one is neither applied nor announced again.
|
|
451
467
|
Focus on a confirmation control that disappears returns to the confirmation's opener when it remains, else to the section's heading; focus on a row's 取り消す that disappears while the row stays (its cancel was asked) goes to the section's heading; and when the whole row holding focus leaves, `@aiquants/console-ui`'s `DataTable` moves focus first, to the row now at that position, else the last row, else the empty section's text, so the section's own rescue does not act.
|
|
452
|
-
- Each `revision` re-reads a section's first page, a refused one too (a 403 offers no reload, so the next revision brings it back once the refusal is lifted), except a section whose later pages the operator read: it keeps them and offers `最新の一覧に読み直す` (`<section>-stale`).
|
|
468
|
+
- Each `revision` re-reads a section's first page, a refused one too (a 403 offers no reload, so the next revision brings it back once the refusal is lifted), except a section whose later pages the operator read: it keeps them and offers `最新の一覧に読み直す` (`<section>-stale`).
|
|
469
|
+
A failed re-read or later page keeps the rows shown and says why (`<section>-refresh-failed`); a later page's 401 or 403 re-reads the first page: a 403 there withdraws the section (the presenter's notice of `動いている仕事を閲覧する権限がありません。<原因>。`, `INGESTION_JOBS_REFUSAL`), and a 401 there keeps the rows beside the presenter's notice, whose retry reads the first page again.
|
|
453
470
|
|
|
454
471
|
### 17. `EmbeddingVariantBoard`
|
|
455
472
|
|
|
@@ -460,7 +477,7 @@ The board of the tenant's embedding variant sets (the API's `GET /ai/enrichment/
|
|
|
460
477
|
- **Projection:** the scope (`variant-set-scope-${key}`, `未投影の文書だけ` first, or `全ての文書をもう一度`) and `投影を始める` (`variant-set-project-${key}`, `commands.startProjection(key, { scope })`; unavailable for an inactive set). The 202 answer is noted under the set (`variant-set-noted-${key}`) with its job, or that it merged into a job already waiting or running.
|
|
461
478
|
- **Removing every point:** `全ての点を消す` (`variant-set-remove-${key}`, `aria-expanded`) opens a confirmation group (`variant-set-confirm-${key}`) with focus on `全ての点を消すことを確かめる` (`danger`), which calls `commands.removePoints(key)`; `やめる` closes it. Focus on a confirmation that disappears returns to its opener, or to the card's heading when the set left the list. A 423 refusal (a projection job of the set is waiting or running) is the sentence `variantProjectionActiveSentence` with the API's reason naming the job.
|
|
462
479
|
- **Create:** every field of `VariantSetCreateRequest` (`variant-create-key`, `-provider`, `-model`, `-dimension`, `-query-prefix`, `-passage-template`, `-sparse-modifier`, `-base-url`, `-api-key-env`, `-auto-project`); the texts are sent as typed, an empty optional text as `null` and the dimension as a number. The form is checked with the core's `VariantSetCreateRequestSchema` before it is sent, and each refused field says why (`VARIANT_SET_FIELD_MESSAGES`) once a send has been attempted.
|
|
463
|
-
A refusal the host reads (`VariantSetCreateRejection`) puts the API's 422 messages at the fields they name and the rest in `variant-create-rejected`, and an endpoint outside the deployment (403 / 4033) at the URL field (`ENDPOINT_OUTSIDE_DEPLOYMENT_TEXT`); any other failure is `variant-create-failure
|
|
480
|
+
A refusal the host reads (`VariantSetCreateRejection`) puts the API's 422 messages at the fields they name and the rest in `variant-create-rejected`, and an endpoint outside the deployment (403 / 4033) at the URL field (`ENDPOINT_OUTSIDE_DEPLOYMENT_TEXT`); any other failure is `variant-create-failure`, and a 401 or a 403 the presenter's notice of a write without a retry (as a set's commands' failures under the set). A created set is announced and the form empties.
|
|
464
481
|
- Only the pressed control is pending while its request is in flight (a switch draws `切り替えを送っています…` beside it, a button is busy); each set's last outcome is noted or alerted under it (`variant-set-failure-${key}`). With `canSendCommands` false, every control is unavailable from the first render, described by `variant-board-forbidden-note` (`VARIANT_COMMAND_FORBIDDEN_SENTENCE`), and nothing is sent.
|
|
465
482
|
|
|
466
483
|
### 18. `PipelineRunFlowViewer`
|
|
@@ -468,7 +485,7 @@ The board of the tenant's embedding variant sets (the API's `GET /ai/enrichment/
|
|
|
468
485
|
One recorded run drawn on the shape of the flow version it ran, from the run flow the API answers (`GET /ai/document-history/runs/{run_id}`, `@aiquants/enrichment-core`'s `RunFlow`, required as `runFlow`): a console `Card` (`run-flow`, `data-run-id`) titled `実行 #<id> · 流れ <pipelineFlowLabel>` (`h2`, `run-flow-heading`) holding the run's summary, its links and notices, the figure with each node in the state the run left it, the selected node's detail and the run's step timeline. It draws only what the run flow and the host's reads hold.
|
|
469
486
|
|
|
470
487
|
Props, all required: `runFlow`, `catalog` (the flows' titles and versions for the links, and the figure's geometry), `selectedNodeId` (`string | null`) with `onSelectNode(nodeId | null)`, `onOpenFlow(flowKey, version | null)` (a definition's figure, `null` for the current version), `onOpenRun(runId, nodeId | null)`, `onOpenDocument(metadataId)`, `onClose()`, `readChildRuns: ChildRunPageReader | null` (`null` draws no child run list), `readStepIo: StepIoReader` with `ioRevision` (the inputs and outputs reads' revision),
|
|
471
|
-
`saveStepIoContent: StepIoContentSaver` (given a `StepIoContentTarget` `{ runId, stepId, direction, slot }`, it saves the slot's whole content and resolves to a `ResourceOutcome<null>`; the host names the file, since the gateway does not relay `Content-Disposition`), `refreshFailure: { status, reason } | null` (the host's last failed re-read of the run, as the console foundation's `keepLastGood` keeps it on a shown value) and `headingRef`.
|
|
488
|
+
`saveStepIoContent: StepIoContentSaver` (given a `StepIoContentTarget` `{ runId, stepId, direction, slot }`, it saves the slot's whole content and resolves to a `ResourceOutcome<null>`; the host names the file, since the gateway does not relay `Content-Disposition`), `refreshFailure: { status, reason } | null` (the host's last failed re-read of the run, as the console foundation's `keepLastGood` keeps it on a shown value), `onReload: () => void` (the host's re-read of the run, the retry of a re-read's 401) and `headingRef`.
|
|
472
489
|
|
|
473
490
|
- **Summary** (`run-flow-summary`): 状態 (the `Pill` `run-flow-status` with `data-status` and `data-presentation`, `PIPELINE_RUN_STATUS_PRESENTATION` with `PIPELINE_RUN_STATUS_TONES`), 試行, 開始 (`run-flow-started-at-value`), 終了 (`run-flow-finished-at-value`, or `未完了` in `run-flow-summary-finished-at` while the run is open), 文書 `#<id>`, 選んだ規則 (the rule that chose the run's flow), for a child run 親の実行 (`実行 #<id> (<flow>)`) and 子の道 (`treePathLabel`), and last 誤り (`run-flow-run-error`) when the run recorded an error.
|
|
474
491
|
選んだ規則 reads `組み込みの既定` (`run-flow-binding-default`) when no rule chose the flow, else three lines (`run-flow-binding`): the rule's name with its revision (`run-flow-binding-rule`, `data-binding-id`, `bindingRuleLabel`: `文書の規則 2 番 (改訂 3)`), its conditions (`run-flow-binding-match`, `条件: …`, `bindingMatchLabel`, a child's asset type by its name or `<type> (知らない種類)` outside the vocabulary) and the flow it chose (`run-flow-binding-flow`, `流れ: <title> (<key>)`, or the key alone for a flow the catalogue lacks, as a custom flow the catalogue hides).
|
|
@@ -476,7 +493,8 @@ Props, all required: `runFlow`, `catalog` (the flows' titles and versions for th
|
|
|
476
493
|
- **Notices** (`info` `Notice`s): a run without a shape draws no figure and no detail, only the timeline, and says why: a run without a version, recorded before versions and inputs were, says `この実行は、版と入出力を記録する前の実行です。段の記録を時系列で示します。` (`run-flow-notice-unshaped`), and a run of a version today's steps' words cannot draw (a version the ledger does not keep, or a custom version today's steps no longer draw) says `この実行の版 (版 <v>) は、今の段の言葉で図に描けません。段の記録を時系列で示します。` (`run-flow-notice-undrawable`);
|
|
477
494
|
a replaced run says `この実行は、流れの版が変わったため、実行 #<id> (版 <v>) に置き換えられました。` with `置き換えた実行へ` (`run-flow-notice-superseded-by`, link `run-flow-superseded-by`), and a replacing run `この実行は、実行 #<id> (版 <v>) を置き換えました。` with `置き換えられた実行へ` (`run-flow-notice-supersedes`, link `run-flow-supersedes`), both links calling `onOpenRun(runId, null)` (a run without a version reads `版なし`);
|
|
478
495
|
a run that replaced one the operator may not read says `この実行は、閲覧できない実行を置き換えました。` (`run-flow-supersedes-unreadable`).
|
|
479
|
-
- **Refresh failure**: `refreshFailure` draws, by the console's one failure rule (`labels.failureSentence`), `実行の最新の流れを読めませんでした (<理由>)。` (no parentheses for an empty reason
|
|
496
|
+
- **Refresh failure**: `refreshFailure` draws, by the console's one failure rule (`labels.failureSentence`), `実行の最新の流れを読めませんでした (<理由>)。` (no parentheses for an empty reason; `run-flow-refresh-failed`, an `AlertMessage` whose occurrence advances with every new failure object, so a failure that repeats is announced again), and for a 401 the presenter's notice of a read whose retry is `onReload`.
|
|
497
|
+
A 403 never arrives here: `keepLastGood` withdraws the run on a 403, and the viewer throws `RangeError` if one is passed. `RUN_FLOW_REFUSAL` (`実行の流れを閲覧する権限がありません。`) is exported as the denied sentence a host passes to `ResourceFailed` for a run it could not read.
|
|
480
498
|
- **Figure**: the definition viewer's figure (the same geometry, layout, keys and hint) over the run's shape, named `実行 #<id> の図 (<shape title> 版 <v>)`, with the hooks `run-flow-figure`, `run-flow-svg`, `run-flow-scroll-hint`, `run-flow-node-<id>` and `run-flow-edge-<from>-<to>`. Each node shows the state the run left it in (`data-flow-node-state`, beside `data-step-key`):
|
|
481
499
|
the state of its records, the last one per target (`running` before `failed`, `cancelled`, `succeeded` and `skipped`), and for a node without a record `waiting` while the run runs and `not_run` after; its tone and outline are `RUN_NODE_STATE_TONES` and `RUN_NODE_STATE_OUTLINES` (`failed` `danger`, `succeeded` `success`, `skipped` `warning`, the rest `neutral`; `waiting` and `not_run` dashed).
|
|
482
500
|
Note 0 says what the node did: a per-child node's counts (`子 <n> 件 · 失敗 <n> 件`, `formatChildCount`), a skipped node's short reason (`skipReasonShortLabel`), `前の成功を使用` when every record reused an earlier success, otherwise its phase; note 1 is the state's word (`RUN_NODE_STATE_LABELS`), written `<word> · 経過 <elapsed>` (`formatElapsed`) for a failed, cancelled or succeeded node whose elapsed time was measured.
|
|
@@ -493,7 +511,8 @@ Props, all required: `runFlow`, `catalog` (the flows' titles and versions for th
|
|
|
493
511
|
- **Inputs and outputs** (`run-flow-io-parts`): `受け取ったもの` (`run-flow-io-inputs`) and `作ったもの` (`run-flow-io-outputs`), each an `h4` with a row per slot (`run-flow-io-slot-<direction>-<slot>`), read through `readStepIo` for the node's record.
|
|
494
512
|
A row names where an input came from (出所: a link `<node title> の <slot>` to that node's output, a link `<node title> の子ごとの記録 (<n> 件)` to a per-child node's records, or `流れの入力 (文書 #<id>)`), the slot's size (`run-flow-io-size-<direction>-<slot>`), the head of its SHA-256 (`DIGEST_HEAD_LENGTH` characters) with `ハッシュを写す`, a document it names (`文書 #<id>` in `run-flow-io-document-id-<direction>-<slot>` with the link `文書を開く`, `run-flow-io-document-open-<direction>-<slot>`, calling `onOpenDocument`; then its `名` and `MIME` when they are not empty, and its size),
|
|
495
513
|
its content with `全体を保存` (`saveStepIoContent`) and `開いて見る` (the recorded preview as a tree, `PREVIEW_TRUNCATED_TEXT` where the preview was cut), and for an output the records that took it (受けた記録, `run-flow-io-consumers-<slot>`, each a link `<node title> の <slot>` to that node's input).
|
|
496
|
-
A node without a record says `この節の記録はありません。` (`NO_STEP_RECORD_TEXT`), and a slot without a value says why (`受け取っていません (上流が出力を作りませんでした)`, `作っていません` and `中身の写しはありません (記録の前の出力)` among others).
|
|
514
|
+
A node without a record says `この節の記録はありません。` (`NO_STEP_RECORD_TEXT`), and a slot without a value says why (`受け取っていません (上流が出力を作りませんでした)`, `作っていません` and `中身の写しはありません (記録の前の出力)` among others).
|
|
515
|
+
A read's 401 or 403 is the presenter's notice of a read (`run-flow-io-failure`; a 403 states `段の記録の入出力を閲覧する権限がありません。<原因>。`, `STEP_IO_REFUSAL`, and a 401's retry reads again); any other failure is an `AlertMessage` (`run-flow-io-failed`) with `もう一度読む` (`run-flow-io-retry`). A failed save of a slot's whole content is stated under the slot (`run-flow-io-download-failed-<direction>-<slot>`): an `AlertMessage`, or for a 401 or a 403 the presenter's notice of a read without a retry, since `全体を保存` stays.
|
|
497
516
|
- **Timeline** (`run-flow-timeline`, `段の時系列`, `h3`): the run's `PipelineRunSteps` (see `DocumentHistoryInspector`) in step with the figure: each entry carries `data-entry-key` and `data-selected` (whether it names the selected node); when the selected node changes, its entries open once and the first of them is scrolled into view after the commit (`scrollIntoView({ block: "nearest" })`); the selection the timeline mounts with opens its entries without scrolling, so a screen opened on a selected node stays on the figure.
|
|
498
517
|
The operator can still close the selected node's entries, and opening an entry that names a node selects that node. A run without a shape draws the timeline alone.
|
|
499
518
|
- **Focus**: the card is drawn anew for another run (it is keyed by the run's id), and focus that leaves with the old card goes to the new card's heading (`useFocusRescue`). The node detail opens and closes as the definition viewer's does (the opener, `閉じる`, Escape inside, and `節の選びを外す`).
|
|
@@ -505,7 +524,7 @@ Props, all required: `runFlow`, `catalog` (the flows' titles and versions for th
|
|
|
505
524
|
runFlow={runFlow} catalog={flowCatalog} selectedNodeId={nodeId} onSelectNode={setNodeId}
|
|
506
525
|
onOpenFlow={openFlow} onOpenRun={openRun} onOpenDocument={openDocument} onClose={closeRunFlow}
|
|
507
526
|
readChildRuns={readChildRunPage} readStepIo={documentHistoryHost.loadStepIo} ioRevision={ioRevision}
|
|
508
|
-
saveStepIoContent={documentHistoryHost.saveStepIoContent} refreshFailure={runFlowRefreshFailure} headingRef={runFlowHeadingRef}
|
|
527
|
+
saveStepIoContent={documentHistoryHost.saveStepIoContent} refreshFailure={runFlowRefreshFailure} onReload={reloadRunFlow} headingRef={runFlowHeadingRef}
|
|
509
528
|
/>
|
|
510
529
|
```
|
|
511
530
|
|
|
@@ -531,11 +550,12 @@ Props, all required: `variantSets: readonly VariantSetView[]` (`VariantSetList.v
|
|
|
531
550
|
A success is announced (`問い <id> を採ったにしました。` / `問い <id> を捨てたにしました。`, `問い <id> の本文を直しました。`, `人の問い <id> を採った問いとして足しました。`); a failure is one alert above the table (`evaluation-query-command-failed`): `問い <id> を採れませんでした (<理由>)。`, `問い <id> を捨てられませんでした (<理由>)。`, `問い <id> の本文を直せませんでした (<理由>)。` (the edit stays open on the typed text) or `人の問いを足せませんでした (<理由>)。`.
|
|
532
551
|
Only the pressed command is pending: while it waits, the other row commands and the edit's 直す point at `EVALUATION_QUERY_ROWS_BUSY_SENTENCE` above the table (`evaluation-queries-busy-note`, drawn only while a row command other than the pressed one remains), and 問いを足す draws its own reason, `他の命令の答えを待っています`.
|
|
533
552
|
- **Runs** (`Card` `走り`, `evaluation-runs`, `h2` `evaluation-runs-heading`, drawn for the chosen set): 比べる組 (`evaluation-run-sets`, production `本番 (default)` first and then the active sets, sent in that order, the first the intervals' baseline; `比べる組を 2〜4 つ選んでください。`), 形 (`evaluation-run-modes`: `融合 (HYBRID)`, `密 (DENSE)`, `疎 (SPARSE)`, sent in that order; `形を 1 つ以上選んでください。`),
|
|
534
|
-
判定役が読むチャンクの数 (`evaluation-run-judge-passages`, 1〜10)
|
|
553
|
+
判定役が読むチャンクの数 (`evaluation-run-judge-passages`, 1〜10), 区間の種 (`evaluation-run-seed`, 0 up to `Number.MAX_SAFE_INTEGER`) and 並べ直し (`evaluation-run-rerank`: whether every search reranks the vector tier's chunks with the cross-encoder, `使わない` or `使う` by `rerankText` after `並べ直すかを選ぶ`; there is no default, since a run states what it measured instead of following the tenant's default; `並べ直すかを選んでください。`),
|
|
554
|
+
sent by 走らせる (`evaluation-run-submit`, busy `走りを始めています…`) as `startRun({ query_set_id, variant_keys, modes, judge_passages, bootstrap_seed, rerank })`; a started run is announced (`走り <run uid> を始めました。`) and its report shown.
|
|
535
555
|
The 422 / 4227 refusal says `比べる組の文書が揃っていないので、走りを始めませんでした (<理由>)。組の投影を済ませてから始め直してください。` (`evaluation-run-failed`) above the chosen active sets' projection counts by domain from `variantSets` (`選んだ組の投影`, `evaluation-scope`, rows `evaluation-scope-row` with `data-variant-key` and `data-domain-key`: 組, ドメイン, 今の文書, 今の身元で投影済み, 古い版だけ, 失敗); any other failure says `走りを始められませんでした (<理由>)。` and draws no counts.
|
|
536
|
-
The set's runs, newest first (`集まりの走り`, `evaluation-run-list`, rows `evaluation-run-row` with `data-run-uid` and `data-status`): 作った時刻 (`evaluation-run-created-at-<run uid>`, `RecordedInstant`), 状態 (`evaluation-run-progress-<run uid>`, `runProgressText`: `<state> · <step> <done> / <total> · <failure>`), 組,
|
|
556
|
+
The set's runs, newest first (`集まりの走り`, `evaluation-run-list`, rows `evaluation-run-row` with `data-run-uid` and `data-status`): 作った時刻 (`evaluation-run-created-at-<run uid>`, `RecordedInstant`), 状態 (`evaluation-run-progress-<run uid>`, `runProgressText`: `<state> · <step> <done> / <total> · <failure>`), 組, 形, 並べ直し (`evaluation-run-rerank-<run uid>`, `使う` or `使わない` by `rerankText`) and 結果を見る (`evaluation-run-open-<run uid>`), which shows the run's report.
|
|
537
557
|
The shown run's command reads `示しています`, unavailable and pointing at `EVALUATION_RUN_SHOWN_SENTENCE` (`evaluation-runs-shown-note`, drawn while that run is listed). An empty list says `この集まりの走りはまだありません。`.
|
|
538
|
-
- **Report** (`Card` `結果`, `evaluation-report`, `h2` `evaluation-report-heading`, drawn anew for each run): the summary (`evaluation-report-summary`) — 走り (`evaluation-report-run`), 状態 (`evaluation-report-status`), 失敗の文 (`evaluation-report-failure`, only for a run that recorded one, `文はありません` when it is empty), 比べた組 (`evaluation-report-sets`),
|
|
558
|
+
- **Report** (`Card` `結果`, `evaluation-report`, `h2` `evaluation-report-heading`, drawn anew for each run): the summary (`evaluation-report-summary`) — 走り (`evaluation-report-run`), 状態 (`evaluation-report-status`), 失敗の文 (`evaluation-report-failure`, only for a run that recorded one, `文はありません` when it is empty), 比べた組 (`evaluation-report-sets`), 並べ直し (`evaluation-report-rerank`, `rerankText`),
|
|
539
559
|
範囲 (`evaluation-report-scope`: `<domain> <n> 文書` joined by `・`, `文字のドメインがありません`, or `まだ確かめていません`), 外した採った問い (`evaluation-report-skipped`: `<n> 問 (関連ありと判定した文書が全て今の版を失った)` or `まだ数えていません`) and 採点の決まり (`evaluation-report-constants`: `上位 <cutoff> 件・区間は <resamples> 回の対の bootstrap で信頼 <confidence>%`).
|
|
540
560
|
A run that is not `COMPLETED` says `走りが終わると採点を示します。` while it moves and `終わらなかった走りは採点を持ちません。` otherwise (`evaluation-report-unscored`). A `COMPLETED` run has a section per mode (`evaluation-mode-<mode>`, `h3` by `EVALUATION_SEARCH_MODE_LABELS`) with the questions scored and left out (`evaluation-mode-<mode>-counts`) and a row per set (`evaluation-scores-<mode>`, rows `evaluation-score-row-<mode>` with `data-variant-key`):
|
|
541
561
|
nDCG@10, MRR@10 and Recall@10 (`evaluation-score-<mode>-<key>-<metric>`, three decimals, `採点なし` when the mode scored no question) and each one's difference from the baseline (`evaluation-difference-<mode>-<key>-<metric>`: `基準` for the baseline, otherwise the signed mean with its interval, such as `+0.250 [0.100, 0.400]`, and what the interval says, `基準より良い` above zero, `基準より悪い` below it, `差が分からない` when it reaches zero).
|
|
@@ -546,12 +566,12 @@ Props, all required: `variantSets: readonly VariantSetView[]` (`VariantSetList.v
|
|
|
546
566
|
A row without a chosen grade has its 書く point at `EVALUATION_POOL_CHOOSE_SENTENCE` (`evaluation-review-choose-note`), and while a grade waits the other rows' 書く point at `EVALUATION_POOL_BUSY_SENTENCE` (`evaluation-review-busy-note`); each note is drawn only while a 書く points at it.
|
|
547
567
|
Each mode's rankings then stand side by side (`evaluation-rankings-<id>-<mode>`, `<mode> の組ごとの順位`, rows `<n> 位`, a column per set, each cell `<file uri> · <grade>` with `判定なし` for an unjudged document, or `この順位の文書無し`), or the mode says `<mode> ではどの組も文書を返していません。` (`evaluation-rankings-<id>-<mode>-empty`).
|
|
548
568
|
- **Reads and failures**: a read draws its loading line until it answers (`evaluation-sets-loading`, `evaluation-queries-loading`, `evaluation-runs-loading`, `evaluation-report-loading`, `evaluation-review-loading`), and a failed read is `@aiquants/console-ui`'s `ResourceFailed` with its reload (`evaluation-sets-failed`, `evaluation-queries-failed`, `evaluation-runs-failed`, `evaluation-report-failed`, `evaluation-review-failed`, `evaluation-review-judgments-failed`, each with `-reload`):
|
|
549
|
-
`問いの集まりを読めませんでした (<理由>)。`, and likewise `問い`, `走り`, `走りの採点`, `問いごとの順位` and `問いの判定` (no parentheses for an empty reason), or for a 403 `EVALUATION_READ_FORBIDDEN_SENTENCE
|
|
550
|
-
A failed re-read keeps the values shown and says why (`evaluation-sets-refresh-failed`, `evaluation-queries-refresh-failed`, `evaluation-runs-refresh-failed`, `evaluation-report-refresh-failed`, `evaluation-review-refresh-failed
|
|
551
|
-
Every failure but the run's scope refusal is stated by the console's one failure rule (`labels.failureSentence`)
|
|
569
|
+
`問いの集まりを読めませんでした (<理由>)。`, and likewise `問い`, `走り`, `走りの採点`, `問いごとの順位` and `問いの判定` (no parentheses for an empty reason), or for a 401 or a 403 the presenter's notice in place of the reload (a 401's retry reads again; a 403's denied sentence is `EVALUATION_READ_FORBIDDEN_SENTENCE`, `検索の評価を読む権限がありません。`).
|
|
570
|
+
A failed re-read keeps the values shown and says why (`evaluation-sets-refresh-failed`, `evaluation-queries-refresh-failed`, `evaluation-runs-refresh-failed`, `evaluation-report-refresh-failed`, `evaluation-review-refresh-failed`; a 401 there is the presenter's notice whose retry reads that panel again); a command answered 401 or 403 is the presenter's notice of a write without a retry (a 403's denied sentence is `EVALUATION_COMMAND_FORBIDDEN_SENTENCE`, `検索の評価を操作する権限がありません。`).
|
|
571
|
+
Every other failure but the run's scope refusal is stated by the console's one failure rule (`labels.failureSentence`) in an `AlertMessage` whose occurrence (`data-cui-occurrence`) advances with each failure, so a repeated sentence is announced again; a repeated access failure draws its notice anew.
|
|
552
572
|
- **An operator who may not send commands** (`canSendCommands` false): the workbench says so once above the panels (`evaluation-forbidden-note`, `EVALUATION_COMMAND_FORBIDDEN_SENTENCE`), and from the first render every command — 作る, 問いを作る, 採る, 捨てる, 直す, 問いを足す, 走らせる, each grade choice and 書く — is unavailable (`aria-disabled="true"`) and points at that note (`aria-describedby`); nothing is sent, not even by submitting a form. The fields, the filters, the reads and the reloads keep working, and the notes of a waiting command and of an unchosen grade are not drawn.
|
|
553
573
|
- **Polling and re-reading**: while the chosen set's generation moves (its job is named and it has no summary yet), the sets are read again every `refreshMs`, and when that generation ends every panel is read again; the runs are read again every `refreshMs` while one of them is `QUEUED` or `RUNNING`, and the shown report while its run is. A command's success reads every panel again, as an advance of `revision` does.
|
|
554
|
-
- **Focus**: a busy or unavailable button keeps focus (`aria-disabled`, never `disabled`). Focus on a reload that disappears (its read answered, or came back 403) goes to the panel's heading (`useFocusRescue`): `evaluation-sets-heading` for the sets, `evaluation-queries-section-heading` for the questions, `evaluation-runs-heading` for the runs, and `evaluation-report-heading` for the report, the review and a question's judgments.
|
|
574
|
+
- **Focus**: a busy or unavailable button keeps focus (`aria-disabled`, never `disabled`). Focus on a reload or a notice's retry that disappears (its read answered, or came back 401 or 403) goes to the panel's heading (`useFocusRescue`): `evaluation-sets-heading` for the sets, `evaluation-queries-section-heading` for the questions, `evaluation-runs-heading` for the runs, and `evaluation-report-heading` for the report, the review and a question's judgments.
|
|
555
575
|
- **Headings**: the cards' `h2` (`問いの集まり`, `走り`, `結果`) and the `h3` sections (`集まりを作る`, `問いを作る`, `問い`, and each mode's); `tests/HeadingOutline.spec.tsx` checks the outline with a report shown.
|
|
556
576
|
|
|
557
577
|
```tsx
|
|
@@ -582,36 +602,44 @@ The tenant's custom flows as the editing routes list them (`FlowDraftList`, `GET
|
|
|
582
602
|
|
|
583
603
|
The editor of one custom flow's draft (`flow-editor`; `GET /ai/pipeline/flow-drafts/{flow_key}/draft`, `@aiquants/enrichment-core`'s `FlowDraftAnswer`): its states, its toolbar, the reasons publishing would meet, the flow's own fields, and the draft figure and the node table beside the selected node's fields.
|
|
584
604
|
|
|
585
|
-
Props, all required: `host` (`PipelineEditorHost`), `steps` (the step catalogue, `GET /ai/pipeline/steps`), `opened` (the draft, read once when the editor mounts, so a host draws it with the flow's key as its React key), `canUpdate` (the reader's `storage_admin:update`, limited to neither rows nor columns) and `headingRef` (the host's ref of the heading, where it moves the focus when it draws the editor in place of something else).
|
|
605
|
+
Props, all required: `host` (`PipelineEditorHost`), `steps` (the step catalogue, `GET /ai/pipeline/steps`), `nodeOptions` (the option batches the loader asked for the draft's nodes and could read, the plugin base's `AnsweredOptionBatch<FlowNode>[]`), `opened` (the draft, read once when the editor mounts, so a host draws it with the flow's key as its React key), `canUpdate` (the reader's `storage_admin:update`, limited to neither rows nor columns) and `headingRef` (the host's ref of the heading, where it moves the focus when it draws the editor in place of something else).
|
|
606
|
+
A reader without the right sees the same draft without the toolbar, the fields' controls or the way to add a node, and keeps no work copy; a parameter's value shows as its state among the step's options.
|
|
607
|
+
The editor wraps its tree in the plugin base's `PluginOptionsProvider` (answered by `nodeOptions`, asking through `host.resolveNodeOptions`, its targets keyed by the core's `nodeOptionTargetKeyOf`): a closed field's options and the names of the values the fields and the diffs show come from it. The loader's answers serve at once, and a query they do not answer (a node added, a node of another version, a node of a body compared with, or a batch the loader could not read) is asked through the host in batches. A host batch that breaks the base's contract throws for the nearest error boundary.
|
|
586
608
|
|
|
587
609
|
- **Heading** (`flow-editor-heading`, an `h2` of the flow's `title.ja`, `tabIndex={-1}`, the host's `headingRef`): the key line `鍵 <key> · 文書の流れ` or `鍵 <key> · 子の読みの流れ` (`flow-editor-key`), and the states (`flow-editor-state`, tint `Pill`s `flow-editor-state-<state>` with `data-draft-state`): the list's states (`customFlowStatesOf`), then `保存していない変更` while the work differs from the saved draft.
|
|
588
610
|
- **Toolbar** (`flow-editor-toolbar`, a `Toolbar` named `下書きの操作`): `元に戻す` and `やり直す` (`flow-editor-undo`, `flow-editor-redo`; `元に戻す手はありません。` / `やり直す手はありません。` without a step), `下書きを保存` (`flow-editor-save`, busy `保存しています…`; `保存していない変更はありません。` without one), `公開…` (`flow-editor-publish`), `版から戻す…` (`flow-editor-restore`; `公開した版がありません。` before the first publication), `題を変える…` (`flow-editor-title`) and `退役…` or `退役を解く…` (`flow-editor-retire`).
|
|
589
|
-
`公開…` waits for saved work and a finished check without reasons, and says which is missing (`保存していない変更があります。先に下書きを保存してください。`, `確かめが終わるまで公開できません。`,
|
|
611
|
+
`公開…` waits for saved work and a finished check without reasons, and says which is missing (`保存していない変更があります。先に下書きを保存してください。`, `確かめが終わるまで公開できません。`, `確かめられなかったので公開できません。「もう一度確かめる」で確かめ直してください。` (`確かめられなかったので公開できません。` after a check's 401 or 403, which offers no such button; `checkFailedPublishReason`), `公開できない理由が <n> 件あります。`); `題を変える…` and `退役…` wait for saved work (`保存していない変更があります。先に下書きを保存するか、元に戻してください。`), since both act on the saved draft. An unavailable button keeps its focus and says why (the foundation's `unavailable`).
|
|
590
612
|
Ctrl or ⌘ with Z undoes, with Shift and Z redoes, and with S saves unsaved work while no command is pending (`editorShortcutOf`); a press typed in a text field is left to the field (a checkbox or a radio button is not one).
|
|
591
613
|
- **Notices and failures**: `この窓では作業の写しを残せないので、保存せずに閉じると作業が消えます。` (`flow-editor-work-copy-refused`, `warning`) when `sessionStorage` refuses the work copy; after a re-read, `ほかの人が下書きを変えたので、読み直しました。` (a publication, a retirement or a title refused with 412 / 4120 `PIPELINE_EDIT_STALE`) or `公開の直前の確かめが公開できない理由を見つけたので、下書きを読み直しました。理由の一覧を確かめてください。` (422 / 42210 `PIPELINE_RULES_BROKEN`), both `flow-editor-notice` (`info`) until the next edit;
|
|
592
|
-
and a failed
|
|
614
|
+
and a failed save or re-read above the reasons: `下書きを保存できませんでした (<reason>)。` or `下書きを読み直せませんでした (<reason>)。` (`flow-editor-failure`, an `AlertMessage`, by the console's one failure rule `labels.failureSentence`), or for a 401 or a 403 the presenter's notice — a save's of a write without a retry (`保存` stays; a 403 states `自前の流れを編む権限がありません。<原因>。`), a re-read's of a read whose retry is the same re-read, since no control on the screen reads again (a 403 states `自前の流れと規則は読めません。<原因>。`). Focus on the notice's retry moves to the editor's heading when the notice leaves.
|
|
593
615
|
- **Reasons** (`flow-editor-issues`, `IssueSummary`): the reasons the check of the latest answered round found (`POST /ai/pipeline/flow-drafts/{flow_key}/checks`), numbered, each with its place and a link that selects its node and moves focus to its field (a reason of the node as a whole to the node's reasons at the head of its fields), the editor moving there itself since the browser's move would drop the focus at a field's wrapper.
|
|
594
|
-
For a reader without the update right, whose detail draws no fields, a link leads to the node's heading, or to the flow's own line, and so does a reason of a field that draws no control (the parameters of a step that
|
|
595
|
-
While a check is in flight (`確かめています。`) or after it failed (the failure's sentence, with `もう一度確かめる`), the previous round's reasons stay listed and the sentence says so.
|
|
616
|
+
For a reader without the update right, whose detail draws no fields, a link leads to the node's heading, or to the flow's own line, and so does a reason of a field that draws no control yet (a parameter whose options are still awaited or that has none, and the parameters of a step that takes none). With none it says `公開できない理由はありません (写した元との違い <n> 件)。` (after the first publication `公開した版との違い`).
|
|
617
|
+
While a check is in flight (`確かめています。`) or after it failed (the failure's sentence, with `もう一度確かめる`), the previous round's reasons stay listed and the sentence says so.
|
|
618
|
+
A check answered 401 or 403 says `確かめられませんでした。` and draws the presenter's notice of a read in place of `もう一度確かめる` (`flow-editor-issues-access-failure`; a 403 states `下書きを確かめる権限がありません。<原因>。`, and a 401's retry sends the check again); focus on the button or the notice's retry moves to the region's heading when it leaves. A change of the reasons is announced (`公開できない理由は <n> 件です。` / `公開できない理由はありません。`).
|
|
596
619
|
- **Flow fields** (`flow-editor-wide`, `FlowWideFields`): the flow's inputs as the draft's answer names them (`流れの入力`, which the editor does not change) and its terminal nodes (`終わりの節`, a choice among the body's nodes).
|
|
597
620
|
- **Master and detail** (`flow-editor-master-detail`, the foundation's `MasterDetail`): the master holds the draft figure and the node table, the detail the selected node's fields (`flow-editor-detail`).
|
|
598
621
|
The figure (`flow-editor-figure`, `FlowFigure`, captioned `<title> の下書きの図`) is drawn from the latest answered round's body and the check's figure (`DraftFigure`), under `前の手の図です。` (`flow-editor-figure-previous`) while a newer round waits; when the check found a cycle or a name used twice it is replaced by `図は描けません (輪か重なった名があります)。公開できない理由から直してください。` (`flow-editor-figure-blocked`).
|
|
599
622
|
Its boxes draw no gate state: each names its step (`stepTitleOf`), its node and its count of reasons (`理由なし`, `理由 <n> 件`), `danger` with reasons and `neutral` without, with `data-flow-issue-count`; the keys and the selection are the viewer's.
|
|
600
623
|
The node table (`flow-editor-node-table`, a `DataTable` captioned `節の表`, rows `flow-editor-node-row` with `data-node-id` and `data-selected`) lists the current body's nodes: `順`, the node as a disclosure button `節 <id>` (`flow-editor-node-select`, `aria-expanded`, `aria-controls` naming the detail) with its step's title under it, and `理由の数` (`確かめ待ち` for a node the answer has not seen). With `canUpdate`, `節を足す…` (`flow-editor-add-node`) follows it.
|
|
601
|
-
The detail holds the selected node's fields (`flow-editor-node`, `FlowNodeEditor`: the reasons of the node as a whole at its head (a duplicate name, an unregistered step, an output nothing reads and the like; `flow-editor-node-node-issues`, which takes the focus), then its name, its step (`<title> (<key> 版 <version>)`), its inputs, the nodes it waits for, its parameters and its gates (`門 <n>`), each with its description and its reasons) or `表か図で節を選ぶと、ここに節の欄を示します。` (`flow-editor-detail-empty`).
|
|
624
|
+
The detail holds the selected node's fields (`flow-editor-node`, `FlowNodeEditor`: the reasons of the node as a whole at its head (a duplicate name, an unregistered step, an output nothing reads and the like; `flow-editor-node-node-issues`, which takes the focus), then its name, its step (`<title> (<key> 版 <version>)` in words, with its abilities, since changing a step means adding the node again), its inputs, the nodes it waits for, its parameters and its gates (`門 <n>`), each with its description and its reasons) or `表か図で節を選ぶと、ここに節の欄を示します。` (`flow-editor-detail-empty`).
|
|
625
|
+
The step's abilities are the rows `STEP_DETAIL_ABILITY_ROWS` (`flow-editor-node-step-abilities`: where it goes out to, what it reads, what it changes, whether a cancel stops it and whether it reports its progress). Each settings field of the step's descriptor is the base's `SettingsFieldInput` (`flow-editor-node-parameter-<name>`, legend `引数「<title>」`) over the options the step answers, and the parameters the step does not declare follow as `段の欄に無い引数`, each with `引数 <name> を外す`.
|
|
626
|
+
A closed list of one page and at most `RADIO_MAX_OPTIONS` (8) options draws as radio buttons; an open list, or a closed one longer than one page or 8 options, needs the base's combo box, which is not built yet, so the field throws for the nearest error boundary.
|
|
627
|
+
Removing a node moves focus to the node now in its row, or to `節を足す…` when it was the last.
|
|
602
628
|
The widths come from `flowEditorWidths(formatLocale)`: the position column fits the largest position (`FLOW_NODES_BOUND`), the count column the widest count and `確かめ待ち`;
|
|
603
629
|
the master's minimum is the wider of the history panel's master (`HISTORY_MASTER_MIN_PX`, a line of 20 full-width characters) and the table's frame, and the detail's minimum is the master's times φ, not rounded to the lattice (the foundation gives the master the golden share of the container), so both panes reach their minimums at the width where they come side by side (about 840.8 px for the 312 px master and the 24 px gap) and are split exactly 1:φ at every width from there on;
|
|
604
630
|
a locale whose digits need more room widens the count column, and the master's and detail's minimums follow it.
|
|
605
631
|
- **Dialogs**: `公開…`, `退役…` and `退役を解く…` open `FlowChangeDialog` (`flow-editor-change`; titled `流れを公開する` / `流れを退役させる` / `流れの退役を解く`, busy `公開しています…` / `退役させています…` / `退役を解いています…`).
|
|
606
|
-
Publishing compares the saved draft with the latest published version, or before the first publication with the source it was copied from (`比べる元は公開した版 <n> です。`, `比べる元は写した元 (<flow> 版 <v>) です。`; when the copied version's body is gone, `写した元の版 <n> の構造は残っていないので、今の版 <m> と比べています。`, `flow-editor-change-compare-moved`), node by node (`足す節`, `外す節` and `変わる節` with each changed field's before and after, the terminal nodes and the flow's inputs), and counts the rules that name the flow (`この流れを名指す規則 <n> 本 (次の試みからこの版が走ります)。`).
|
|
632
|
+
Publishing compares the saved draft with the latest published version, or before the first publication with the source it was copied from (`比べる元は公開した版 <n> です。`, `比べる元は写した元 (<flow> 版 <v>) です。`; when the copied version's body is gone, `写した元の版 <n> の構造は残っていないので、今の版 <m> と比べています。`, `flow-editor-change-compare-moved`), node by node (`足す節`, `外す節` and `変わる節` with each changed field's before and after, a closed parameter's values by their options' names, the terminal nodes and the flow's inputs), and counts the rules that name the flow (`この流れを名指す規則 <n> 本 (次の試みからこの版が走ります)。`).
|
|
633
|
+
Retiring lists those rules and waits until none stands (`この流れを名指す規則が <n> 本あります。規則を外してから退役させてください。`).
|
|
607
634
|
`版から戻す…` opens `RestoreVersionDialog` (`flow-editor-restore-dialog`), which lists the published versions newest first (`版 <n>`), says under them who published the chosen one and when (`版 <n> は <published_by> が <instant> に公開しました。`, `flow-editor-restore-dialog-published`, the instant a `RecordedInstant`), reads the chosen version (`readFlowVersion`) and copies its body into the work as one step that undo reverts (`版 <n> の構造を作業へ写しました。元に戻すで戻せます。`);
|
|
608
|
-
`題を変える…` opens `FlowTitleDialog` (`flow-editor-title-dialog`), which saves the titles with the saved body (`題を変えました。`); `節を足す…` opens `AddNodeDialog` (`flow-editor-add-dialog`),
|
|
635
|
+
`題を変える…` opens `FlowTitleDialog` (`flow-editor-title-dialog`), which saves the titles with the saved body (`題を変えました。`); `節を足す…` opens `AddNodeDialog` (`flow-editor-add-dialog`): the step catalogue by phase, each step's newest registered version with its descriptor's title and description, the types of its inputs and outputs, and the two abilities a choice between steps compares (`STEP_CHOICE_ABILITY_ROWS`: where it goes out to and what it changes, each as `<term>: <description>`).
|
|
636
|
+
Its node joins the end of the flow unconnected and without parameters (until each required one is chosen, the check names it), and is selected with focus on its heading; a body that already holds `FLOW_NODES_BOUND` nodes keeps the dialog open with the refusal as an alert.
|
|
609
637
|
After a publication, a retirement or a reinstatement the editor reads the draft again, starts from it and announces the dialog's sentence (`版 <n> を公開しました。` and the like).
|
|
610
638
|
- **Work copy and conflicts**: with `canUpdate`, the unsaved work is kept in `sessionStorage` under `workCopyKey(host.workCopyScope, "flows/<key>")` (`flowWorkCopyKey`), with the row version it started from. Opening the flow again at that row version restores it; at another one (someone saved since), the dialog `保存していない作業と、ほかの人の保存が食い違います` (`flow-editor-conflict`) shows how the kept work differs from that save (`flow-editor-conflict-changes`) and offers `残した作業を採る` (`flow-editor-conflict-keep`; closing the dialog keeps it too) and `残した作業を捨てる` (`flow-editor-conflict-drop`).
|
|
611
639
|
A save refused with 412 / 4120 `PIPELINE_EDIT_STALE` reads the draft again and offers the same choice.
|
|
612
640
|
|
|
613
641
|
```tsx
|
|
614
|
-
<FlowEditor key={flowKey} host={pipelineEditorHost} steps={stepCatalog} opened={flowDraft} canUpdate={canUpdatePipeline} headingRef={editorHeadingRef} />
|
|
642
|
+
<FlowEditor key={flowKey} host={pipelineEditorHost} steps={stepCatalog} nodeOptions={nodeOptions} opened={flowDraft} canUpdate={canUpdatePipeline} headingRef={editorHeadingRef} />
|
|
615
643
|
```
|
|
616
644
|
|
|
617
645
|
### 22. `BindingRulesEditor`
|
|
@@ -623,7 +651,7 @@ Props, all required: `host`, `opened` (the rules, read once when the editor moun
|
|
|
623
651
|
- **Heading** (`binding-editor-heading`, `h2` `結び付けの規則`, `tabIndex={-1}`, the host's `headingRef`): the states (`binding-editor-state`, tint `Pill`s `binding-editor-state-<state>` with `data-draft-state`, in the editors' words and tones): `未公開` before the first revision, else `今の改訂 <n>`; `下書きに未公開の変更` while the draft's rules differ from the current revision's; `保存していない変更` while the work is unsaved.
|
|
624
652
|
Under them, who published the current revision and when (`binding-editor-published`: `今の改訂 <n> は <published_by> が <instant> に公開しました。`, the instant a `RecordedInstant`, `binding-editor-published-at-value`), and `規則は <n> 本です (公開できるのは <max_rules> 本まで)。` (`binding-editor-count`).
|
|
625
653
|
- **Toolbar** (`binding-editor-toolbar`, a `Toolbar` named `規則の操作`): `元に戻す`, `やり直す`, `下書きを保存` (busy `保存しています…`; unavailable without unsaved changes, or while the work has shape errors: `形の誤りが <n> 件あります。直すと保存できます。`) and `公開…` (on the flow editor's terms), with the flow editor's keys.
|
|
626
|
-
- **Notices and failures**: as the flow editor's (`binding-editor-work-copy-refused`, `binding-editor-notice`, `binding-editor-failure`), in the rules' words: `ほかの人が規則を変えたので、読み直しました。`,
|
|
654
|
+
- **Notices and failures**: as the flow editor's (`binding-editor-work-copy-refused`, `binding-editor-notice`, `binding-editor-failure`), in the rules' words: `ほかの人が規則を変えたので、読み直しました。`, `公開の直前の確かめが公開できない理由を見つけたので、規則を読み直しました。理由の一覧を確かめてください。`, and for the presenter's notices of a 403 `結び付けの規則を編む権限がありません。<原因>。` (a save), `自前の流れと規則は読めません。<原因>。` (a re-read or a trial) and `規則を確かめる権限がありません。<原因>。` (a check, `binding-editor-issues-access-failure`).
|
|
627
655
|
- **Reasons** (`binding-editor-issues`, `IssueSummary`): as the flow editor's, with `公開できない理由はありません (今の改訂と違う規則を持つ順 <n> 個)。` (`空の組と…` before the first revision) and a fourth state: the work's shape is checked by the core's schema on every edit (`bindingShapeOf`), and while it has errors the region lists them alone (`形の誤りが <n> 件あります。直すまで、確かめ・試し・保存・公開を送りません。`) and nothing is checked, saved or tried.
|
|
628
656
|
A rule's reason links to its row's field only while that row still holds the rule the reason was found on (`bindingIssueTarget`).
|
|
629
657
|
- **How rules match** (`binding-editor-guide`, `h3` `規則の当たり方`): `規則は目的ごとに表の上から順に試し、有効な規則のうち、設定した条件が全て成り立つ最初の規則の流れが走ります。どの規則にも当たらなければ、組み込みの既定の流れが走ります (「どれにも当たらない時」)。下書きは公開するまで走りません。` (`binding-editor-guide-order`), and, with `canUpdate`, every field's description (`binding-editor-field-descriptions`, WCAG 3.3.5).
|
|
@@ -655,14 +683,15 @@ The host contracts are `VariantSetCommands` (the board's four commands: `create`
|
|
|
655
683
|
## Search Exchange Shapes (`documentSearch.ts`)
|
|
656
684
|
|
|
657
685
|
The shapes the document search exchanges with its host, field for field the public API's answers, and the words both search workbenches are drawn with:
|
|
658
|
-
`DocumentSearchParams` (`threshold` is sent with `DENSE` only; `fusion`, `rrf_k`, `alpha` and `dense_sparse_fusion` with `HYBRID` only), `DocumentSearchAnswer` (`hits: DocumentSearchHit[]`, `authz_scopes`, `search_metadata: DocumentSearchMetadata
|
|
659
|
-
|
|
686
|
+
`DocumentSearchParams` (`threshold` is sent with `DENSE` only; `fusion`, `rrf_k`, `alpha` and `dense_sparse_fusion` with `HYBRID` only; `variant_key` and `rerank` with a strategy that reads a vector tier only), `DocumentSearchAnswer` (`hits: DocumentSearchHit[]`, `authz_scopes`, `search_metadata: DocumentSearchMetadata`, whose `reranked` says whether a cross-encoder reordered the vector tier's chunks),
|
|
687
|
+
`DocumentSearchHit` (every column `null` when the caller's scope hides it, `graph_relations` `null` while a row scope applies or the column scope hides the body), `DocumentScores` (`fused`, `vector: DocumentVectorScore | null`, `lexical_rank`, `graph_rank`),
|
|
688
|
+
and the keys sent only away from a default: `DocumentSearchParams.variant_key` (a set other than production) and `DocumentSearchParams.dense_sparse_fusion` (a fusion other than `DEFAULT_DENSE_SPARSE_FUSION`), each away from the API's, and `DocumentSearchParams.rerank` (`true` or `false`, when the operator turned the rerank on or off instead of leaving it to the tenant's default for the mode), away from the tenant's. The comparison exchanges the core's `VariantComparisonRequest` and `VariantComparisonAnswer` as they are.
|
|
660
689
|
The document search's `degradation_reasons` is `readonly string[]`, not the closed vocabulary, so an answer from a newer API that adds a code is still taken and the code shown as it is; `DEGRADATION_REASON_LABELS` words every code of the core's vocabulary, `dense_embedding_unavailable` (the query's embedding endpoint was not reached, so the dense tier was skipped) included.
|
|
661
|
-
The words: `SEARCH_MODE_LABELS`, `SEARCH_FUSION_LABELS`, `DENSE_SPARSE_FUSION_LABELS`, `QUALITY_TIER_LABELS`, `BREAKER_STATE_LABELS`, `DEGRADATION_REASON_LABELS` / `degradationReasonText`, `HIDDEN_FIELD_TEXT`, and the value helpers `vectorScoreText`, `SCORE_DECIMALS` (3), `rankAgreement` / `RankAgreement` and `variantHitKey`.
|
|
690
|
+
The words: `SEARCH_MODE_LABELS`, `SEARCH_FUSION_LABELS`, `DENSE_SPARSE_FUSION_LABELS`, `RERANK_CHOICES` / `RerankChoice` with `RERANK_CHOICE_LABELS`, `QUALITY_TIER_LABELS`, `BREAKER_STATE_LABELS`, `DEGRADATION_REASON_LABELS` / `degradationReasonText`, `HIDDEN_FIELD_TEXT`, and the value helpers `vectorScoreText`, `SCORE_DECIMALS` (3), `rankAgreement` / `RankAgreement` and `variantHitKey`.
|
|
662
691
|
|
|
663
692
|
## Pipeline Editor Host (`pipelineEditorHost.ts`)
|
|
664
693
|
|
|
665
|
-
The routes the editors send and read again through (`PipelineEditorHost`), one editing route each under `/ai/pipeline
|
|
694
|
+
The routes the editors send and read again through (`PipelineEditorHost`), one editing route each under `/ai/pipeline`, and the options route of the flows' nodes. The first reads a view opens with (the step catalogue, the flow catalogue, the custom flows' list, a draft with the options of its nodes, and the rules) are the loader's, so the components take them as props; the routes, the transport and the authorization are the host's.
|
|
666
695
|
`workCopyScope` names the tenant and the operator the unsaved work belongs to, in the host's words (one string per pair, e.g. the tenant's and the operator's ids). The editors key their work copies by it (`workCopyKey`, which throws `RangeError` for an empty scope), so a window's storage, which outlives a sign-out, never restores one operator's work to another, nor one tenant's to another. A host confirms before its sign-out while any copy is kept and clears every copy during it, both with the light entry `@aiquants/enrichment-react/work-copies` (below).
|
|
667
696
|
|
|
668
697
|
| Route | Request | Answer |
|
|
@@ -679,9 +708,10 @@ The routes the editors send and read again through (`PipelineEditorHost`), one e
|
|
|
679
708
|
| `readFlowDraft(flowKey, signal)` | `GET /flow-drafts/{flow_key}/draft` | `FlowDraftAnswer` |
|
|
680
709
|
| `readBindings(signal)` | `GET /bindings` | `BindingsAnswer` |
|
|
681
710
|
| `readFlowVersion(flowKey, version, signal)` | `GET /flow-drafts/{flow_key}/versions/{version}` | `FlowVersionBody` |
|
|
711
|
+
| `resolveNodeOptions(request, signal)` | `POST /nodes/options` | The plugin base's `OptionBatchOutcome` (one answer per query, in the queries' order) |
|
|
682
712
|
|
|
683
713
|
Every command resolves to a `PipelineEditOutcome<T>` (`CommandOutcome<T, PipelineEditRejection>`), whose `rejection` names the refusal the host read from the upstream status and business code (`pipelineEditCommandFailureCodeOf` of `@aiquants/enrichment-core`): `STALE` (412 / 4120 `PIPELINE_EDIT_STALE`), `RULES_BROKEN` (422 / 42210 `PIPELINE_RULES_BROKEN`), `NOT_FOUND` (404 / 4040 `NOT_FOUND`), `REQUEST_INVALID` (422 / 4222 `REQUEST_INVALID`) or `FORBIDDEN` (403 / 4031 `PERMISSION_DENIED`).
|
|
684
|
-
A refusal the table does not name is no rejection (`null`), and the screen words it from the outcome's status and reason. Every read again resolves to a `ResourceOutcome` and takes the editor's abort signal (a superseded read is aborted and may reject with `AbortError`). No route throws for a failure it can describe.
|
|
714
|
+
A refusal the table does not name is no rejection (`null`), and the screen words it from the outcome's status and reason. Every read again resolves to a `ResourceOutcome` and takes the editor's abort signal (a superseded read is aborted and may reject with `AbortError`). A batch of the nodes' option queries (`resolveNodeOptions`, the base's `ResolveOptions<FlowNode>`) resolves to the base's `OptionBatchOutcome` and rejects only when its signal aborts. No route throws for a failure it can describe.
|
|
685
715
|
|
|
686
716
|
## Work Copies Entry (`@aiquants/enrichment-react/work-copies`)
|
|
687
717
|
|