@w6w/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +260 -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-DJPYXE9t.cjs +11 -0
- package/dist/ConfirmModal-DJPYXE9t.cjs.map +1 -0
- package/dist/ConfirmModal-sY1tzkBO.js +6335 -0
- package/dist/ConfirmModal-sY1tzkBO.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 +7 -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 +22 -0
- package/dist/flow.mjs +1977 -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 +1811 -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 +420 -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/ui.css +1 -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 +111 -3
- package/src/code.css +542 -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 +141 -0
- package/src/styles/_uptime.scss +61 -0
- package/src/styles.css +4208 -0
- package/src/styles.scss +61 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { AppSummary } from './types.ts';
|
|
2
|
+
/** The user-controlled inputs that identify a distinct page fetch. */
|
|
3
|
+
export interface AppsPageQuery {
|
|
4
|
+
/** Trimmed search text; `""` means no search term. */
|
|
5
|
+
q: string;
|
|
6
|
+
/** Server-side category filter (e.g. `"ai"` for the AI tab), or absent. */
|
|
7
|
+
category?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Two queries are the same fetch target when both fields match exactly
|
|
11
|
+
* (empty-string `q` included) — used to short-circuit a reducer action that
|
|
12
|
+
* would otherwise restart an identical in-flight query.
|
|
13
|
+
*/
|
|
14
|
+
export declare function sameAppsPageQuery(a: AppsPageQuery, b: AppsPageQuery): boolean;
|
|
15
|
+
export type AppsPageStatus = "loading" | "loading-more" | "ready" | "error";
|
|
16
|
+
export interface AppsPageState {
|
|
17
|
+
query: AppsPageQuery;
|
|
18
|
+
/**
|
|
19
|
+
* Bumped every time the query changes (new search/category/tab). A
|
|
20
|
+
* response tagged with an older generation is stale and MUST be dropped by
|
|
21
|
+
* the caller before dispatching — {@link isStalePageGeneration} is the
|
|
22
|
+
* check; the reducer itself also refuses a stale `page-loaded`/`page-failed`
|
|
23
|
+
* defensively, so a caller that forgets the check still cannot corrupt state.
|
|
24
|
+
*/
|
|
25
|
+
generation: number;
|
|
26
|
+
status: AppsPageStatus;
|
|
27
|
+
/** Every app fetched so far for the CURRENT query, in server order, deduped by id. */
|
|
28
|
+
apps: AppSummary[];
|
|
29
|
+
/** Cursor to send on the NEXT "load more"; absent once the server has no more pages. */
|
|
30
|
+
cursor?: string;
|
|
31
|
+
hasMore: boolean;
|
|
32
|
+
error?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function initialAppsPageState(query: AppsPageQuery, generation?: number): AppsPageState;
|
|
35
|
+
export type AppsPageAction =
|
|
36
|
+
/** A new search/category/tab was selected — resets `apps`/`cursor` and starts a fresh fetch. */
|
|
37
|
+
{
|
|
38
|
+
type: "query-changed";
|
|
39
|
+
query: AppsPageQuery;
|
|
40
|
+
generation: number;
|
|
41
|
+
}
|
|
42
|
+
/** The user asked for more results on the CURRENT query. No-op unless `status==="ready" && hasMore`. */
|
|
43
|
+
| {
|
|
44
|
+
type: "load-more";
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The user pressed Retry after a failure. Only meaningful from `"error"`:
|
|
48
|
+
* back to `"loading"` when nothing is shown yet, `"loading-more"` when a
|
|
49
|
+
* list is already on screen (apps and cursor kept, so the retry resends the
|
|
50
|
+
* SAME cursor). No-op in any other status.
|
|
51
|
+
*/
|
|
52
|
+
| {
|
|
53
|
+
type: "retry";
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* One page arrived. `requestedCursor` is the cursor that page was fetched
|
|
57
|
+
* WITH (undefined for a first page) — compared against the server's own
|
|
58
|
+
* `nextCursor` to catch a server that echoes back the same cursor forever
|
|
59
|
+
* (a repeated/non-advancing cursor is treated as "no more pages", never
|
|
60
|
+
* retried, so it can neither loop nor duplicate a request).
|
|
61
|
+
*/
|
|
62
|
+
| {
|
|
63
|
+
type: "page-loaded";
|
|
64
|
+
generation: number;
|
|
65
|
+
apps: AppSummary[];
|
|
66
|
+
nextCursor?: string;
|
|
67
|
+
requestedCursor?: string;
|
|
68
|
+
} | {
|
|
69
|
+
type: "page-failed";
|
|
70
|
+
generation: number;
|
|
71
|
+
error: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Dedupe-append: every app in `incoming` not already present (by `id`) in
|
|
75
|
+
* `existing`, in `incoming`'s own order, appended after `existing`.
|
|
76
|
+
* Immutable — always returns a new array, and existing entries in `existing`
|
|
77
|
+
* are shared references, never mutated, so a caller that kept the old array
|
|
78
|
+
* around still sees the original values (copy-safety for cache reads).
|
|
79
|
+
*/
|
|
80
|
+
export declare function dedupeAppend(existing: AppSummary[], incoming: AppSummary[]): AppSummary[];
|
|
81
|
+
/**
|
|
82
|
+
* The paged-picker reducer. Every transition is a pure function of
|
|
83
|
+
* `(state, action)` — no timers, no fetch; the caller performs the actual
|
|
84
|
+
* request and feeds the result back in as `page-loaded`/`page-failed`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function appsPageReducer(state: AppsPageState, action: AppsPageAction): AppsPageState;
|
|
87
|
+
/** Whether a response tagged `generation` is stale against `state` — check before dispatching. */
|
|
88
|
+
export declare function isStalePageGeneration(state: AppsPageState, generation: number): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Reserved `@w6w/*` pseudo-apps are never a pickable catalog entry (mirrors
|
|
91
|
+
* `AppPicker`'s existing exclusion) — factored out so the paged path and the
|
|
92
|
+
* id-batch path apply the exact same rule.
|
|
93
|
+
*/
|
|
94
|
+
export declare function excludeInternalApps(apps: readonly AppSummary[]): AppSummary[];
|
|
95
|
+
/**
|
|
96
|
+
* The next batch of ids to resolve: up to `batchSize` entries from `ids`,
|
|
97
|
+
* preserving `ids`' own order, skipping anything already in `requested`.
|
|
98
|
+
* Returns `[]` once every id has been requested — the caller's signal to stop
|
|
99
|
+
* showing "load more". Never re-requests an id already in `requested`, even
|
|
100
|
+
* across repeated calls with a growing `requested` set (idempotent given the
|
|
101
|
+
* same two inputs).
|
|
102
|
+
*/
|
|
103
|
+
export declare function nextIdBatch(ids: readonly string[], requested: ReadonlySet<string>, batchSize: number): string[];
|
|
104
|
+
/**
|
|
105
|
+
* Merge a batch of resolved summaries into the accumulated visible list,
|
|
106
|
+
* preserving `ids`' overall order (not fetch-arrival order) and silently
|
|
107
|
+
* dropping any id with no entry in `resolved` — the caller's contract for a
|
|
108
|
+
* missing/404 id (see `useReadyToUse`'s id-batch rewrite): omitted, not shown
|
|
109
|
+
* as an error.
|
|
110
|
+
*/
|
|
111
|
+
export declare function mergeResolvedApps(ids: readonly string[], resolved: ReadonlyMap<string, AppSummary>): AppSummary[];
|
package/dist/code.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/code.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@w6w/ui/code` — the read-only code block, on its own.
|
|
3
|
+
*
|
|
4
|
+
* The third entrypoint, for the same reason `./flow` is the second: importing
|
|
5
|
+
* the root `index.ts` pulls that module's WHOLE graph, and a bundler resolves
|
|
6
|
+
* imports before it tree-shakes, so "we only use one component" does not save
|
|
7
|
+
* the consumer anything. From `index.ts` that graph reaches:
|
|
8
|
+
*
|
|
9
|
+
* - `@w6w/expr` — the expression engine, an npm dependency of this package.
|
|
10
|
+
* In this monorepo it is overridden to a `link:../core/packages/expr`
|
|
11
|
+
* sibling checkout (`packages/core`, itself a submodule), so a consumer
|
|
12
|
+
* that links this package's SOURCE without that checkout fails to build,
|
|
13
|
+
* with an unresolved-import error naming a package it never asked for.
|
|
14
|
+
* Measured, not theorised: it is what broke the frontend site's first
|
|
15
|
+
* build. (An npm install of the published package is unaffected.)
|
|
16
|
+
* - `@uiw/react-codemirror` + `@codemirror/*` — the editors, which are far
|
|
17
|
+
* heavier than the thing being imported.
|
|
18
|
+
*
|
|
19
|
+
* Nothing here reaches either. `CodeBlock` imports `prism-react-renderer` and
|
|
20
|
+
* `Copyable`; `Copyable` imports React and nothing else.
|
|
21
|
+
*
|
|
22
|
+
* The matching stylesheet is `@w6w/ui/code.css` (13 KB) — `@w6w/ui/styles.css`
|
|
23
|
+
* also contains these rules, so a host already importing the full sheet needs
|
|
24
|
+
* no second import.
|
|
25
|
+
*/
|
|
26
|
+
export { CodeBlock } from './CodeBlock.tsx';
|
|
27
|
+
export type { CodeBlockProps, CodeLanguage } from './CodeBlock.tsx';
|
|
28
|
+
export { Copyable } from './components/Copyable.tsx';
|
|
29
|
+
export type { CopyableProps } from './components/Copyable.tsx';
|
package/dist/code.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ApiCallRecord } from '../types.ts';
|
|
3
|
+
export interface ApiCallsPanelProps {
|
|
4
|
+
/** The captured outbound calls to render, in the order they were made. */
|
|
5
|
+
calls: ApiCallRecord[];
|
|
6
|
+
/**
|
|
7
|
+
* Open every call's `<details>` on first render. Default `false` — the wire
|
|
8
|
+
* log is ground truth you reach for, not something to read on every run. A
|
|
9
|
+
* host that already landed the user on ONE specific call (e.g. a drill-down
|
|
10
|
+
* that scoped the list to it) passes `true` so the user isn't made to click
|
|
11
|
+
* twice through their own target.
|
|
12
|
+
*/
|
|
13
|
+
defaultOpen?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* React `key` for each call. Defaults to method + url + array index, which is
|
|
16
|
+
* stable within a single run because captured calls carry no id of their own.
|
|
17
|
+
* A host rendering PERSISTED rows (which do have an id) across a paginated
|
|
18
|
+
* list must pass its own — index keys collide between pages and React then
|
|
19
|
+
* reuses the wrong `<details>` open-state.
|
|
20
|
+
*/
|
|
21
|
+
keyOf?: (call: ApiCallRecord, index: number) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Section header. Defaults to `API call(s) (N)`. Pass `false` to suppress it
|
|
24
|
+
* entirely when the host already owns the heading — same idiom as
|
|
25
|
+
* `ActionTestForm`'s `embedded` prop, which suppresses its own pop-out chrome
|
|
26
|
+
* because the host provides it. Any other node replaces the default text.
|
|
27
|
+
*/
|
|
28
|
+
title?: ReactNode | false;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The wire log for a run: each outbound HTTP call the action made, with the
|
|
32
|
+
* request we sent and the response we got back. Collapsed by default — it is the
|
|
33
|
+
* ground truth you open when the result looks wrong (e.g. a template variable
|
|
34
|
+
* that came through unrendered), not something to read on every run.
|
|
35
|
+
*
|
|
36
|
+
* Purely presentational: it renders exactly what it is given, with no fetching,
|
|
37
|
+
* no context, and no derivation of state from the calls. Credential redaction
|
|
38
|
+
* happens server-side at capture time (request AND response headers); nothing
|
|
39
|
+
* here re-inspects or re-redacts them.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ApiCallsPanel({ calls, defaultOpen, keyOf, title }: ApiCallsPanelProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ThemeMode } from '../types.ts';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Data URI or absolute URL for the light-mode icon. Falsy → render an initials tile. */
|
|
4
|
+
src?: string;
|
|
5
|
+
/** Optional dark-mode variant; used when `theme === "dark"`. */
|
|
6
|
+
srcDark?: string;
|
|
7
|
+
/** Background color when falling back to the initials tile. */
|
|
8
|
+
brandColor?: string;
|
|
9
|
+
/** Display name used to produce initials when there's no image. */
|
|
10
|
+
name?: string;
|
|
11
|
+
/** Square px size. Defaults to 32. */
|
|
12
|
+
size?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Explicit theme. If omitted, reads `data-theme` from `<html>` and falls
|
|
15
|
+
* back to `prefers-color-scheme` — matches how most theme systems work.
|
|
16
|
+
*/
|
|
17
|
+
theme?: ThemeMode;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Renders an app's icon. Prefers the inlined SVG served by the w6w server;
|
|
21
|
+
* falls back to a small initials tile when no icon is provided or when both
|
|
22
|
+
* light and dark variants are missing.
|
|
23
|
+
*/
|
|
24
|
+
export declare function AppIcon({ src, srcDark, brandColor, name, size, theme }: Props): import("react").JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { KeyboardEventHandler } from 'react';
|
|
2
|
+
import { AuthField } from '../types.ts';
|
|
3
|
+
interface Props {
|
|
4
|
+
fields: AuthField[];
|
|
5
|
+
values: Record<string, unknown>;
|
|
6
|
+
onChange: (values: Record<string, unknown>) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Spread onto every field's `<input>` — from the caller's own
|
|
9
|
+
* `useEnterSubmit(submit, { enabled })`, so Enter in a credential field
|
|
10
|
+
* submits the same way the form's primary button does. Optional so this
|
|
11
|
+
* component still works with no submit-on-Enter wiring at all.
|
|
12
|
+
*/
|
|
13
|
+
enterSubmitProps?: {
|
|
14
|
+
onKeyDown: KeyboardEventHandler<HTMLElement>;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Renders the form for an Auth method's `fields` declaration. Field shape
|
|
19
|
+
* comes from the app's manifest so no app-specific knowledge is needed here.
|
|
20
|
+
*/
|
|
21
|
+
export declare function AuthFieldsForm({ fields, values, onChange, enterSubmitProps }: Props): import("react").JSX.Element;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ComboboxOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ComboboxProps {
|
|
6
|
+
options: ComboboxOption[];
|
|
7
|
+
value: string;
|
|
8
|
+
onChange: (value: string) => void;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
"aria-label"?: string;
|
|
12
|
+
/** `auto` picks a native `<select>` for short lists, a combobox for long ones. */
|
|
13
|
+
mode?: "select" | "combobox" | "auto";
|
|
14
|
+
/** true (default): typing only filters; value changes by picking. false: free text is a value. */
|
|
15
|
+
forceSelection?: boolean;
|
|
16
|
+
/** Estimated option height in px, used by `auto` mode. Default 32. */
|
|
17
|
+
optionHeight?: number;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Combobox is chosen when the list would take more than 60% of the viewport. */
|
|
21
|
+
export declare function shouldUseCombobox(count: number, optionHeight: number, viewportHeight: number): boolean;
|
|
22
|
+
/** Case-insensitive substring match on label and value. */
|
|
23
|
+
export declare function filterOptions(options: ComboboxOption[], query: string): ComboboxOption[];
|
|
24
|
+
export declare function Combobox({ options, value, onChange, placeholder, disabled, "aria-label": ariaLabel, mode, forceSelection, optionHeight, className, }: ComboboxProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface ConfirmModalProps {
|
|
3
|
+
title: string;
|
|
4
|
+
message: string;
|
|
5
|
+
/** Fired when the user confirms. The caller clears its pending state via onClose. */
|
|
6
|
+
onConfirm: () => void;
|
|
7
|
+
/** Fired on Cancel, Esc, or outside-click — dismisses without confirming. */
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
confirmLabel?: string;
|
|
10
|
+
cancelLabel?: string;
|
|
11
|
+
/** Style the confirm button as destructive (default true — this dialog gates dangerous actions). */
|
|
12
|
+
destructive?: boolean;
|
|
13
|
+
/** Extra consequence copy under the message (e.g. a warning line) that a string cannot carry. */
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A reusable confirmation dialog built on `@w6w/ui`'s <Modal>, so it inherits the
|
|
18
|
+
* same backdrop, Esc-dismiss and outside-click close as every other dialog here.
|
|
19
|
+
* Replaces the browser's native confirmation prompt: Confirm fires `onConfirm`;
|
|
20
|
+
* Cancel/Esc/outside-click fires `onClose` only (no confirmation).
|
|
21
|
+
*
|
|
22
|
+
* Prop API mirrors `packages/studio/src/components/ConfirmModal.tsx` and
|
|
23
|
+
* `packages/admin/src/components/ConfirmModal.tsx` so all three consoles share one
|
|
24
|
+
* vocabulary. Only the class names differ — this one is `w6w-*` namespaced.
|
|
25
|
+
*
|
|
26
|
+
* It owns its own <Modal>, so never render it *inside* another modal's body: ui's
|
|
27
|
+
* Modal is a native <dialog>, so nesting one works mechanically and fails no gate —
|
|
28
|
+
* it just looks wrong. Render it as a **sibling** of the other modal instead.
|
|
29
|
+
*
|
|
30
|
+
* Confirmations are `{pending}` state + a rendered sibling modal, never a blocking
|
|
31
|
+
* call: a caller reachable from a keydown handler cannot swap in a boolean.
|
|
32
|
+
*/
|
|
33
|
+
export declare function ConfirmModal({ title, message, onConfirm, onClose, confirmLabel, cancelLabel, destructive, children, }: ConfirmModalProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/** The copy glyph, now from the shared set (`icons.tsx`'s `copy`) rather than
|
|
3
|
+
* colocated: the set exists precisely so this glyph (drawn inline at 21+ sites
|
|
4
|
+
* elsewhere, e.g. `CallFromCodeButton.tsx:44-63`) has one definition. Still
|
|
5
|
+
* exported, and still 14px, because `JsonEditor` and `YamlEditor` reuse it
|
|
6
|
+
* rather than redraw it; `Icon`'s `currentColor` paint is what keeps
|
|
7
|
+
* `.is-copied`'s colour applying with no extra prop. */
|
|
8
|
+
export declare function CopyGlyph(): import("react").JSX.Element;
|
|
9
|
+
/** The copied-state checkmark, same deal (`icons.tsx`'s `check`). */
|
|
10
|
+
export declare function CheckGlyph(): import("react").JSX.Element;
|
|
11
|
+
export interface CopyableProps {
|
|
12
|
+
/** Exact text written to the clipboard. */
|
|
13
|
+
value: string;
|
|
14
|
+
/**
|
|
15
|
+
* How long the checkmark stays before reverting to the copy glyph, in ms.
|
|
16
|
+
*
|
|
17
|
+
* Defaults to the 1500 ms every other copy affordance in the tree already
|
|
18
|
+
* uses — a number worth keeping unless a caller has a reason, because the
|
|
19
|
+
* revert delay is the only feedback that the copy happened at all and an
|
|
20
|
+
* inconsistent one reads as a different control.
|
|
21
|
+
*
|
|
22
|
+
* `0` is not a way to disable the revert: the timer still fires, it just
|
|
23
|
+
* fires on the next tick, so the checkmark is effectively never seen.
|
|
24
|
+
*/
|
|
25
|
+
copiedMs?: number;
|
|
26
|
+
/** Read-only display: a click anywhere in the box copies. Default false ⇒ the icon only. */
|
|
27
|
+
readOnly?: boolean;
|
|
28
|
+
/** Accessible name of the copy button. CONSTANT across states. Default "Copy". */
|
|
29
|
+
label?: string;
|
|
30
|
+
className?: string;
|
|
31
|
+
/** The control that displays `value`: an <input>, <textarea>, or <pre>/<CodeBlock>. */
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Decorates a value-displaying control with an in-box copy affordance — a
|
|
36
|
+
* button at the trailing top/centre that writes `value` to the clipboard, and
|
|
37
|
+
* (when `readOnly`) a click anywhere in the box that does the same.
|
|
38
|
+
*
|
|
39
|
+
* This is the FIRST factored clipboard helper in `@w6w/ui`: every existing
|
|
40
|
+
* copy-to-clipboard call in the tree today (studio's five pages,
|
|
41
|
+
* `CallFromCodeButton`, admin's own `CopyButton`) is an independently authored
|
|
42
|
+
* inline clipboard write — the sole call in this package's `src` now lives in
|
|
43
|
+
* `./use-copy.ts`'s `useCopyToClipboard`, which this component and
|
|
44
|
+
* `JsonEditor` both consume.
|
|
45
|
+
*
|
|
46
|
+
* A decorating component, not a new `TextField`/`TextArea` primitive
|
|
47
|
+
* (HITL-2): the copy behaviour, the glyphs, the box geometry and the copied
|
|
48
|
+
* visual all live in this one place, so a future `TextField` can compose it
|
|
49
|
+
* rather than re-implement it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function Copyable(props: CopyableProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Truncate `value` on a character budget, keeping `chars` VALUE characters and
|
|
3
|
+
* adding {@link MARKER} on top (the marker is extra, not counted against
|
|
4
|
+
* `chars`) — mirrors `page-title.ts`'s `clamp()` in STYLE (a single budget,
|
|
5
|
+
* slice + marker, pure) but NOT its arithmetic: `clamp` slices at
|
|
6
|
+
* `MAX - 1` so its marker counts inside the budget, which is the wrong shape
|
|
7
|
+
* here (see `CopyableText.test.ts`'s fixture table).
|
|
8
|
+
*
|
|
9
|
+
* `chars` omitted, less than 1, or covering the whole value: returned as-is,
|
|
10
|
+
* no marker.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cropText(value: string, chars?: number, crop?: "start" | "end" | "middle"): string;
|
|
13
|
+
export interface CopyableTextProps {
|
|
14
|
+
/** The full string. Always what gets written to the clipboard, regardless
|
|
15
|
+
* of how much of it the cropped display shows. */
|
|
16
|
+
value: string;
|
|
17
|
+
/** How many VALUE characters to show. Omitted, `< 1`, or `>= value.length`
|
|
18
|
+
* ⇒ shown in full. */
|
|
19
|
+
chars?: number;
|
|
20
|
+
/** Where the marker goes. Default `"end"`. */
|
|
21
|
+
crop?: "start" | "end" | "middle";
|
|
22
|
+
/** Accessible name of the copy button. Default "Copy" (per `Copyable`). */
|
|
23
|
+
label?: string;
|
|
24
|
+
className?: string;
|
|
25
|
+
/** Forwarded to `Copyable`. See its own doc for the revert-delay caveat. */
|
|
26
|
+
copiedMs?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A chrome-less, croppable copy-to-clipboard text — for a value too long to
|
|
30
|
+
* show in full inline (an id, a token, a URL fragment) that still needs to be
|
|
31
|
+
* copyable exactly.
|
|
32
|
+
*
|
|
33
|
+
* Composes `Copyable` rather than widening it (`Copyable`'s box chrome has 9
|
|
34
|
+
* existing call sites depending on it) — `readOnly` + the
|
|
35
|
+
* `.w6w-copyable--bare` modifier (`_copyable.scss`) strip the box, and the
|
|
36
|
+
* FULL `value` is what `Copyable` receives, so a click always copies the
|
|
37
|
+
* whole string even when the display is cropped. No `navigator.clipboard`
|
|
38
|
+
* call lives in this file — that stays `Copyable`'s alone.
|
|
39
|
+
*/
|
|
40
|
+
export declare function CopyableText(props: CopyableTextProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface DeleteButtonProps {
|
|
2
|
+
label: string;
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
"data-testid"?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* An `IconButton` bundling the canonical trash glyph — `icons.tsx`'s `delete`,
|
|
10
|
+
* the fuller 4-shape Feather `trash-2` — always `danger`-styled.
|
|
11
|
+
*
|
|
12
|
+
* Presentational only (HITL-1, binding): takes a plain `onClick`, never an
|
|
13
|
+
* `onConfirm`, and never imports any confirm-dialog component — the call
|
|
14
|
+
* site owns whether and which one gates the click.
|
|
15
|
+
*/
|
|
16
|
+
export declare function DeleteButton(props: DeleteButtonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface EditButtonProps {
|
|
2
|
+
label: string;
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
"data-testid"?: string;
|
|
7
|
+
}
|
|
8
|
+
/** An `IconButton` bundling the canonical pencil glyph — `icons.tsx`'s `edit`,
|
|
9
|
+
* the two-path Feather pencil — with no `danger` styling. */
|
|
10
|
+
export declare function EditButton(props: EditButtonProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ExecutionKind } from './ExecutionList.tsx';
|
|
3
|
+
import { ExecutionLogStep } from './ExecutionLogPanel.tsx';
|
|
4
|
+
import { ExecutionStatus } from './StepStatusPill.tsx';
|
|
5
|
+
/**
|
|
6
|
+
* One past execution in full — an already-mapped slice of the host's history
|
|
7
|
+
* payload, the detail-level sibling of `ExecutionListItem`. The HOST maps its
|
|
8
|
+
* own record into this shape; this component never fetches, polls or reaches
|
|
9
|
+
* for an SDK.
|
|
10
|
+
*
|
|
11
|
+
* D2: there is no log-line field anywhere in this shape, on purpose — "logs"
|
|
12
|
+
* for an execution ARE its status, timing, input, output and error, and for a
|
|
13
|
+
* workflow that is the per-step `steps` list below.
|
|
14
|
+
*/
|
|
15
|
+
export interface ExecutionDetailValue {
|
|
16
|
+
id: string;
|
|
17
|
+
kind: ExecutionKind;
|
|
18
|
+
callableName: string;
|
|
19
|
+
status: ExecutionStatus;
|
|
20
|
+
/** ISO-8601 instant the run started. */
|
|
21
|
+
startedAt: string;
|
|
22
|
+
/** ISO-8601 instant the run finished, or `null` while it is still
|
|
23
|
+
* queued/running (rendered as `—`). */
|
|
24
|
+
finishedAt: string | null;
|
|
25
|
+
/** Wall-clock duration once the run has finished, or `null` while it has not
|
|
26
|
+
* (rendered as `—`). */
|
|
27
|
+
durationMs: number | null;
|
|
28
|
+
/** The run's own input, once it is known. `undefined` = "not available" (no
|
|
29
|
+
* section); `null` = "available, and it is null" (section renders `null`). */
|
|
30
|
+
input?: unknown;
|
|
31
|
+
output?: unknown;
|
|
32
|
+
/** The failure's payload for a failed run. `null`/`undefined` = no error
|
|
33
|
+
* section at all — the reverse gate to `input`/`output`, because an error
|
|
34
|
+
* that is `null` is the absence of an error. */
|
|
35
|
+
error?: unknown;
|
|
36
|
+
/** A workflow run's steps. `undefined` = not a step-bearing run (no section);
|
|
37
|
+
* `[]` = it ran and no step did (the panel's own empty state). */
|
|
38
|
+
steps?: ExecutionLogStep[];
|
|
39
|
+
}
|
|
40
|
+
export interface ExecutionDetailProps {
|
|
41
|
+
/** The execution to show, or `null` when there is nothing to show yet. */
|
|
42
|
+
execution: ExecutionDetailValue | null;
|
|
43
|
+
/** `true` while the fetch for a `null` `execution` is still in flight —
|
|
44
|
+
* renders the loading branch. Once an `execution` is present it is rendered
|
|
45
|
+
* as-is: a host re-fetching (polling a running run) keeps showing the last
|
|
46
|
+
* known state rather than flashing back to "Loading…". */
|
|
47
|
+
loading?: boolean;
|
|
48
|
+
/** A failure to surface, e.g. the fetch for this execution failed. Rendered
|
|
49
|
+
* as an alert in EVERY branch — it is about the view, not about the run. */
|
|
50
|
+
errorMessage?: ReactNode;
|
|
51
|
+
/** Supplied ⇒ a dismiss control renders and calls this. Omitted ⇒ no
|
|
52
|
+
* control. */
|
|
53
|
+
onClose?: () => void;
|
|
54
|
+
/** Supplied ⇒ the "Open in visual editor" button renders and calls this.
|
|
55
|
+
* Omitted ⇒ no button (a function/endpoint run has no visual editor to open). */
|
|
56
|
+
onOpenInEditor?: () => void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Everything known about one past execution: which callable it was and how it
|
|
60
|
+
* went, its timing, its own input/output/error, and — for a workflow run — the
|
|
61
|
+
* per-step list.
|
|
62
|
+
*
|
|
63
|
+
* The per-step list sits directly under the timing, above the run's own
|
|
64
|
+
* payloads: for a workflow it is the substance of the view (D2), and burying it
|
|
65
|
+
* under three JSON blocks would make the run read as a function call with
|
|
66
|
+
* appendices.
|
|
67
|
+
*
|
|
68
|
+
* A pure display leaf — no fetching, no polling, no live-ticking timer.
|
|
69
|
+
*/
|
|
70
|
+
export declare function ExecutionDetail({ execution, loading, errorMessage, onClose, onOpenInEditor, }: ExecutionDetailProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ExecutionKind } from './ExecutionList.tsx';
|
|
2
|
+
import { ExecutionStatus } from './StepStatusPill.tsx';
|
|
3
|
+
/**
|
|
4
|
+
* The filter/search state of the history view — one plain object, owned by the
|
|
5
|
+
* HOST. This component is fully controlled: it holds no state of its own, it
|
|
6
|
+
* only renders `value` and reports the next one. Same "host owns the data, the
|
|
7
|
+
* control is presentational" split `ExecutionList` establishes, and the same
|
|
8
|
+
* reason: the host owns where the filters live (URL search params today, a
|
|
9
|
+
* query cache tomorrow) and this leaf must not disagree with it.
|
|
10
|
+
*/
|
|
11
|
+
export interface ExecutionFilterValue {
|
|
12
|
+
/** `""` = "no status filter" (the `Any status` option), never `null`. */
|
|
13
|
+
status: ExecutionStatus | "";
|
|
14
|
+
/** `""` = "no kind filter" (the `Any type` option). Only reachable when the
|
|
15
|
+
* host renders the kind select (`showKind`). */
|
|
16
|
+
kind: ExecutionKind | "";
|
|
17
|
+
/** Inclusive lower bound on the run's start, as `YYYY-MM-DD` — exactly what
|
|
18
|
+
* `input[type=date]` reports and accepts. `""` = unbounded. */
|
|
19
|
+
from: string;
|
|
20
|
+
/** Inclusive upper bound on the run's start, same format. `""` = unbounded. */
|
|
21
|
+
to: string;
|
|
22
|
+
/** Free-text query. D3: the server matches execution id + callable name/key,
|
|
23
|
+
* never payload JSON. */
|
|
24
|
+
q: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ExecutionFiltersProps {
|
|
27
|
+
/** The current filter state — rendered verbatim, never re-derived. */
|
|
28
|
+
value: ExecutionFilterValue;
|
|
29
|
+
/** Called ONCE per user interaction with the ONE field that changed:
|
|
30
|
+
* `{ ...value, <that field>: next }`. No debounce, no batching — the host
|
|
31
|
+
* decides when a request is worth making (it may debounce `q` itself). */
|
|
32
|
+
onChange: (next: ExecutionFilterValue) => void;
|
|
33
|
+
/** `true` ⇒ the kind select renders between the status select and the date
|
|
34
|
+
* bounds. Defaults to `false`: the per-callable history view already knows
|
|
35
|
+
* the kind, so a kind filter there would be a control of one option. */
|
|
36
|
+
showKind?: boolean;
|
|
37
|
+
/** Placeholder for the search box. Defaults to `"Search by id or name"` —
|
|
38
|
+
* the same two fields D3 pins the server-side search to. */
|
|
39
|
+
searchPlaceholder?: string;
|
|
40
|
+
/** `true` ⇒ every control (the clear button included) renders disabled — the
|
|
41
|
+
* state a host uses while a request is already in flight. */
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The history view's filter/search bar: free text, status, (optionally) kind,
|
|
46
|
+
* and a start-date window, plus a Clear control that appears only once there is
|
|
47
|
+
* something to clear.
|
|
48
|
+
*
|
|
49
|
+
* A pure controlled leaf. Every change reports exactly one field's new value,
|
|
50
|
+
* spread over the value it was given — a control that rebuilt the whole object
|
|
51
|
+
* would silently drop a sibling filter the moment the two are edited close
|
|
52
|
+
* together, and the host is the only party that knows the authoritative value.
|
|
53
|
+
*
|
|
54
|
+
* Each control carries its own `aria-label`: the visible layout is one dense
|
|
55
|
+
* row of heterogeneous controls (a search box, three or four dropdowns, two
|
|
56
|
+
* date pickers) with no room for a label per control, so the accessible name is
|
|
57
|
+
* what tells them apart.
|
|
58
|
+
*/
|
|
59
|
+
export declare function ExecutionFilters({ value, onChange, showKind, searchPlaceholder, disabled, }: ExecutionFiltersProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ExecutionStatus } from './StepStatusPill.tsx';
|
|
3
|
+
/** What kind of callable a run belongs to. A thin LOCAL literal — the same
|
|
4
|
+
* deliberate duplication `StepStatusPill`'s unions keep. */
|
|
5
|
+
export type ExecutionKind = "function" | "endpoint" | "workflow";
|
|
6
|
+
/** One past execution's display row — an already-mapped slice of the host's
|
|
7
|
+
* history payload. The HOST maps its own record into this shape (the same
|
|
8
|
+
* "host owns the data, the list is presentational" split `ExecutionLogPanel`
|
|
9
|
+
* establishes): this component never fetches, paginates or reaches for an SDK. */
|
|
10
|
+
export interface ExecutionListItem {
|
|
11
|
+
/** Stable id for this row — what `onSelect` reports and `selectedId` matches. */
|
|
12
|
+
id: string;
|
|
13
|
+
kind: ExecutionKind;
|
|
14
|
+
/** The callable's name/key this run belongs to. */
|
|
15
|
+
callableName: string;
|
|
16
|
+
status: ExecutionStatus;
|
|
17
|
+
/** ISO-8601 instant the run started. */
|
|
18
|
+
startedAt: string;
|
|
19
|
+
/** Wall-clock duration once the run has finished; `null` while it is still
|
|
20
|
+
* queued/running (rendered as `—`). */
|
|
21
|
+
durationMs: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface ExecutionListProps {
|
|
24
|
+
/** The page of past executions, rendered in exactly this order — never re-sorted. */
|
|
25
|
+
items: ExecutionListItem[];
|
|
26
|
+
/** The row to highlight as current. `null`/omitted ⇒ no row is active. */
|
|
27
|
+
selectedId?: string | null;
|
|
28
|
+
/** Supplied ⇒ rows are clickable and report their id here. Omitted ⇒ every
|
|
29
|
+
* row is a plain, non-interactive row. */
|
|
30
|
+
onSelect?: (id: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* `true` ⇒ each row's title is the callable's name and its subtitle carries
|
|
33
|
+
* the kind + start time (the project-wide history view). `false` ⇒ the title
|
|
34
|
+
* is the start time and the subtitle is the run id (the per-callable view,
|
|
35
|
+
* where the callable is already known). Defaults to `false`.
|
|
36
|
+
*/
|
|
37
|
+
showCallable?: boolean;
|
|
38
|
+
/** `true` ⇒ the loading branch while there is nothing to show yet. */
|
|
39
|
+
loading?: boolean;
|
|
40
|
+
/** Shown instead of the list when `items` is empty. */
|
|
41
|
+
emptyLabel?: ReactNode;
|
|
42
|
+
/** Whether a previous page exists — drives the pager's `Previous` state. */
|
|
43
|
+
hasPrev?: boolean;
|
|
44
|
+
/** Whether a next page exists — drives the pager's `Next` state. */
|
|
45
|
+
hasNext?: boolean;
|
|
46
|
+
/** Supplied ⇒ the pager renders and `Previous` calls this. */
|
|
47
|
+
onPrev?: () => void;
|
|
48
|
+
/** Supplied ⇒ the pager renders and `Next` calls this. */
|
|
49
|
+
onNext?: () => void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A paged list of past executions: one row per run, click-to-select, with a
|
|
53
|
+
* prev/next pager.
|
|
54
|
+
*
|
|
55
|
+
* A pure display leaf — no fetching, no polling, no sorting, no local
|
|
56
|
+
* selection state. It renders `items` in the order given, reports a click, and
|
|
57
|
+
* reports a page request; the host owns which page is loaded and which row is
|
|
58
|
+
* selected.
|
|
59
|
+
*/
|
|
60
|
+
export declare function ExecutionList({ items, selectedId, onSelect, showCallable, loading, emptyLabel, hasPrev, hasNext, onPrev, onNext, }: ExecutionListProps): import("react").JSX.Element;
|