@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.
Files changed (143) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +21 -0
  3. package/README.md +260 -2
  4. package/dist/ActionTestForm.d.ts +76 -0
  5. package/dist/AddConnectionModal.d.ts +24 -0
  6. package/dist/AppPicker.d.ts +83 -0
  7. package/dist/CodeBlock-CZu4TFSi.cjs +15 -0
  8. package/dist/CodeBlock-CZu4TFSi.cjs.map +1 -0
  9. package/dist/CodeBlock-Dot3Pd7P.js +2889 -0
  10. package/dist/CodeBlock-Dot3Pd7P.js.map +1 -0
  11. package/dist/CodeBlock.d.ts +65 -0
  12. package/dist/CodeEditor.d.ts +42 -0
  13. package/dist/ConfirmModal-DJPYXE9t.cjs +11 -0
  14. package/dist/ConfirmModal-DJPYXE9t.cjs.map +1 -0
  15. package/dist/ConfirmModal-sY1tzkBO.js +6335 -0
  16. package/dist/ConfirmModal-sY1tzkBO.js.map +1 -0
  17. package/dist/Copyable-1niV9gUa.js +771 -0
  18. package/dist/Copyable-1niV9gUa.js.map +1 -0
  19. package/dist/Copyable-CYZU1o4X.cjs +2 -0
  20. package/dist/Copyable-CYZU1o4X.cjs.map +1 -0
  21. package/dist/JsonEditor.d.ts +60 -0
  22. package/dist/NodeConfigForm.d.ts +70 -0
  23. package/dist/ParamsForm.d.ts +56 -0
  24. package/dist/PropertyEntryForm.d.ts +56 -0
  25. package/dist/RetryPolicyFields.d.ts +18 -0
  26. package/dist/StepBuilderModal.d.ts +375 -0
  27. package/dist/TriggerFillForm.d.ts +52 -0
  28. package/dist/WaitEditor.d.ts +6 -0
  29. package/dist/WorkflowFlowEditor.d.ts +119 -0
  30. package/dist/YamlEditor.d.ts +46 -0
  31. package/dist/app-categories.d.ts +38 -0
  32. package/dist/app-pages.d.ts +111 -0
  33. package/dist/code.cjs +2 -0
  34. package/dist/code.cjs.map +1 -0
  35. package/dist/code.d.ts +29 -0
  36. package/dist/code.mjs +7 -0
  37. package/dist/code.mjs.map +1 -0
  38. package/dist/components/ApiCallsPanel.d.ts +41 -0
  39. package/dist/components/AppIcon.d.ts +25 -0
  40. package/dist/components/AuthFieldsForm.d.ts +22 -0
  41. package/dist/components/Combobox.d.ts +24 -0
  42. package/dist/components/ConfirmModal.d.ts +33 -0
  43. package/dist/components/Copyable.d.ts +51 -0
  44. package/dist/components/CopyableText.d.ts +40 -0
  45. package/dist/components/DeleteButton.d.ts +16 -0
  46. package/dist/components/EditButton.d.ts +10 -0
  47. package/dist/components/ExecutionDetail.d.ts +70 -0
  48. package/dist/components/ExecutionFilters.d.ts +59 -0
  49. package/dist/components/ExecutionList.d.ts +60 -0
  50. package/dist/components/ExecutionLogPanel.d.ts +98 -0
  51. package/dist/components/ExecutionStats.d.ts +47 -0
  52. package/dist/components/ExpressionEditorModal.d.ts +42 -0
  53. package/dist/components/ExpressionInput.d.ts +36 -0
  54. package/dist/components/ExpressionOptions.d.ts +185 -0
  55. package/dist/components/HealthStatusPill.d.ts +25 -0
  56. package/dist/components/HistoryTimeline.d.ts +56 -0
  57. package/dist/components/Icon.d.ts +34 -0
  58. package/dist/components/IconButton.d.ts +60 -0
  59. package/dist/components/InfoTip.d.ts +15 -0
  60. package/dist/components/InternalIcon.d.ts +19 -0
  61. package/dist/components/ListItem.d.ts +25 -0
  62. package/dist/components/Modal.d.ts +29 -0
  63. package/dist/components/RepoSyncIndicator.d.ts +29 -0
  64. package/dist/components/ResolvedParams.d.ts +31 -0
  65. package/dist/components/ServerResources.d.ts +47 -0
  66. package/dist/components/StepStatusPill.d.ts +51 -0
  67. package/dist/components/UptimeStrip.d.ts +56 -0
  68. package/dist/components/execution-format.d.ts +24 -0
  69. package/dist/components/expression-dom.d.ts +154 -0
  70. package/dist/components/expression-template.d.ts +86 -0
  71. package/dist/components/history-scale.d.ts +33 -0
  72. package/dist/components/icons.d.ts +41 -0
  73. package/dist/components/resolved-clip.d.ts +42 -0
  74. package/dist/components/server-resources-format.d.ts +68 -0
  75. package/dist/components/server-resources.fixture.d.ts +9 -0
  76. package/dist/components/use-copy.d.ts +14 -0
  77. package/dist/createW6WApi.d.ts +31 -0
  78. package/dist/flow-connect.d.ts +138 -0
  79. package/dist/flow-fanout.d.ts +15 -0
  80. package/dist/flow-types.d.ts +356 -0
  81. package/dist/flow-utils.d.ts +284 -0
  82. package/dist/flow.cjs +3 -0
  83. package/dist/flow.cjs.map +1 -0
  84. package/dist/flow.d.ts +22 -0
  85. package/dist/flow.mjs +1977 -0
  86. package/dist/flow.mjs.map +1 -0
  87. package/dist/index.cjs +2 -0
  88. package/dist/index.cjs.map +1 -0
  89. package/dist/index.d.ts +94 -0
  90. package/dist/index.mjs +1811 -0
  91. package/dist/index.mjs.map +1 -0
  92. package/dist/oauth-popup.d.ts +17 -0
  93. package/dist/output-shape.d.ts +58 -0
  94. package/dist/provider.d.ts +420 -0
  95. package/dist/resolve-params.d.ts +112 -0
  96. package/dist/resolved-json.d.ts +21 -0
  97. package/dist/run-visuals.d.ts +90 -0
  98. package/dist/step-preview-state.d.ts +143 -0
  99. package/dist/theme.d.ts +32 -0
  100. package/dist/trigger-fields.d.ts +56 -0
  101. package/dist/types.d.ts +413 -0
  102. package/dist/ui.css +1 -0
  103. package/dist/use-app-action-defs.d.ts +7 -0
  104. package/dist/use-enter-submit.d.ts +23 -0
  105. package/dist/use-seed-sources.d.ts +16 -0
  106. package/package.json +111 -3
  107. package/src/code.css +542 -0
  108. package/src/styles/_buttons.scss +38 -0
  109. package/src/styles/_chips.scss +210 -0
  110. package/src/styles/_code.scss +139 -0
  111. package/src/styles/_copyable.scss +147 -0
  112. package/src/styles/_data-vars.scss +38 -0
  113. package/src/styles/_execution-history.scss +282 -0
  114. package/src/styles/_execution-log.scss +178 -0
  115. package/src/styles/_expression-field.scss +65 -0
  116. package/src/styles/_expression-inline.scss +63 -0
  117. package/src/styles/_expression-modal.scss +292 -0
  118. package/src/styles/_fields.scss +161 -0
  119. package/src/styles/_flow.scss +217 -0
  120. package/src/styles/_fx.scss +158 -0
  121. package/src/styles/_health.scss +46 -0
  122. package/src/styles/_history-timeline.scss +156 -0
  123. package/src/styles/_icon-button.scss +22 -0
  124. package/src/styles/_icon.scss +15 -0
  125. package/src/styles/_icons.scss +31 -0
  126. package/src/styles/_incoming-state.scss +46 -0
  127. package/src/styles/_info-tip.scss +9 -0
  128. package/src/styles/_layout.scss +6 -0
  129. package/src/styles/_lists.scss +64 -0
  130. package/src/styles/_modal.scss +125 -0
  131. package/src/styles/_multiselect.scss +69 -0
  132. package/src/styles/_repo-sync-indicator.scss +99 -0
  133. package/src/styles/_scale.scss +70 -0
  134. package/src/styles/_sections.scss +36 -0
  135. package/src/styles/_server-resources.scss +163 -0
  136. package/src/styles/_step-builder.scss +376 -0
  137. package/src/styles/_step-config.scss +195 -0
  138. package/src/styles/_tabs.scss +54 -0
  139. package/src/styles/_tester.scss +111 -0
  140. package/src/styles/_tokens.scss +141 -0
  141. package/src/styles/_uptime.scss +61 -0
  142. package/src/styles.css +4208 -0
  143. 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,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./CodeBlock-CZu4TFSi.cjs"),o=require("./Copyable-CYZU1o4X.cjs");exports.CodeBlock=e.CodeBlock;exports.Copyable=o.Copyable;
2
+ //# sourceMappingURL=code.cjs.map
@@ -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,7 @@
1
+ import { C as r } from "./CodeBlock-Dot3Pd7P.js";
2
+ import { C as a } from "./Copyable-1niV9gUa.js";
3
+ export {
4
+ r as CodeBlock,
5
+ a as Copyable
6
+ };
7
+ //# sourceMappingURL=code.mjs.map
@@ -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;