@w6w/ui 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +275 -2
- package/dist/ActionTestForm.d.ts +76 -0
- package/dist/AddConnectionModal.d.ts +24 -0
- package/dist/AppPicker.d.ts +83 -0
- package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
- package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
- package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
- package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
- package/dist/CodeBlock.d.ts +65 -0
- package/dist/CodeEditor.d.ts +42 -0
- package/dist/ConfirmModal-8avl9Nv8.cjs +11 -0
- package/dist/ConfirmModal-8avl9Nv8.cjs.map +1 -0
- package/dist/ConfirmModal-CD-P8mhN.js +6335 -0
- package/dist/ConfirmModal-CD-P8mhN.js.map +1 -0
- package/dist/Copyable-1niV9gUa.js +771 -0
- package/dist/Copyable-1niV9gUa.js.map +1 -0
- package/dist/Copyable-CYZU1o4X.cjs +2 -0
- package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
- package/dist/JsonEditor.d.ts +60 -0
- package/dist/NodeConfigForm.d.ts +70 -0
- package/dist/ParamsForm.d.ts +56 -0
- package/dist/PropertyEntryForm.d.ts +56 -0
- package/dist/RetryPolicyFields.d.ts +18 -0
- package/dist/StepBuilderModal.d.ts +375 -0
- package/dist/TriggerFillForm.d.ts +52 -0
- package/dist/WaitEditor.d.ts +6 -0
- package/dist/WorkflowFlowEditor.d.ts +119 -0
- package/dist/YamlEditor.d.ts +46 -0
- package/dist/app-categories.d.ts +38 -0
- package/dist/app-pages.d.ts +111 -0
- package/dist/code.cjs +2 -0
- package/dist/code.cjs.map +1 -0
- package/dist/code.d.ts +29 -0
- package/dist/code.mjs +8 -0
- package/dist/code.mjs.map +1 -0
- package/dist/components/ApiCallsPanel.d.ts +41 -0
- package/dist/components/AppIcon.d.ts +25 -0
- package/dist/components/AuthFieldsForm.d.ts +22 -0
- package/dist/components/Combobox.d.ts +24 -0
- package/dist/components/ConfirmModal.d.ts +33 -0
- package/dist/components/Copyable.d.ts +51 -0
- package/dist/components/CopyableText.d.ts +40 -0
- package/dist/components/DeleteButton.d.ts +16 -0
- package/dist/components/EditButton.d.ts +10 -0
- package/dist/components/ExecutionDetail.d.ts +70 -0
- package/dist/components/ExecutionFilters.d.ts +59 -0
- package/dist/components/ExecutionList.d.ts +60 -0
- package/dist/components/ExecutionLogPanel.d.ts +98 -0
- package/dist/components/ExecutionStats.d.ts +47 -0
- package/dist/components/ExpressionEditorModal.d.ts +42 -0
- package/dist/components/ExpressionInput.d.ts +36 -0
- package/dist/components/ExpressionOptions.d.ts +185 -0
- package/dist/components/HealthStatusPill.d.ts +25 -0
- package/dist/components/HistoryTimeline.d.ts +56 -0
- package/dist/components/Icon.d.ts +34 -0
- package/dist/components/IconButton.d.ts +60 -0
- package/dist/components/InfoTip.d.ts +15 -0
- package/dist/components/InternalIcon.d.ts +19 -0
- package/dist/components/ListItem.d.ts +25 -0
- package/dist/components/Modal.d.ts +29 -0
- package/dist/components/RepoSyncIndicator.d.ts +29 -0
- package/dist/components/ResolvedParams.d.ts +31 -0
- package/dist/components/ServerResources.d.ts +47 -0
- package/dist/components/StepStatusPill.d.ts +51 -0
- package/dist/components/UptimeStrip.d.ts +56 -0
- package/dist/components/execution-format.d.ts +24 -0
- package/dist/components/expression-dom.d.ts +154 -0
- package/dist/components/expression-template.d.ts +86 -0
- package/dist/components/history-scale.d.ts +33 -0
- package/dist/components/icons.d.ts +41 -0
- package/dist/components/resolved-clip.d.ts +42 -0
- package/dist/components/server-resources-format.d.ts +68 -0
- package/dist/components/server-resources.fixture.d.ts +9 -0
- package/dist/components/use-copy.d.ts +14 -0
- package/dist/createW6WApi.d.ts +31 -0
- package/dist/flow-connect.d.ts +138 -0
- package/dist/flow-fanout.d.ts +15 -0
- package/dist/flow-types.d.ts +356 -0
- package/dist/flow-utils.d.ts +284 -0
- package/dist/flow.cjs +3 -0
- package/dist/flow.cjs.map +1 -0
- package/dist/flow.d.ts +24 -0
- package/dist/flow.mjs +1978 -0
- package/dist/flow.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.mjs +1812 -0
- package/dist/index.mjs.map +1 -0
- package/dist/oauth-popup.d.ts +17 -0
- package/dist/output-shape.d.ts +58 -0
- package/dist/provider.d.ts +421 -0
- package/dist/resolve-params.d.ts +112 -0
- package/dist/resolved-json.d.ts +21 -0
- package/dist/run-visuals.d.ts +90 -0
- package/dist/step-preview-state.d.ts +143 -0
- package/dist/theme.d.ts +32 -0
- package/dist/trigger-fields.d.ts +56 -0
- package/dist/types.d.ts +413 -0
- package/dist/use-app-action-defs.d.ts +7 -0
- package/dist/use-enter-submit.d.ts +23 -0
- package/dist/use-seed-sources.d.ts +16 -0
- package/package.json +112 -3
- package/src/code.css +561 -0
- package/src/styles/_buttons.scss +38 -0
- package/src/styles/_chips.scss +210 -0
- package/src/styles/_code.scss +139 -0
- package/src/styles/_copyable.scss +147 -0
- package/src/styles/_data-vars.scss +38 -0
- package/src/styles/_execution-history.scss +282 -0
- package/src/styles/_execution-log.scss +178 -0
- package/src/styles/_expression-field.scss +65 -0
- package/src/styles/_expression-inline.scss +63 -0
- package/src/styles/_expression-modal.scss +292 -0
- package/src/styles/_fields.scss +161 -0
- package/src/styles/_flow.scss +217 -0
- package/src/styles/_fx.scss +158 -0
- package/src/styles/_health.scss +46 -0
- package/src/styles/_history-timeline.scss +156 -0
- package/src/styles/_icon-button.scss +22 -0
- package/src/styles/_icon.scss +15 -0
- package/src/styles/_icons.scss +31 -0
- package/src/styles/_incoming-state.scss +46 -0
- package/src/styles/_info-tip.scss +9 -0
- package/src/styles/_layout.scss +6 -0
- package/src/styles/_lists.scss +64 -0
- package/src/styles/_modal.scss +125 -0
- package/src/styles/_multiselect.scss +69 -0
- package/src/styles/_repo-sync-indicator.scss +99 -0
- package/src/styles/_scale.scss +70 -0
- package/src/styles/_sections.scss +36 -0
- package/src/styles/_server-resources.scss +163 -0
- package/src/styles/_step-builder.scss +376 -0
- package/src/styles/_step-config.scss +195 -0
- package/src/styles/_tabs.scss +54 -0
- package/src/styles/_tester.scss +111 -0
- package/src/styles/_tokens.scss +160 -0
- package/src/styles/_uptime.scss +61 -0
- package/src/styles.css +4894 -0
- package/src/styles.scss +61 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
interface ModalProps {
|
|
3
|
+
/** Title row content. A plain string also seeds the dialog's `aria-label`. */
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
/** Accessible name for the dialog; defaults to `title` when it's a string. */
|
|
6
|
+
ariaLabel?: string;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Dialog width. `"wide"` fits a sidebar + content layout; `"xl"` is a large
|
|
11
|
+
* work surface (e.g. the app picker); `"full"` is a near-fullscreen work
|
|
12
|
+
* surface (e.g. the expression editor) that fills most of the viewport;
|
|
13
|
+
* `"fullscreen"` is edge-to-edge 100vw x 100vh with no visible backdrop.
|
|
14
|
+
*
|
|
15
|
+
* `"fullscreen"` leaves NO backdrop to click, so outside-click dismissal is
|
|
16
|
+
* unreachable by construction — a caller using it must give the user a
|
|
17
|
+
* visible way out via {@link ModalProps.headerRight} (Esc alone is not a
|
|
18
|
+
* discoverable affordance).
|
|
19
|
+
*/
|
|
20
|
+
size?: "default" | "wide" | "xl" | "full" | "fullscreen";
|
|
21
|
+
/** Optional node rendered next to the title (e.g. an app icon). */
|
|
22
|
+
titleIcon?: ReactNode;
|
|
23
|
+
/** Optional muted meta rendered after the title (e.g. an app's id + version). */
|
|
24
|
+
subtitle?: ReactNode;
|
|
25
|
+
/** Optional node rendered at the far right of the title row (e.g. a back button). */
|
|
26
|
+
headerRight?: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export declare function Modal({ title, ariaLabel, onClose, children, size, titleIcon, subtitle, headerRight, }: ModalProps): import("react").JSX.Element;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface RepoSyncIndicatorProps {
|
|
2
|
+
/** Branch name, e.g. "main". */
|
|
3
|
+
branch: string;
|
|
4
|
+
/** Already-shortened commit sha (the consumer formats it — D-6). `null` renders no sha. */
|
|
5
|
+
shortSha: string | null;
|
|
6
|
+
/** Already-formatted last-sync text, e.g. "3/9/2026, 12:16:29 PM" or "Never synced".
|
|
7
|
+
* `null` renders no time row. */
|
|
8
|
+
lastSyncLabel: string | null;
|
|
9
|
+
/** Fired when the flyout's "Sync now" item is activated. The consumer owns the mutation. */
|
|
10
|
+
onSyncNow: () => void;
|
|
11
|
+
/** True while the consumer's sync is in flight. */
|
|
12
|
+
syncing?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
"data-testid"?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A compact header control showing a repo glyph, a branch name and a short
|
|
18
|
+
* commit sha, with an inline flyout menu carrying the sync detail and a
|
|
19
|
+
* "Sync now" action the consumer wires.
|
|
20
|
+
*
|
|
21
|
+
* `@w6w/ui` never fetches and holds no studio policy
|
|
22
|
+
* (`studio/src/ui/ExpressionScope.tsx:40-41`, extended by D-6) — this
|
|
23
|
+
* component takes already-formatted strings and a callback.
|
|
24
|
+
*
|
|
25
|
+
* The open/close + outside-click + Escape state machine mirrors
|
|
26
|
+
* `studio/src/components/Layout.tsx:222-328`'s `ProjectMenu()` (D-3: no
|
|
27
|
+
* shared Menu/Popover/Dropdown primitive — there is exactly one consumer).
|
|
28
|
+
*/
|
|
29
|
+
export declare function RepoSyncIndicator(props: RepoSyncIndicatorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { StepStartState } from '../provider.tsx';
|
|
2
|
+
import { ActionParam } from '../types.ts';
|
|
3
|
+
export interface ResolvedParamsProps {
|
|
4
|
+
/** The action's declared params — same list `ParamsForm` renders on Configure. */
|
|
5
|
+
params: ActionParam[];
|
|
6
|
+
/** What will actually be submitted: `{ ...step.with, ...override }` — `testValues`, not `step.with`. */
|
|
7
|
+
values: Record<string, unknown>;
|
|
8
|
+
/** The exact object the test invoke sends as `state` — `steps.*`/`trigger.*` resolve against this. */
|
|
9
|
+
testStartState?: StepStartState;
|
|
10
|
+
/**
|
|
11
|
+
* `"props"` (default) renders the filtered row list; `"code"` renders the
|
|
12
|
+
* COMPLETE resolved-values JSON (A4/A5/D-2) — every visible param, defaults
|
|
13
|
+
* included. Driven by the host's own toggle state; this component never
|
|
14
|
+
* mounts a toggle of its own (D-7 — `PropertyEntryForm` already owns one on
|
|
15
|
+
* the trigger arm, and two side by side is a defect, not a feature).
|
|
16
|
+
*/
|
|
17
|
+
view?: "props" | "code";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read-only sibling of `ParamsForm`: for every configured param, shows the
|
|
21
|
+
* value it resolves to against the current test scope instead of an editable
|
|
22
|
+
* widget. Mounts no `contentEditable`, no `ƒx` button, no input, and never
|
|
23
|
+
* calls an `onChange` — this is the Test tab's "what will actually be sent"
|
|
24
|
+
* view, not a second place to edit params.
|
|
25
|
+
*
|
|
26
|
+
* Reuses `flattenParams`/`isParamVisible` from `ParamsForm.tsx` (same order +
|
|
27
|
+
* visibility the Configure tab uses) rather than re-flattening sections, and
|
|
28
|
+
* the static chip vocabulary (`varLabel`, `.w6w-expr-chip-*`) rather than
|
|
29
|
+
* `expression-dom.ts`'s DOM-painting, which is for the editable field.
|
|
30
|
+
*/
|
|
31
|
+
export declare function ResolvedParams({ params, values, testStartState, view, }: ResolvedParamsProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ServerResourceSample } from './server-resources-format.ts';
|
|
2
|
+
export interface ServerResourcesProps {
|
|
3
|
+
/**
|
|
4
|
+
* The samples to render, oldest first. The LAST entry is the current reading;
|
|
5
|
+
* the whole array is the sparkline's series. May be empty — then every value
|
|
6
|
+
* reads `—` and no line is drawn.
|
|
7
|
+
*/
|
|
8
|
+
samples: readonly ServerResourceSample[];
|
|
9
|
+
}
|
|
10
|
+
export interface ServerResourcesCardProps extends ServerResourcesProps {
|
|
11
|
+
/** Heading text. Defaults to `Server resources`. */
|
|
12
|
+
title?: string;
|
|
13
|
+
/** The sampler's cadence, in ms. When given, the card shows `Sampled every Ns`. */
|
|
14
|
+
intervalMs?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ServerResourcesRailProps extends ServerResourcesProps {
|
|
17
|
+
/**
|
|
18
|
+
* When given, the rail shows one button that asks the caller to open the full
|
|
19
|
+
* view. The rail never opens anything itself — mounting is the caller's job.
|
|
20
|
+
*/
|
|
21
|
+
onExpand?: () => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The large variant: three readings (CPU, memory, process RSS), each with its
|
|
25
|
+
* own sparkline, plus the load averages and — when the caller knows it — the
|
|
26
|
+
* sampling cadence. This is the Console/Modal body.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ServerResourcesCard({ samples, title, intervalMs, }: ServerResourcesCardProps): import("react").JSX.Element;
|
|
29
|
+
/**
|
|
30
|
+
* The small variant: CPU and memory only, one sparkline (CPU). For a compact
|
|
31
|
+
* surface that has room for a headline and a shape, but not for a third
|
|
32
|
+
* reading or the load breakdown.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ServerResourcesCardSmall({ samples, title }: ServerResourcesCardProps): import("react").JSX.Element;
|
|
35
|
+
/**
|
|
36
|
+
* The left-rail variant: a stacked CPU and MEM reading, each with a sparkline,
|
|
37
|
+
* sized to fit a ~200 px column. When the caller passes `onExpand` it also
|
|
38
|
+
* shows the single "show me the rest" button; without one it is read-only
|
|
39
|
+
* decoration and renders no interactive element at all.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ServerResourcesRail({ samples, onExpand }: ServerResourcesRailProps): import("react").JSX.Element;
|
|
42
|
+
/**
|
|
43
|
+
* The header badge: one line, `CPU <pct> · MEM <pct>`, no sparkline (a badge is
|
|
44
|
+
* a fixed-height strip of text, and a line there would be unreadable). The
|
|
45
|
+
* whole string is a single text node so assistive tech reads it as one phrase.
|
|
46
|
+
*/
|
|
47
|
+
export declare function ServerResourcesBadge({ samples }: ServerResourcesProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The five states a workflow step's execution can be in — a thin LOCAL copy
|
|
4
|
+
* of the workflow spec's `StepStatus` union
|
|
5
|
+
* (`packages/w6w-workflow/packages/types/mod.ts`). `@w6w/ui` deliberately
|
|
6
|
+
* keeps a small literal type here rather than depend on `@w6w/workflow-types`,
|
|
7
|
+
* so this stays a pure-presentation leaf with no transport/spec coupling —
|
|
8
|
+
* the same precedent `HealthStatusPill`'s `HealthPillState` establishes.
|
|
9
|
+
*/
|
|
10
|
+
export type StepStatus = "pending" | "running" | "succeeded" | "failed" | "skipped";
|
|
11
|
+
/**
|
|
12
|
+
* The five states a whole EXECUTION (an invocation, an endpoint call, a
|
|
13
|
+
* workflow run) can be in — the run-level sibling of `StepStatus`, and again a
|
|
14
|
+
* thin LOCAL literal rather than an import of any spec/wire type. The two
|
|
15
|
+
* unions differ exactly where runs and steps differ: a run can be `queued`
|
|
16
|
+
* before it starts and `canceled` after it started, while a step inside a run
|
|
17
|
+
* can be `pending` or `skipped` (a run is never either). They are deliberately
|
|
18
|
+
* NOT merged into one five/six-member union — `ExecutionList` and the step
|
|
19
|
+
* panel must each accept only their own vocabulary.
|
|
20
|
+
*/
|
|
21
|
+
export type ExecutionStatus = "queued" | "running" | "succeeded" | "failed" | "canceled";
|
|
22
|
+
export interface StepStatusPillProps {
|
|
23
|
+
/**
|
|
24
|
+
* Which state to render — drives the colour + default label. Accepts both
|
|
25
|
+
* vocabularies: a workflow step's `StepStatus` and a whole run's
|
|
26
|
+
* `ExecutionStatus` (the pill is only a coloured label, so it does not care
|
|
27
|
+
* which of the two a host is describing).
|
|
28
|
+
*/
|
|
29
|
+
state: StepStatus | ExecutionStatus;
|
|
30
|
+
/** Override the visible text (defaults to a humanised form of `state`). */
|
|
31
|
+
label?: ReactNode;
|
|
32
|
+
/** Accessible label for the pill (falls back to the visible text). */
|
|
33
|
+
ariaLabel?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A small, theme-aware status pill for one workflow step's execution state.
|
|
37
|
+
*
|
|
38
|
+
* Mirrors `HealthStatusPill` shape for shape: a state union, a
|
|
39
|
+
* `DEFAULT_LABELS` record, a coloured dot + text label using one
|
|
40
|
+
* `--w6w-step-color` custom property per modifier class, and the
|
|
41
|
+
* `w6w-step-pill w6w-step-pill-${state}` className convention. Colour is
|
|
42
|
+
* never the only signal — the text label carries the same meaning for
|
|
43
|
+
* accessibility. Five states rather than `HealthStatusPill`'s four, so this
|
|
44
|
+
* is a mirror of that shape, not a shared implementation.
|
|
45
|
+
*
|
|
46
|
+
* Renders BOTH vocabularies through the one prop: `StepStatus` (a step inside
|
|
47
|
+
* a run) and `ExecutionStatus` (a whole run). The union is widened at the
|
|
48
|
+
* PROP only — `StepStatus` itself is unchanged, so the step panel's own type
|
|
49
|
+
* cannot silently grow run-only states.
|
|
50
|
+
*/
|
|
51
|
+
export declare function StepStatusPill({ state, label, ariaLabel }: StepStatusPillProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The four states a single day of the strip can be in — a thin LOCAL copy of the
|
|
3
|
+
* RFC's `HealthReport.state` union, exactly as `HealthStatusPill` keeps one. The
|
|
4
|
+
* duplication is deliberate: it keeps `@w6w/ui` a pure-presentation leaf with no
|
|
5
|
+
* transport/spec coupling, so nothing here has to move when the spec package does.
|
|
6
|
+
*
|
|
7
|
+
* There is no fifth state. A day on which the account made no calls at all is
|
|
8
|
+
* `unknown`, never `ok` — an unverified day must never be presented as a healthy
|
|
9
|
+
* one (`rfcs/healthcheck.md`: `unknown` ranks above `ok` for that reason).
|
|
10
|
+
*/
|
|
11
|
+
export type UptimeCellState = "ok" | "degraded" | "down" | "unknown";
|
|
12
|
+
/** One cell: the day it stands for, and the state already decided for it. */
|
|
13
|
+
export interface UptimeDay {
|
|
14
|
+
/** The day this cell represents, e.g. `2026-07-27`. Shown verbatim in the tooltip. */
|
|
15
|
+
day: string;
|
|
16
|
+
/** The state for that day. The strip renders it; it never decides it. */
|
|
17
|
+
state: UptimeCellState;
|
|
18
|
+
/** Tooltip override. Defaults to `<day> — <state label>`. */
|
|
19
|
+
label?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface UptimeStripProps {
|
|
22
|
+
/**
|
|
23
|
+
* The days to render, oldest first, one cell each. The component makes no
|
|
24
|
+
* assumption about how many there are — a caller showing a 30-day window
|
|
25
|
+
* passes 30, and a younger account can pass fewer.
|
|
26
|
+
*/
|
|
27
|
+
days: UptimeDay[];
|
|
28
|
+
/**
|
|
29
|
+
* Accessible label for the strip as a whole (it is exposed as one image, not
|
|
30
|
+
* as N unlabelled boxes). Defaults to `<n>-day status`.
|
|
31
|
+
*/
|
|
32
|
+
ariaLabel?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A fixed-height strip of one cell per day, for "how has this service behaved
|
|
36
|
+
* lately" at a glance.
|
|
37
|
+
*
|
|
38
|
+
* Purely presentational — it is handed an array of ALREADY-DECIDED states and
|
|
39
|
+
* renders exactly those. No rules, no roll-up and no judgement about what counts
|
|
40
|
+
* as broken live in this package; whatever decided the states owns that.
|
|
41
|
+
*
|
|
42
|
+
* Colour is never the only signal (same rule as `HealthStatusPill`, which pairs
|
|
43
|
+
* its dot with a text label). Thirty cells cannot carry thirty labels, so the
|
|
44
|
+
* strip signals twice in two other ways:
|
|
45
|
+
* - every cell carries a `title` with its day and state, and
|
|
46
|
+
* - the FILL HEIGHT encodes severity, so the row survives greyscale and
|
|
47
|
+
* colour-blind viewing: `ok` is a short baseline bar, `degraded` a taller
|
|
48
|
+
* one, `down` fills the cell, and `unknown` is a hatched outline with no
|
|
49
|
+
* solid fill at all (nothing was measured — it is not a good day and not a
|
|
50
|
+
* bad one).
|
|
51
|
+
*
|
|
52
|
+
* Colour itself comes from the shared `--w6w-health-*` tokens through the single
|
|
53
|
+
* `--w6w-health-color` indirection the health pill uses, so a host that
|
|
54
|
+
* overrides a token restyles the pill and the strip together.
|
|
55
|
+
*/
|
|
56
|
+
export declare function UptimeStrip({ days, ariaLabel }: UptimeStripProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure duration/time formatters for the execution-history family, kept in
|
|
3
|
+
* their own module so they carry no React and can be unit-tested on their own
|
|
4
|
+
* — the same split `server-resources-format.ts` establishes.
|
|
5
|
+
*
|
|
6
|
+
* Both are TOTAL: a duration that was never measured (a still-running or
|
|
7
|
+
* queued run) is rendered as an em dash, never as `0 ms` — "unknown" must not
|
|
8
|
+
* read as "instant".
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* A run duration as a short human string: whole milliseconds below a second
|
|
12
|
+
* (`999 ms`), one decimal place in seconds below a minute (`1.5 s`), and
|
|
13
|
+
* `2m 5s` from a minute up. `null`/`undefined` (nothing measured), `NaN` and
|
|
14
|
+
* negatives are all `—`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatDurationMs(ms: number | null | undefined): string;
|
|
17
|
+
/**
|
|
18
|
+
* An ISO-8601 instant as a short, locale-formatted date+time (`Sep 22, 2026,
|
|
19
|
+
* 10:00 AM` under the default locale). The locale is the HOST's
|
|
20
|
+
* (`undefined`), so the string follows the viewer's own settings rather than
|
|
21
|
+
* baking one in. A string `Date` cannot parse is returned UNCHANGED — an
|
|
22
|
+
* unrenderable timestamp is shown as the wire value, never as "Invalid Date".
|
|
23
|
+
*/
|
|
24
|
+
export declare function formatExecutionTime(iso: string): string;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { ExprPart } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The name a source or chip DISPLAYS. Never the ref it SAVES.
|
|
4
|
+
*
|
|
5
|
+
* A saved ref is always canonical and engine-resolvable — the run scope offers
|
|
6
|
+
* exactly `vars.* · steps.<id>.output.* · steps.<id>.meta.* · trigger.* · secrets.* · documents.* ·
|
|
7
|
+
* inputs.* · foreach.* · output.*` (`core/rfcs/workflow.md` §Expressions, built
|
|
8
|
+
* in `w6w-workflow/packages/engine/src/run.ts`). Those read long in a field, so
|
|
9
|
+
* the label drops the root the chip's sigil and colour already imply:
|
|
10
|
+
*
|
|
11
|
+
* | ref | label |
|
|
12
|
+
* |-----------------------------|----------------|
|
|
13
|
+
* | `vars.from_email` | `from_email` |
|
|
14
|
+
* | `steps.gate_1.output` | `gate_1` |
|
|
15
|
+
* | `steps.gate_1.output.email` | `gate_1.email` |
|
|
16
|
+
* | `steps.gate_1.meta.version` | `gate_1 meta · version` |
|
|
17
|
+
* | anything else | verbatim |
|
|
18
|
+
*
|
|
19
|
+
* **`gate_1.email` is a LABEL ONLY — it is not an expression.** There is no
|
|
20
|
+
* `gate_1` key at the run-scope root, so a chip that STORED the short form would
|
|
21
|
+
* render perfectly in the editor and resolve to empty at run time, silently and
|
|
22
|
+
* untraceably. `makeChip` keeps the two apart deliberately: the chip's stored
|
|
23
|
+
* attribute carries the ref, this function only ever feeds `label.textContent`.
|
|
24
|
+
*/
|
|
25
|
+
export declare const varLabel: (ref: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether a declared output key can become a ref the engine actually resolves.
|
|
28
|
+
*
|
|
29
|
+
* A key that fails this would still produce a chip that renders perfectly and
|
|
30
|
+
* evaluates to **empty at run time, silently** — the same failure mode the
|
|
31
|
+
* label/ref split exists to avoid — so the picker must not offer it at all. The
|
|
32
|
+
* step's WHOLE output (`steps.<id>.output`) is still offered, which remains the
|
|
33
|
+
* author's route to such a field via an explicit `=` JSONLogic expression.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isRefSafeKey(key: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Whether a declared output PATH (`start.utc` — an app action's `OutputField`
|
|
38
|
+
* key, where `.` means nesting, not a literal character) can become a ref the
|
|
39
|
+
* engine resolves: the same `getVar` split that makes a literal `a.b` key
|
|
40
|
+
* unreachable is what walks a path, so each SEGMENT must pass
|
|
41
|
+
* {@link isRefSafeKey} on its own.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isRefSafePath(path: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Build the non-editable inline chip (tag) DOM node for a part.
|
|
46
|
+
*
|
|
47
|
+
* `renderToggle` is opt-in and defaults OFF: `makeChip` is shared through
|
|
48
|
+
* {@link paintParts} by every editing surface, including the inline
|
|
49
|
+
* `ExpressionInput` (`ExpressionInput.tsx`), which has no handler for the
|
|
50
|
+
* flip control at all. A painter must not decide who gets an affordance —
|
|
51
|
+
* only `ExpressionEditorModal` (the one surface with a click delegate for
|
|
52
|
+
* `[data-render-toggle]`) passes `true`. Round 2 fix for F-2: before this,
|
|
53
|
+
* every `var`/`render` chip everywhere painted the toggle unconditionally,
|
|
54
|
+
* so it leaked into every inline expression field in studio as a dead,
|
|
55
|
+
* screen-reader-announced control.
|
|
56
|
+
*/
|
|
57
|
+
export declare function makeChip(doc: Document, part: ExprPart, { renderToggle }?: {
|
|
58
|
+
renderToggle?: boolean;
|
|
59
|
+
}): HTMLElement;
|
|
60
|
+
/**
|
|
61
|
+
* Decode a chip element back into the part it represents — the one and only
|
|
62
|
+
* decode in the file. Hoisted out of {@link readParts}'s inline `var` /
|
|
63
|
+
* `secret` / `render` (`data-ref`) and `expr` (`data-expr` JSON) arms so
|
|
64
|
+
* {@link chipToText} can reuse the exact same logic rather than re-deriving
|
|
65
|
+
* it; `readParts` itself now calls this instead of carrying its own copy.
|
|
66
|
+
* `null` for any element that isn't a chip (`data-kind` absent or not one of
|
|
67
|
+
* the four kinds) — the caller falls through to its other element handling.
|
|
68
|
+
*/
|
|
69
|
+
export declare function chipToPart(el: HTMLElement): ExprPart | null;
|
|
70
|
+
/**
|
|
71
|
+
* Reconstruct parts from an editor's DOM (the source of truth while editing).
|
|
72
|
+
*
|
|
73
|
+
* The walk is **recursive**: a native Enter wraps the caret's line in a `<div>`
|
|
74
|
+
* (or drops a `<br>`), and anything nested inside it — chips included — must
|
|
75
|
+
* survive. Reading `textContent` at that point would flatten a chip to its
|
|
76
|
+
* label and silently destroy the reference it carries, so every unrecognised
|
|
77
|
+
* element is descended into instead. `<br>` and block children map to a literal
|
|
78
|
+
* `"\n"`; `pushText` coalesces those into the surrounding text part.
|
|
79
|
+
*
|
|
80
|
+
* One `<br>` is deliberately NOT a newline: a FILLER one, closing its block —
|
|
81
|
+
* see `walk` and {@link ensureFillerBreak}.
|
|
82
|
+
*/
|
|
83
|
+
export declare function readParts(root: HTMLElement): ExprPart[];
|
|
84
|
+
/**
|
|
85
|
+
* Give a line break at the very END of the caret's line somewhere to render.
|
|
86
|
+
*
|
|
87
|
+
* A `"\n"` that is the last thing in a `white-space: pre-wrap` block paints
|
|
88
|
+
* nothing, and the caret cannot land past it — the author presses Enter, sees no
|
|
89
|
+
* break, and their next keystroke lands on the *previous* line (observed in
|
|
90
|
+
* Chromium; see `artifacts/T3.1.2-browser-check.sh`). Browsers solve this for
|
|
91
|
+
* their own line breaks with a FILLER `<br>` as the block's last child, so ours
|
|
92
|
+
* uses the same device. `readParts` skips exactly that node — the two are one
|
|
93
|
+
* fact, kept in one file.
|
|
94
|
+
*/
|
|
95
|
+
export declare function ensureFillerBreak(editor: HTMLElement): void;
|
|
96
|
+
/**
|
|
97
|
+
* Paint an editor's DOM from parts (text nodes + chips).
|
|
98
|
+
*
|
|
99
|
+
* `opts` passes straight through to {@link makeChip} — `renderToggle`
|
|
100
|
+
* defaults off, so a caller that never opts in (`ExpressionInput.tsx`) paints
|
|
101
|
+
* no toggle at all, and only `ExpressionEditorModal` turns it on.
|
|
102
|
+
*/
|
|
103
|
+
export declare function paintParts(el: HTMLElement, parts: ExprPart[], opts?: {
|
|
104
|
+
renderToggle?: boolean;
|
|
105
|
+
}): void;
|
|
106
|
+
/**
|
|
107
|
+
* Put the caret at the end of the editor.
|
|
108
|
+
*
|
|
109
|
+
* Deliberately NOT special-cased for a trailing filler `<br>`: a caret placed
|
|
110
|
+
* past the filler is a position Chromium normalises straight back into the
|
|
111
|
+
* content, so the next character still lands before the filler. That was
|
|
112
|
+
* measured, not assumed — a version of this function that skipped the filler
|
|
113
|
+
* explicitly could not be distinguished from this one by any probe in
|
|
114
|
+
* `T3.1.2-browser-check.sh`, including §K, which exists to try. What DOES have
|
|
115
|
+
* to respect the filler is the node insertion itself (see `insertNodeAtCaret`).
|
|
116
|
+
*/
|
|
117
|
+
export declare function placeCaretAtEnd(el: HTMLElement): void;
|
|
118
|
+
/** Insert a node at the caret (or at the end if the caret isn't in the editor). */
|
|
119
|
+
export declare function insertNodeAtCaret(editor: HTMLElement, node: Node): void;
|
|
120
|
+
/**
|
|
121
|
+
* D-3 (binding): promote a just-closed `{{ … }}` marker to a chip at the
|
|
122
|
+
* keystroke that closes it — the caret-safe surgery an `onInput` handler can
|
|
123
|
+
* call directly, with NO `paintGen` bump (see the warning at the top of
|
|
124
|
+
* `ExpressionEditorModal.tsx` and `G-typing` in `expr-template-guards.test.cjs`:
|
|
125
|
+
* a repaint here resets the caret and reorders every subsequent keystroke).
|
|
126
|
+
*
|
|
127
|
+
* Returns `false`, doing nothing, unless ALL of:
|
|
128
|
+
* - the selection is collapsed inside a text node `editor` contains;
|
|
129
|
+
* - the two characters immediately before the caret are `}}`;
|
|
130
|
+
* - there is a `{{` earlier in THAT SAME text node (a marker interrupted by
|
|
131
|
+
* a chip — i.e. split across text nodes — is not a marker, deliberately);
|
|
132
|
+
* - `parseRootAnchoredTemplate` of the text from that `{{` to the caret
|
|
133
|
+
* parses to exactly ONE part that is not `kind: "text"` (an unrooted
|
|
134
|
+
* marker, or one that isn't a single complete part, stays literal).
|
|
135
|
+
*
|
|
136
|
+
* On success: deletes exactly that span and inserts the chip in its place —
|
|
137
|
+
* the same `Range` surgery `insertNodeAtCaret` performs, mirrored rather than
|
|
138
|
+
* reused because the span here is a slice of an EXISTING text node, not the
|
|
139
|
+
* live selection — then collapses the caret just after the chip.
|
|
140
|
+
*/
|
|
141
|
+
export declare function promoteCompletedMarkerAtCaret(editor: HTMLElement, opts?: {
|
|
142
|
+
renderToggle?: boolean;
|
|
143
|
+
}): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* D-3: the reverse of {@link promoteCompletedMarkerAtCaret} — a chip back to
|
|
146
|
+
* its editable `{{ … }}` text, in place. `chipToPart` is the SAME decode
|
|
147
|
+
* `readParts` uses, so what comes back is exactly what the chip carries, and
|
|
148
|
+
* `serializeTemplate` is the SAME serializer the round trip already goes
|
|
149
|
+
* through everywhere else in this file. `null` for an element that isn't a
|
|
150
|
+
* chip. The caller collapses the caret at the returned node's end — this
|
|
151
|
+
* function only performs the DOM swap, mirroring `chip.replaceWith` being the
|
|
152
|
+
* whole of the "remove" arm (`onClick`'s `[data-x]` handler) in both editors.
|
|
153
|
+
*/
|
|
154
|
+
export declare function chipToText(chip: HTMLElement): Text | null;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { parseTemplate, serializeTemplate } from '@w6w/expr';
|
|
2
|
+
import { ExprPart, ExprValue, SecretValue } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* `ui`'s view of the one `{{ }}` inline-expression grammar. The parser and the
|
|
5
|
+
* serializer live in `@w6w/expr` (`core/packages/expr/src/template.ts`) so the
|
|
6
|
+
* engine and the editor read the SAME grammar rather than two copies that must
|
|
7
|
+
* agree forever; this module re-exports them and keeps the editor-only helpers
|
|
8
|
+
* below (`renderResult` masks secrets as `•••` — a preview policy that must not
|
|
9
|
+
* enter the engine's package).
|
|
10
|
+
*
|
|
11
|
+
* Grammar, modes, and the secret fence (D-8) are documented at the definition.
|
|
12
|
+
*
|
|
13
|
+
* `parseTemplate` itself builds every `{{ }}` marker unconditionally — it has
|
|
14
|
+
* no opinion on whether a marker is a W6W expression or a vendor placeholder
|
|
15
|
+
* (Mailjet's `{{var:name}}`, Metabase's `{{tag}}`, …). {@link
|
|
16
|
+
* parseRootAnchoredTemplate} below adds that opinion (root-anchored parsing,
|
|
17
|
+
* CONDUCTOR AMENDMENT 2026-08-14) and is what `valueToParts` and the chip-ify
|
|
18
|
+
* commit paths call — never `parseTemplate` directly on untrusted text.
|
|
19
|
+
*/
|
|
20
|
+
export { parseTemplate, serializeTemplate };
|
|
21
|
+
/**
|
|
22
|
+
* Serialize parts to the leanest faithful VALUE: prune empty text, collapse a
|
|
23
|
+
* lone text segment to a plain string (backward-compat), else an `ExprValue`.
|
|
24
|
+
* Shared by the inline field and the expression editor modal.
|
|
25
|
+
*/
|
|
26
|
+
export declare function partsToValue(parts: ExprPart[]): ExprValue | string;
|
|
27
|
+
/** Every root name, for tests that pin the derived set without reaching into the type. */
|
|
28
|
+
export declare const RUN_SCOPE_ROOT_NAMES: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Root-anchored parse (CONDUCTOR AMENDMENT 2026-08-14): builds every marker in
|
|
31
|
+
* `s` via `parseTemplate` (never a second `{{ }}` scanner), then requires:
|
|
32
|
+
* - a `var` marker: `hasRefusedChainToken` must be false (a `||`/`??` the
|
|
33
|
+
* chain grammar refused — mixed operators, a `secrets.` operand, … — is
|
|
34
|
+
* never treated as an ordinary path) AND its first path segment must be a
|
|
35
|
+
* `RUN_SCOPE_ROOTS` member;
|
|
36
|
+
* - an `expr` marker recognised by `coalesceOperandRefs` as a `||`/`??`
|
|
37
|
+
* chain: EVERY operand ref's first path segment must be a
|
|
38
|
+
* `RUN_SCOPE_ROOTS` member — a chain is a first-class citizen here, not
|
|
39
|
+
* the opaque escape hatch below;
|
|
40
|
+
* - any other `expr` marker (`=<jsonlogic>`, or a `{{ }}` chip inserted from
|
|
41
|
+
* the rail) or a `secret` marker (`secrets.NAME`): unambiguous by its OWN
|
|
42
|
+
* syntax, no separate check.
|
|
43
|
+
* One unrooted marker/operand reverts the WHOLE string to a single literal
|
|
44
|
+
* `text` part (byte-identical to the input) — all-or-nothing, because the
|
|
45
|
+
* grammar has no escape syntax and a mixed string can't half-chip. This is
|
|
46
|
+
* what keeps `{{ vars.a }}` and `{{ vars.a || "x" }}` chips while Mailjet's
|
|
47
|
+
* `{{var:name}}`, Mandrill's Handlebars, and Metabase's `{{tag}}` stay literal
|
|
48
|
+
* text forever (121 spellings surveyed across `packages/apps`, 116 of them
|
|
49
|
+
* vendor placeholders with no root of their own).
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseRootAnchoredTemplate(s: string): ExprPart[];
|
|
52
|
+
/**
|
|
53
|
+
* Parse an incoming value into editable parts (+ any sealed secret to display).
|
|
54
|
+
* The inverse of {@link partsToValue} for the editable forms; a sealed
|
|
55
|
+
* `SecretValue` has no parts (it's shown as a masked chip, never decrypted).
|
|
56
|
+
*
|
|
57
|
+
* The string arm root-anchor-parses (see {@link parseRootAnchoredTemplate}):
|
|
58
|
+
* a hand-typed, pasted, re-opened, or SDK/MCP-written `"{{ vars.x }}"` now
|
|
59
|
+
* chip-ifies identically to a rail insertion, while a vendor placeholder like
|
|
60
|
+
* `"{{name}}"` stays literal text forever — it never had a root to lose.
|
|
61
|
+
*/
|
|
62
|
+
export declare function valueToParts(value: ExprValue | string | SecretValue | undefined): {
|
|
63
|
+
parts: ExprPart[];
|
|
64
|
+
sealed: SecretValue | null;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Render parts to their preview text for the expression editor's Result pane:
|
|
68
|
+
* `text` parts concatenate literally, a `var` part resolves against `samples`
|
|
69
|
+
* (keyed by full ref) or renders `""` when unresolved — never the raw
|
|
70
|
+
* `{{ ref }}` template token — and a `secret` part always masks as `•••`.
|
|
71
|
+
*
|
|
72
|
+
* A `render` part resolves through the exact SAME flat `samples` lookup as
|
|
73
|
+
* `var` (A4c) — it does NOT additionally substitute `{{ }}` markers inside the
|
|
74
|
+
* resolved value. That substitution is the engine's `resolveRenderPart`
|
|
75
|
+
* (`packages/w6w-workflow/packages/engine/src/expr.ts`, out of scope), which
|
|
76
|
+
* runs against a real run scope; this design-time preview has no run scope to
|
|
77
|
+
* substitute against, so it shows the field's raw template text verbatim, same
|
|
78
|
+
* as `var` would. Without at least the flat-lookup half, the new
|
|
79
|
+
* insert-as-render action's very first click would leave the Result pane
|
|
80
|
+
* blank, which reads as broken.
|
|
81
|
+
*
|
|
82
|
+
* No client-side evaluator for `expr` parts (see the TODO in
|
|
83
|
+
* `ExpressionEditorModal.tsx`) — those fall back to their `{{ }}` template
|
|
84
|
+
* form.
|
|
85
|
+
*/
|
|
86
|
+
export declare function renderResult(parts: ExprPart[], samples: Record<string, string>): string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { HistoryWindow, VendorIncidentBar } from './HistoryTimeline.tsx';
|
|
2
|
+
/**
|
|
3
|
+
* Minimum visible width for a bar, as a percentage of the window's span. A
|
|
4
|
+
* point-in-time entry (no `startedAt`) has zero duration and would otherwise
|
|
5
|
+
* be invisible; a very short span is floored to the same width so it never
|
|
6
|
+
* shrinks below it either.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MIN_BAR_WIDTH_PCT = 1;
|
|
9
|
+
export interface BarPlacement {
|
|
10
|
+
/** Left edge, as a percentage of the window's span, clamped to `[0, 100]`. */
|
|
11
|
+
leftPct: number;
|
|
12
|
+
/** Width, as a percentage of the window's span. Never below `MIN_BAR_WIDTH_PCT`. */
|
|
13
|
+
widthPct: number;
|
|
14
|
+
/** `true` if the bar's start was clamped to the window's left edge. */
|
|
15
|
+
clippedStart: boolean;
|
|
16
|
+
/** `true` if the bar's end was clamped to the window's right edge. */
|
|
17
|
+
clippedEnd: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Places one vendor incident bar on the window's `[from T00:00:00Z, to+1 day
|
|
21
|
+
* T00:00:00Z)` span.
|
|
22
|
+
*
|
|
23
|
+
* - A bar's start is `startedAt ?? updatedAt`; with neither present there is
|
|
24
|
+
* nothing to place, so this returns `null` (B5).
|
|
25
|
+
* - Its end is `resolvedAt ?? (startedAt !== undefined ? nowMs : start)` — an
|
|
26
|
+
* open incident (has `startedAt`, no `resolvedAt`) therefore runs to
|
|
27
|
+
* `nowMs`, and a feed-only entry with no `startedAt` is a point in time,
|
|
28
|
+
* not a span (B3).
|
|
29
|
+
* - A bar wholly outside the window (ends before it starts, or starts at or
|
|
30
|
+
* after it ends) returns `null` (B4). One overlapping an edge is clamped
|
|
31
|
+
* into the window, with `clippedStart`/`clippedEnd` set accordingly.
|
|
32
|
+
*/
|
|
33
|
+
export declare function placeIncidentBar(window: HistoryWindow, bar: VendorIncidentBar, nowMs: number): BarPlacement | null;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Kebab-case, named for what the glyph DEPICTS or for its conventional meaning —
|
|
4
|
+
* never for the studio component that happened to draw it, so a caller asks for
|
|
5
|
+
* `icon="history"` rather than `icon="history-icon-tsx"`.
|
|
6
|
+
*/
|
|
7
|
+
export type IconName = "edit" | "edit-2" | "delete" | "copy" | "check" | "close" | "history" | "info" | "clock" | "json" | "code" | "sync" | "cloud-download" | "eye" | "play" | "stop" | "warning" | "file-text" | "settings" | "github" | "user" | "users" | "logout" | "id-card" | "dashboard" | "pulse" | "workflow" | "globe" | "lambda" | "sliders" | "file" | "plug" | "grid" | "folder" | "git-branch" | "coin" | "building" | "server" | "price-tag" | "lang-node" | "terminal" | "lang-python" | "lang-curl" | "sun" | "moon" | "circle-half" | "layout" | "run" | "trash" | "maximize" | "form" | "braces" | "settings-2";
|
|
8
|
+
/**
|
|
9
|
+
* Which attributes the shared `<svg>` root carries — i.e. how the glyph is
|
|
10
|
+
* painted. The sources are not uniform, and forcing them into one shape would
|
|
11
|
+
* change how they render:
|
|
12
|
+
*
|
|
13
|
+
* - `fill` — Material-style: a single `fill="currentColor"` path, no stroke.
|
|
14
|
+
* - `stroke` — Feather-style outline: `fill="none"`, `stroke="currentColor"`,
|
|
15
|
+
* round caps/joins, plus the source's own `strokeWidth`.
|
|
16
|
+
* - `mixed` — the glyph paints each element itself (the language marks: a
|
|
17
|
+
* stroked outline next to filled dots, and `lang-python`'s mask),
|
|
18
|
+
* so the root carries NO paint attribute at all, exactly as its
|
|
19
|
+
* source did. Adding a root stroke here would fatten every dot;
|
|
20
|
+
* `layout`'s single path paints nothing either, its colour coming
|
|
21
|
+
* from the surrounding control button — again as its source did.
|
|
22
|
+
*/
|
|
23
|
+
export type IconVariant = "fill" | "stroke" | "mixed";
|
|
24
|
+
/** One glyph: its source `<svg>`'s viewBox, its paint variant, and its children. */
|
|
25
|
+
interface IconDef {
|
|
26
|
+
viewBox: string;
|
|
27
|
+
variant: IconVariant;
|
|
28
|
+
/** `stroke` variants only — the source's own weight (2 for Feather, 1.75 for the rail glyphs). */
|
|
29
|
+
strokeWidth?: number;
|
|
30
|
+
/** The source `<svg>`'s children, verbatim. */
|
|
31
|
+
body: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/** The set. Entries are grouped for readability; `iconNames` is this object's own order. */
|
|
34
|
+
export declare const icons: Record<IconName, IconDef>;
|
|
35
|
+
/**
|
|
36
|
+
* Every name in the set, in the object's curated order — what the gallery story
|
|
37
|
+
* renders and what `Icon.test.ts` walks. Derived from `icons` rather than
|
|
38
|
+
* repeated, so it cannot drift from what `Icon` can actually draw.
|
|
39
|
+
*/
|
|
40
|
+
export declare const iconNames: readonly IconName[];
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clipping for ONE resolved value's display text (Test tab, read-only rows).
|
|
3
|
+
*
|
|
4
|
+
* A resolved row is a SUMMARY of what the run will be sent, not a viewer for
|
|
5
|
+
* it. A value that resolves from a document (`documents.*.body`) or a rendered
|
|
6
|
+
* template is routinely tens of kilobytes of HTML, and pasting all of it inline
|
|
7
|
+
* pushed the rest of the params — and the run's own result — off the screen
|
|
8
|
+
* (human report, 2026-09-01). So a long value is clipped here and offered
|
|
9
|
+
* behind a toggle; the complete value is always one click away in the `<>`
|
|
10
|
+
* code view above, which is COMPLETE over every visible param by construction
|
|
11
|
+
* (`resolved-json.ts`, D-2) and so must never be clipped itself.
|
|
12
|
+
*
|
|
13
|
+
* Plain `.ts`, no React — same pure-module-beside-the-component precedent
|
|
14
|
+
* `history-scale.ts` sets for `HistoryTimeline.tsx`, so the rule is testable
|
|
15
|
+
* without a JSX transpile.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Characters shown before a value is clipped. Sized to a few lines at the
|
|
19
|
+
* row's font — enough to recognize WHICH value resolved (the opening of an
|
|
20
|
+
* HTML document, a subject line, a URL) without becoming the page.
|
|
21
|
+
*/
|
|
22
|
+
export declare const RESOLVED_VALUE_CLIP = 220;
|
|
23
|
+
/** A clip decision: the text to render, and whether anything was withheld. */
|
|
24
|
+
export interface ClippedValue {
|
|
25
|
+
/** What to show when collapsed — never longer than {@link RESOLVED_VALUE_CLIP}. */
|
|
26
|
+
text: string;
|
|
27
|
+
/** True when `text` is shorter than the input, i.e. a toggle is warranted. */
|
|
28
|
+
clipped: boolean;
|
|
29
|
+
/** The full value's length, for the toggle's own label. */
|
|
30
|
+
length: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Clip `text` for the collapsed row. At or under the budget the input is
|
|
34
|
+
* returned byte-identically and `clipped` is false — a short value must never
|
|
35
|
+
* grow a toggle, an ellipsis, or a trailing-whitespace trim it didn't ask for.
|
|
36
|
+
*
|
|
37
|
+
* Over the budget, the cut is a plain `slice` at the boundary with trailing
|
|
38
|
+
* whitespace trimmed (so an ellipsis never floats a space away from the text).
|
|
39
|
+
* No word-boundary search: these values are markup and JSON as often as prose,
|
|
40
|
+
* where "the last space" is not a meaningful place to stop.
|
|
41
|
+
*/
|
|
42
|
+
export declare function clipResolvedValue(text: string): ClippedValue;
|