@parallelworks/ui 0.15.0 → 0.17.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 (38) hide show
  1. package/dist/chunks/{CodePreviewEditor-DuMZMA_k.js → CodePreviewEditor-UAtnpmOV.js} +1 -1
  2. package/dist/chunks/{CreateModal-B7smkHkv.js → CreateModal-BbV5cTj7.js} +3 -3
  3. package/dist/chunks/{Monaco-BXDH2jVj.js → Monaco-DVyIpyv4.js} +485 -172
  4. package/dist/chunks/{PageHeader-CoZWF0pJ.js → PageHeader-MxuOs9cH.js} +1 -1
  5. package/dist/chunks/{Provider-CbFVFB7O.js → Provider-DHmZ3v9i.js} +28 -2
  6. package/dist/chunks/{StatusBadge-zvEtK16a.js → StatusBadge-C1Blx_cW.js} +23 -6
  7. package/dist/chunks/{SwitchToggle-3V836Cn7.js → SwitchToggle-BRQoEwLZ.js} +7 -4
  8. package/dist/chunks/{Table-CutP1bRt.js → Table-C6JdFFiJ.js} +1 -1
  9. package/dist/chunks/{editor-Ko3zX22Y.js → editor-mNznodJN.js} +2 -2
  10. package/dist/chunks/{list-CduoUsMW.js → list-7k0eaI5N.js} +21 -19
  11. package/dist/components/Button.d.ts +2 -1
  12. package/dist/components/Provider.d.ts +57 -2
  13. package/dist/components/SectionHeader.d.ts +3 -1
  14. package/dist/components/StatusBadge.d.ts +7 -2
  15. package/dist/components/relativeTime.d.ts +15 -0
  16. package/dist/editor/index.js +1 -1
  17. package/dist/editor/usesGitlab.d.ts +97 -0
  18. package/dist/file-explorer/index.js +253 -253
  19. package/dist/file-explorer/lib/paging.d.ts +27 -28
  20. package/dist/file-explorer/lib/types.d.ts +0 -1
  21. package/dist/file-explorer/lib/utils.d.ts +16 -5
  22. package/dist/form/index.js +5 -5
  23. package/dist/form/types/workflow-schema.d.ts +38 -0
  24. package/dist/index.d.ts +4 -2
  25. package/dist/index.js +42 -11
  26. package/dist/list/ListPage.d.ts +3 -1
  27. package/dist/list/ListPager.d.ts +3 -1
  28. package/dist/list/ListTable.d.ts +2 -1
  29. package/dist/list/index.js +2 -2
  30. package/dist/list/listView.d.ts +1 -1
  31. package/dist/logviewer/index.js +1 -1
  32. package/dist/styles/theme.css +14 -12
  33. package/dist/styles.css +1 -1
  34. package/dist/workflow/DependencyGraph.d.ts +2 -0
  35. package/dist/workflow/index.d.ts +1 -0
  36. package/dist/workflow/index.js +3 -2
  37. package/dist/workflow/types.d.ts +5 -0
  38. package/package.json +4 -4
@@ -7,11 +7,10 @@ export type TListPageRequest = {
7
7
  /** Overridable so a test can page without seeding 2,000 objects. */
8
8
  pageSize?: number;
9
9
  };
10
- /** Keyed by tree path. A storage's flat `objects` bag cannot say whether a directory
11
- * was listed at all, only whether anything landed under it. */
10
+ /** Keyed by tree path. */
12
11
  export type TDirectoryListing = {
13
12
  /** Present ⇒ more entries exist and the provider can resume from here. */
14
- cursor?: string;
13
+ cursor?: string | undefined;
15
14
  /** 0 ⇒ never listed, which is what tells "empty" apart from "not asked yet". */
16
15
  pagesLoaded: number;
17
16
  /** Not `loadingPaths`, which swaps the whole table for a skeleton and would blank
@@ -19,7 +18,9 @@ export type TDirectoryListing = {
19
18
  loadingMore: boolean;
20
19
  /** The storage-level error surfaces only on an empty folder, so without this a
21
20
  * failure mid-folder is invisible. */
22
- error?: string;
21
+ error?: string | undefined;
22
+ /** A new array per page, never mutated: the builder reuses work by identity. */
23
+ entries: readonly TStorageObject[];
23
24
  };
24
25
  /** Uncapped, opening a 200k-object folder and scrolling would walk all of it. */
25
26
  export declare const MAX_AUTO_PAGES = 5;
@@ -32,20 +33,20 @@ export declare function canAutoLoadMore(listings: TListings, path: string): bool
32
33
  export declare function isLoadingMore(listings: TListings, path: string): boolean;
33
34
  export declare function loadMoreError(listings: TListings, path: string): string | undefined;
34
35
  export declare function beginLoadingMore(listings: TListings, path: string): TListings;
35
- /** `expectedPagesLoaded` is captured before the request: a mismatch means a refresh
36
- * reset this directory while the page was in flight. */
37
- export declare function advanceListing(listings: TListings, path: string, page: {
38
- cursor?: string;
39
- }, expectedPagesLoaded: number): TListings;
40
- /** Always a new map, since the hydration walk only re-runs on a `listings` change.
41
- * `pagesLoaded` stays put, so a failed first page still reads as unlisted. */
36
+ type TListPage = {
37
+ cursor?: string | undefined;
38
+ entries: readonly TStorageObject[];
39
+ };
40
+ export declare function advanceListing(listings: TListings, path: string, page: TListPage): TListings;
41
+ /** Subfolders the page no longer names lose their records, or a re-created folder
42
+ * would show old contents; the rest keep theirs, since a refresh lists them
43
+ * alongside this one and a parent landing later must not undo a child's page. */
44
+ export declare function replaceListing(listings: TListings, path: string, page: TListPage): TListings;
45
+ /** `pagesLoaded` stays put, so a failed first page still reads as unlisted. */
42
46
  export declare function recordListingError(listings: TListings, path: string, error: string): TListings;
43
- /** Slash-terminates the prefix: without it, clearing `logs` would also clear
44
- * `logs-archive/`. */
47
+ /** Keeps the cursor and pages, so a retry resumes paging instead of starting over. */
48
+ export declare function clearListingError(listings: TListings, path: string): TListings;
45
49
  export declare function clearListingsUnder(listings: TListings, path: string): TListings;
46
- /** The same prefix rule for the attempt sets that shadow `listings`. They gate
47
- * re-listing, so a path left behind here reads as tried-and-empty forever. */
48
- export declare function forgetPathsUnder(paths: Set<string>, path: string): void;
49
50
  /** Tree paths whose children should keep arrival order, since sorting them would
50
51
  * reshuffle rows under the user mid-scroll. */
51
52
  export declare function incompletePaths(listings: TListings): Set<string>;
@@ -62,15 +63,18 @@ type THydrationStep =
62
63
  | {
63
64
  kind: 'more';
64
65
  path: string;
65
- } | {
66
+ }
67
+ /** The deepest directory reached. */
68
+ | {
66
69
  kind: 'stuck';
70
+ path: string;
67
71
  }
68
72
  /** Either resolved, or a request is already in flight. */
69
73
  | {
70
74
  kind: 'done';
71
75
  };
72
76
  /** What a deep link needs next. Pure so the walk is table-testable. */
73
- export declare function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings, inFlight, attempted, pagesPulled, }: {
77
+ export declare function nextHydrationStep({ targetResolved, ancestors, isListableDir, listings, inFlight, pagesPulled, }: {
74
78
  targetResolved: boolean;
75
79
  /** Directory paths from the storage root down to the target. */
76
80
  ancestors: readonly string[];
@@ -78,16 +82,11 @@ export declare function nextHydrationStep({ targetResolved, ancestors, isListabl
78
82
  * introduced yet. */
79
83
  isListableDir: (path: string) => boolean;
80
84
  listings: TListings;
81
- /** Must not be a state value: `attempted` is a ref, so a state-backed signal would
82
- * lag it by a render and make an in-flight ancestor read as stuck. */
83
- inFlight: ReadonlySet<string>;
84
- attempted: ReadonlySet<string>;
85
+ /** Must not be a state value: it would lag the claim by a render and make an
86
+ * in-flight ancestor read as stuck. */
87
+ inFlight: {
88
+ has(path: string): boolean;
89
+ };
85
90
  pagesPulled: number;
86
91
  }): THydrationStep;
87
- /** `replace` drops the directory's previous contents first, which is how a refresh
88
- * sheds deleted objects rather than re-adding them. */
89
- export declare function nextObjects(previous: TStorageObject[], page: TStorageObject[], options: {
90
- replace?: boolean;
91
- dirPath: string;
92
- }): TStorageObject[];
93
92
  export {};
@@ -16,7 +16,6 @@ export type TStorage = {
16
16
  canShare?: boolean | undefined;
17
17
  canManageAccess?: boolean | undefined;
18
18
  supportsPwUri?: boolean | undefined;
19
- objects?: TStorageObject[];
20
19
  };
21
20
  export type TStorageObject = {
22
21
  path: string;
@@ -1,14 +1,23 @@
1
1
  import type { IFileExplorerClient } from './fileExplorer.js';
2
- import type { TStorage, TreeMap, TreeNode, UploadNode } from './types.js';
2
+ import type { TStorage, TStorageObject, TreeMap, TreeNode, UploadNode } from './types.js';
3
3
  export declare function formatFileSize(bytes: number): string;
4
4
  export declare function getFileExtension(filename: string): string | null;
5
- export declare function buildTreeFromUserStorages(storages: TStorage[], options?: {
6
- forceUserHierarchy?: boolean;
7
- unsortedParents?: ReadonlySet<string>;
8
- }): {
5
+ export declare function getNodeName(node: TStorageObject): string;
6
+ export type TTree = {
9
7
  treeMap: TreeMap;
10
8
  parentToChildrenMap: Record<string, TreeNode[]>;
9
+ rootNodes: TreeNode[];
10
+ };
11
+ export type TTreeOptions = {
12
+ listings: ReadonlyMap<string, {
13
+ readonly entries: readonly TStorageObject[];
14
+ }>;
15
+ forceUserHierarchy?: boolean;
16
+ unsortedParents?: ReadonlySet<string>;
11
17
  };
18
+ /** One accumulator per listed directory, so a landed page costs the page and not
19
+ * the tree. One builder per explorer instance. */
20
+ export declare function createTreeBuilder(): (storages: TStorage[], options: TTreeOptions) => TTree;
12
21
  export declare function getNodeChildren(parentToChildrenMap: Record<string, TreeNode[]>, parentPath: string): TreeNode[];
13
22
  export declare function getParentPath(currentPath: string): string;
14
23
  export type DirectoryNameError = 'reserved' | 'separator' | 'exists';
@@ -26,8 +35,10 @@ export declare function pruneNodesInsideSelectedDirectories(nodes: TreeNode[]):
26
35
  export declare function collectObjectKeysToDelete(nodes: TreeNode[], listKeysUnderPrefix: (prefix: string) => Promise<string[]>): Promise<string[]>;
27
36
  export declare function getPwUri(username: string, pwName: string, key: string): string;
28
37
  export declare function getCspUri(csp: string, cspBucketName: string, key: string): string | null;
38
+ export declare function getUriScheme(uri: string): string;
29
39
  export declare function removeLeadingSlash(path: string): string;
30
40
  export declare function removeLeadingAndTrailingSlashes(path: string): string;
41
+ export declare function ensureTrailingSlash(path: string): string;
31
42
  export declare function isClientValid(client: IFileExplorerClient): boolean;
32
43
  export declare function getUploadSessionETA(totalLoadedBytes: number, totalSizeBytes: number, lastProgressTime?: number, lastProgressBytes?: number): {
33
44
  estimatedSecondsLeft?: number;
@@ -1,10 +1,10 @@
1
1
  import { AngleRightIcon, EyeIcon, EyeOffIcon, SuccessCheckmark, TrashIcon } from "../icons.js";
2
- import { c as useStrings, s as useSlots } from "../chunks/Provider-CbFVFB7O.js";
2
+ import { l as useSlots, u as useStrings } from "../chunks/Provider-DHmZ3v9i.js";
3
3
  import { n as TOOLTIP_ID, r as TooltipInfo } from "../chunks/Tooltip-n9w7Tkt1.js";
4
- import { n as StatusDot, s as isCategory } from "../chunks/StatusBadge-zvEtK16a.js";
5
- import { a as UncontrolledCollapsiblePanel, c as Dropdown, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "../chunks/SwitchToggle-3V836Cn7.js";
4
+ import { c as isCategory, n as StatusDot } from "../chunks/StatusBadge-C1Blx_cW.js";
5
+ import { a as UncontrolledCollapsiblePanel, c as Dropdown, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "../chunks/SwitchToggle-BRQoEwLZ.js";
6
6
  import { t as Loader } from "../chunks/Loader-BXoXTZGc.js";
7
- import { n as Table } from "../chunks/Table-CutP1bRt.js";
7
+ import { n as Table } from "../chunks/Table-C6JdFFiJ.js";
8
8
  import { a as resolvedFlag, c as FieldWrapper, d as useFieldLabelledByProps, f as useFieldRequired, i as initializeValues, l as FieldProvider, n as flattenGroups, o as applySecondaryField, r as impureSetValueFromPath, s as findSecondaryOption, t as enforceOneMustBeTrue, u as useFieldControlProps } from "../chunks/lib-CUTRDpa6.js";
9
9
  import cx from "classnames";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -2276,7 +2276,7 @@ function DynamicForm({ formJSONs: options = {}, reinitialize = false, initialVal
2276
2276
  },
2277
2277
  ...formikRef ? { innerRef: formikRef } : {},
2278
2278
  children: ({ values }) => /* @__PURE__ */ jsx(Form, {
2279
- className: "pw-form w-full text-[13px]",
2279
+ className: "w-full text-[13px]",
2280
2280
  children: /* @__PURE__ */ jsx(DynamicFormContent, {
2281
2281
  values,
2282
2282
  options,
@@ -121,6 +121,44 @@ export interface WorkflowSchema {
121
121
  detach?: string | boolean;
122
122
  };
123
123
  };
124
+ /**
125
+ * Links the run page shows, pointing at sessions the workflow registers itself or at addresses elsewhere.
126
+ */
127
+ links?: {
128
+ /**
129
+ * This interface was referenced by `undefined`'s JSON-Schema definition
130
+ * via the `patternProperty` "^[a-z0-9_-]*[a-z0-9]$".
131
+ */
132
+ [k: string]:
133
+ | {
134
+ /**
135
+ * Name of the endpoint session the workflow registers, resolved once it comes online.
136
+ */
137
+ endpoint: string;
138
+ /**
139
+ * If true, the user is redirected to this link once the workflow runs. Only one session or link may set it.
140
+ */
141
+ redirect?: string | boolean;
142
+ /**
143
+ * If true, the session this link names outlives the run instead of being removed with it.
144
+ */
145
+ detach?: string | boolean;
146
+ }
147
+ | {
148
+ /**
149
+ * An http:// or https:// address to link to directly. A value with no scheme is read as https.
150
+ */
151
+ url: string;
152
+ /**
153
+ * If true, the user is redirected to this link once the workflow runs. Only one session or link may set it.
154
+ */
155
+ redirect?: string | boolean;
156
+ /**
157
+ * If true, a session this link addresses outlives the run instead of being removed with it.
158
+ */
159
+ detach?: string | boolean;
160
+ };
161
+ };
124
162
  /**
125
163
  * environment variables to use for this workflow
126
164
  */
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { default as CustomListbox } from './components/Listbox.js';
13
13
  export { default as Loader } from './components/Loader.js';
14
14
  export { default as Markdown } from './components/Markdown.js';
15
15
  export type { MarkdownProps } from './components/Markdown.js';
16
+ export type { GitlabProject, RepoEntry, RepoOwner, RepoRef, RepoSummary, } from './components/Provider.js';
16
17
  export { BareModal, modalPanelClasses } from './components/BareModal.js';
17
18
  export { ConfirmModal } from './components/ConfirmModal.js';
18
19
  export { CREATE_MODAL_SELECT_FILTER_THRESHOLD, CreateModal, CreateModalAutocompleteField, CreateModalField, CreateModalSelect, type CreateModalSelectOption, CreateModalSwitch, CreateModalTextarea, } from './components/CreateModal.js';
@@ -20,13 +21,14 @@ export { AddMenu, type HeaderAddMenuItem } from './components/AddMenu.js';
20
21
  export { dangerButtonClasses, ghostButtonClasses, primaryButtonClasses, } from './components/ghostButton.js';
21
22
  export { default as MultiSelectDropdown } from './components/MultiSelect.js';
22
23
  export { Overview } from './components/Overview.js';
23
- export { UIProvider, useNavigation, useNotify, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowJsonResolver, type RunFileResult, type WorkflowJsonRef, type UIData, type UINavigation, type UINotify, type UISlots, type UIStrings, } from './components/Provider.js';
24
+ export { UIProvider, useNavigation, useNotify, usePersistedState, useProvisionCorsRules, useRepoSuggestions, useRunFile, useSlots, useStrings, useWorkflowJsonResolver, type PersistedStateHook, type RunFileResult, type WorkflowJsonRef, type UIData, type UINavigation, type UINotify, type UISlots, type UIStrings, } from './components/Provider.js';
24
25
  export { useCssIsDark } from './components/useCssIsDark.js';
25
26
  export { Indicator } from './components/Indicator.js';
26
27
  export { ControlledCollapsiblePanel, MaybeCollapsible, UncontrolledCollapsiblePanel, } from './components/CollapsiblePanel.js';
27
28
  export { default as SectionHeader } from './components/SectionHeader.js';
28
29
  export { default as SwitchToggleSmall } from './components/SwitchToggleSmall.js';
29
- export { StatusBadge, StatusDot } from './components/StatusBadge.js';
30
+ export { StatusBadge, StatusDot, statusTextClass, type BadgeVariant, } from './components/StatusBadge.js';
31
+ export { useRelativeTime } from './components/relativeTime.js';
30
32
  export { default as SwitchToggle } from './components/SwitchToggle.js';
31
33
  export { CompactTable, Table } from './components/Table.js';
32
34
  export { formatTooltipContent, GlobalTooltip, TOOLTIP_ID, TooltipInfo, truncationTooltipProps, } from './components/Tooltip.js';
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  import { DEFAULT_PRESET, THEME_PRESETS, THEME_TOKENS, applyTheme, contrastRatio, deriveTheme, isDarkColor } from "./theme/index.js";
2
2
  import { AlertIcon, AngleRightIcon, EyeIcon, EyeOffIcon, FilterIcon, LoaderIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon } from "./icons.js";
3
- import { a as CreateModalSelect, c as ConfirmModal, d as primaryButtonClasses, f as Markdown, h as Callout, i as CreateModalField, l as dangerButtonClasses, m as CopyToClipboard, n as CreateModal, o as CreateModalSwitch, p as CopyCodeBlock, r as CreateModalAutocompleteField, s as CreateModalTextarea, t as CREATE_MODAL_SELECT_FILTER_THRESHOLD, u as ghostButtonClasses } from "./chunks/CreateModal-B7smkHkv.js";
4
- import { a as useProvisionCorsRules, c as useStrings, i as useNotify, l as useWorkflowJsonResolver, n as useLink, o as useRunFile, r as useNavigation, s as useSlots, t as UIProvider } from "./chunks/Provider-CbFVFB7O.js";
3
+ import { a as CreateModalSelect, c as ConfirmModal, d as primaryButtonClasses, f as Markdown, h as Callout, i as CreateModalField, l as dangerButtonClasses, m as CopyToClipboard, n as CreateModal, o as CreateModalSwitch, p as CopyCodeBlock, r as CreateModalAutocompleteField, s as CreateModalTextarea, t as CREATE_MODAL_SELECT_FILTER_THRESHOLD, u as ghostButtonClasses } from "./chunks/CreateModal-BbV5cTj7.js";
4
+ import { a as usePersistedState, c as useRunFile, d as useWorkflowJsonResolver, i as useNotify, l as useSlots, n as useLink, o as useProvisionCorsRules, r as useNavigation, s as useRepoSuggestions, t as UIProvider, u as useStrings } from "./chunks/Provider-DHmZ3v9i.js";
5
5
  import { a as truncationTooltipProps, i as formatTooltipContent, n as TOOLTIP_ID, r as TooltipInfo, t as GlobalTooltip } from "./chunks/Tooltip-n9w7Tkt1.js";
6
- import { c as isOption, i as filterOption, l as toggleSetMember, n as StatusDot, o as flattenOptions, r as DropdownCaret, s as isCategory, t as StatusBadge } from "./chunks/StatusBadge-zvEtK16a.js";
7
- import { a as UncontrolledCollapsiblePanel, c as Dropdown, i as MaybeCollapsible, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "./chunks/SwitchToggle-3V836Cn7.js";
6
+ import { a as filterOption, c as isCategory, i as DropdownCaret, l as isOption, n as StatusDot, r as statusTextClass, s as flattenOptions, t as StatusBadge, u as toggleSetMember } from "./chunks/StatusBadge-C1Blx_cW.js";
7
+ import { a as UncontrolledCollapsiblePanel, c as Dropdown, i as MaybeCollapsible, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "./chunks/SwitchToggle-BRQoEwLZ.js";
8
8
  import { t as Loader } from "./chunks/Loader-BXoXTZGc.js";
9
9
  import { n as modalPanelClasses, t as BareModal } from "./chunks/BareModal-BqroLbZ5.js";
10
- import { C as useSetDefaultBreadcrumbs, S as useSetBreadcrumbs, a as HeaderAddButton, b as useClearBreadcrumbs, c as PageHeader, i as HeaderActionMenu, l as headerActionButtonClasses, n as BreadcrumbsRightAction, o as HeaderEditButton, r as BreadcrumbsTitleAction, s as HeaderRowMenu, t as BreadcrumbsActionButton, v as BreadcrumbProvider, w as AddMenu, x as useHideBreadcrumbs, y as useBreadcrumb } from "./chunks/PageHeader-CoZWF0pJ.js";
10
+ import { C as useSetDefaultBreadcrumbs, S as useSetBreadcrumbs, a as HeaderAddButton, b as useClearBreadcrumbs, c as PageHeader, i as HeaderActionMenu, l as headerActionButtonClasses, n as BreadcrumbsRightAction, o as HeaderEditButton, r as BreadcrumbsTitleAction, s as HeaderRowMenu, t as BreadcrumbsActionButton, v as BreadcrumbProvider, w as AddMenu, x as useHideBreadcrumbs, y as useBreadcrumb } from "./chunks/PageHeader-MxuOs9cH.js";
11
11
  import { t as useCssIsDark } from "./chunks/useCssIsDark-DHr05dG2.js";
12
12
  import { t as Indicator } from "./chunks/Indicator-hBSIxOPK.js";
13
13
  import { t as SwitchToggleSmall } from "./chunks/SwitchToggleSmall-FcsaYSTs.js";
14
- import { n as Table, t as CompactTable } from "./chunks/Table-CutP1bRt.js";
14
+ import { n as Table, t as CompactTable } from "./chunks/Table-C6JdFFiJ.js";
15
15
  import { t as RequiredMark } from "./chunks/RequiredMark-DfLdYbYZ.js";
16
16
  import cx from "classnames";
17
17
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
18
- import React, { forwardRef, useId, useState } from "react";
18
+ import React, { forwardRef, useEffect, useId, useState } from "react";
19
19
  import Skeleton from "react-loading-skeleton";
20
+ import { DateTime } from "luxon";
20
21
  //#region src/components/DescriptionList.tsx
21
22
  function DescriptionListItem({ label, children, tooltip, className, ...props }) {
22
23
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("dt", {
@@ -114,6 +115,34 @@ function Overview({ Icon, name, type, children, right, className, loading, iconS
114
115
  });
115
116
  }
116
117
  //#endregion
118
+ //#region src/components/relativeTime.ts
119
+ var TICK_MS = 3e4;
120
+ function compactRelativeMinutes(minutes, t) {
121
+ if (!Number.isFinite(minutes) || minutes < 1) return t.now;
122
+ if (minutes < 60) return t.minutes(minutes);
123
+ const hours = Math.floor(minutes / 60);
124
+ if (hours < 24) return t.hours(hours);
125
+ const days = Math.floor(hours / 24);
126
+ if (days < 365) return t.days(days);
127
+ return t.years(Math.floor(days / 365));
128
+ }
129
+ /** A clock that re-reads itself, so "5m" ages while the page sits open, with
130
+ * the abbreviated form a row has room for. */
131
+ function useRelativeTime() {
132
+ const t = useStrings().time;
133
+ const [now, setNow] = useState(() => DateTime.now());
134
+ useEffect(() => {
135
+ const id = setInterval(() => setNow(DateTime.now()), TICK_MS);
136
+ return () => clearInterval(id);
137
+ }, []);
138
+ const compactMinutes = (minutes) => compactRelativeMinutes(minutes, t);
139
+ return {
140
+ now,
141
+ compactMinutes,
142
+ compact: (iso) => iso ? compactMinutes(Math.floor(now.diff(DateTime.fromISO(iso)).as("minutes"))) : ""
143
+ };
144
+ }
145
+ //#endregion
117
146
  //#region src/components/Button.tsx
118
147
  var Button = forwardRef(({ children, variant = "primary", size = "default", loading, icon, iconPosition = "right", fullWidth = true, className = "", disabled, ...props }, ref) => {
119
148
  const baseClasses = "inline-flex items-center justify-center gap-2 font-semibold rounded-lg transition-all duration-200 cursor-pointer border-none mt-2 disabled:opacity-50 disabled:cursor-not-allowed";
@@ -149,9 +178,10 @@ var Button = forwardRef(({ children, variant = "primary", size = "default", load
149
178
  });
150
179
  });
151
180
  Button.displayName = "Button";
152
- function MethodButton({ icon, label, description, href, className = "", ...props }) {
181
+ function MethodButton({ icon, label, description, href, loading, disabled, className = "", ...props }) {
153
182
  const Link = useLink();
154
183
  const baseClasses = "flex items-center w-full p-4 bg-[var(--theme-muted-panel-bg)] border border-[var(--theme-border)] rounded-xl text-[var(--theme-app)] text-[0.9375rem] font-medium cursor-pointer transition-all duration-200 no-underline mb-3 last:mb-0 hover:bg-[var(--theme-border)] hover:border-[var(--theme-muted-text-color)] hover:-translate-y-0.5 active:translate-y-0";
184
+ const disabledClasses = "disabled:opacity-60 disabled:cursor-not-allowed disabled:hover:bg-[var(--ds-muted)] disabled:hover:border-[var(--ds-border)] disabled:hover:translate-y-0";
155
185
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
156
186
  icon && /* @__PURE__ */ jsx("span", {
157
187
  className: "size-10 rounded-lg bg-gradient-to-br from-[var(--gradient-start,var(--theme-element))] to-[var(--gradient-mid,var(--theme-link))] flex items-center justify-center shrink-0 mr-4 [&_svg]:size-5 [&_svg]:text-white",
@@ -167,7 +197,7 @@ function MethodButton({ icon, label, description, href, className = "", ...props
167
197
  children: description
168
198
  })]
169
199
  }),
170
- /* @__PURE__ */ jsx(AngleRightIcon, { className: "size-5 text-[var(--theme-muted-text-color)] shrink-0 ml-2 transition-all duration-200 group-hover:translate-x-[3px] group-hover:text-[var(--theme-app)]" })
200
+ loading ? /* @__PURE__ */ jsx(LoaderIcon, { className: "size-5 text-[var(--theme-muted-text-color)] shrink-0 ml-2" }) : /* @__PURE__ */ jsx(AngleRightIcon, { className: "size-5 text-[var(--theme-muted-text-color)] shrink-0 ml-2 transition-all duration-200 group-hover:translate-x-[3px] group-hover:text-[var(--theme-app)]" })
171
201
  ] });
172
202
  if (href) {
173
203
  if (href.startsWith("/api/") || href.startsWith("http")) return /* @__PURE__ */ jsx("a", {
@@ -183,7 +213,8 @@ function MethodButton({ icon, label, description, href, className = "", ...props
183
213
  }
184
214
  return /* @__PURE__ */ jsx("button", {
185
215
  type: "button",
186
- className: cx("group", baseClasses, className),
216
+ className: cx("group", baseClasses, disabledClasses, className),
217
+ disabled: disabled || loading,
187
218
  ...props,
188
219
  children: content
189
220
  });
@@ -566,4 +597,4 @@ function SettingModeOption({ name, checked, onSelect, label, description, isFirs
566
597
  });
567
598
  }
568
599
  //#endregion
569
- export { AddMenu, BareModal, BreadcrumbProvider, BreadcrumbsActionButton, BreadcrumbsRightAction, BreadcrumbsTitleAction, Button, CREATE_MODAL_SELECT_FILTER_THRESHOLD, Callout, Card, CardHeader, CompactTable, ConfirmModal, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CreateModal, CreateModalAutocompleteField, CreateModalField, CreateModalSelect, CreateModalSwitch, CreateModalTextarea, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, Filter, FilterPill, GlobalTooltip, HeaderActionMenu, HeaderAddButton, HeaderEditButton, HeaderRowMenu, IconButton, Indicator, Input, LetterBadge, Loader, Markdown, MaybeCollapsible, MethodButton, MultiSelectDropdown, Overview, PageHeader, Pagination, RequiredMark, SectionHeader, SettingModeOption, SettingRow, SettingSection, SettingsCard, SettingsGroup, Sort, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, Textarea, Toggle, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, contrastRatio, dangerButtonClasses, deriveTheme, filterOption, flattenOptions, formatTooltipContent, ghostButtonClasses, headerActionButtonClasses, inputClasses, isCategory, isDarkColor, isOption, modalPanelClasses, primaryButtonClasses, toggleSetMember, truncationTooltipProps, useBreadcrumb, useClearBreadcrumbs, useCssIsDark, useHideBreadcrumbs, useNavigation, useNotify, useProvisionCorsRules, useRunFile, useSetBreadcrumbs, useSetDefaultBreadcrumbs, useSlots, useStrings, useWorkflowJsonResolver };
600
+ export { AddMenu, BareModal, BreadcrumbProvider, BreadcrumbsActionButton, BreadcrumbsRightAction, BreadcrumbsTitleAction, Button, CREATE_MODAL_SELECT_FILTER_THRESHOLD, Callout, Card, CardHeader, CompactTable, ConfirmModal, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CreateModal, CreateModalAutocompleteField, CreateModalField, CreateModalSelect, CreateModalSwitch, CreateModalTextarea, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, Filter, FilterPill, GlobalTooltip, HeaderActionMenu, HeaderAddButton, HeaderEditButton, HeaderRowMenu, IconButton, Indicator, Input, LetterBadge, Loader, Markdown, MaybeCollapsible, MethodButton, MultiSelectDropdown, Overview, PageHeader, Pagination, RequiredMark, SectionHeader, SettingModeOption, SettingRow, SettingSection, SettingsCard, SettingsGroup, Sort, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, Textarea, Toggle, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, contrastRatio, dangerButtonClasses, deriveTheme, filterOption, flattenOptions, formatTooltipContent, ghostButtonClasses, headerActionButtonClasses, inputClasses, isCategory, isDarkColor, isOption, modalPanelClasses, primaryButtonClasses, statusTextClass, toggleSetMember, truncationTooltipProps, useBreadcrumb, useClearBreadcrumbs, useCssIsDark, useHideBreadcrumbs, useNavigation, useNotify, usePersistedState, useProvisionCorsRules, useRelativeTime, useRepoSuggestions, useRunFile, useSetBreadcrumbs, useSetDefaultBreadcrumbs, useSlots, useStrings, useWorkflowJsonResolver };
@@ -41,8 +41,10 @@ export interface PinnedRowAction {
41
41
  /** Replaces the label on hover when the action is disabled, explaining why. */
42
42
  tooltip?: string | undefined;
43
43
  }
44
- export declare function ListRow({ href, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children, }: {
44
+ export declare function ListRow({ href, onActivate, items, goTo, openMenu, pinnedActions, selected, selectionActive, onRowSelect, leading, className, children, }: {
45
45
  href: string | null;
46
+ /** Plain-click handler for rows that open something in place instead of navigating. */
47
+ onActivate?: (() => void) | undefined;
46
48
  items: RowMenuItem[];
47
49
  goTo: (to: string) => void;
48
50
  openMenu: OpenMenu;
@@ -1,11 +1,13 @@
1
1
  /** Page sizes offered by the pager's per-page select; first entry is the default. */
2
2
  export declare const LIST_PAGE_SIZES: readonly [number, ...number[]];
3
3
  /** Footer pager bar for paginated new-nav lists: "{start}–{end} of {total}" with prev/next. Renders nothing for a single page. */
4
- export declare function ListPager({ page, pageSize, total, onPageChange, pageSizes, onPageSizeChange, }: {
4
+ export declare function ListPager({ page, pageSize, total, onPageChange, pageSizes, onPageSizeChange, hasNext, }: {
5
5
  page: number;
6
6
  pageSize: number;
7
7
  total: number;
8
8
  onPageChange: (page: number) => void;
9
+ /** Cursor lists whose `total` is a capped count pass this so paging doesn't stop at the cap. */
10
+ hasNext?: boolean | undefined;
9
11
  /** Selectable page sizes; shown only when onPageSizeChange is provided. */
10
12
  pageSizes?: readonly number[];
11
13
  onPageSizeChange?: (size: number) => void;
@@ -18,12 +18,13 @@ export declare const listTableFixedProps: {
18
18
  readonly tbodyClassName: 'divide-y border-b border-(--theme-border) divide-(--theme-border)';
19
19
  readonly className: string;
20
20
  };
21
- export declare function NameCell({ icon, name, subtitle, href, badge, }: {
21
+ export declare function NameCell({ icon, name, subtitle, href, badge, title, }: {
22
22
  icon: ReactNode;
23
23
  name: string;
24
24
  subtitle?: string | undefined;
25
25
  href: string | null;
26
26
  badge?: ReactNode;
27
+ title?: string | undefined;
27
28
  }): import("react").JSX.Element;
28
29
  export declare function GroupRow({ label, count, colSpan, }: {
29
30
  label: string;
@@ -1,3 +1,3 @@
1
- import { _ as useRowMenuActive, d as assembleRowMenu, f as copySubmenu, g as useRowMenu, h as toolbarActionToRowAction, m as toRowMenuItem, p as rowContextMenuProps, u as MoreButton } from "../chunks/PageHeader-CoZWF0pJ.js";
2
- import { A as ActionToolbar, C as ListSkeleton, D as actionsColumnWidth, E as RowSelectCheckbox, M as stickyTabsClasses, N as stickyTabsUnderHeaderClasses, O as listTableFixedProps, P as stickyToolbarClasses, S as ListError, T as NameCell, _ as ListRow, a as ListCount, b as GroupRow, c as ListDisplayMenu, d as isTextEntryContext, f as DEFAULT_ORDER, g as ListPage, h as ListColumns, i as ListPager, j as ToolbarButton, k as listTableProps, l as ListFilterMenu, m as useListView, n as useHoverCard, o as ListSearchControl, p as FAVORITE_ORDER, r as LIST_PAGE_SIZES, s as useListSearch, t as HoverCardSurface, u as listControlButtonClasses, v as ListRowActionsProvider, w as NAME_MIN_WIDTH_PX, x as ListActionsHeader, y as useListNavigate } from "../chunks/list-CduoUsMW.js";
1
+ import { _ as useRowMenuActive, d as assembleRowMenu, f as copySubmenu, g as useRowMenu, h as toolbarActionToRowAction, m as toRowMenuItem, p as rowContextMenuProps, u as MoreButton } from "../chunks/PageHeader-MxuOs9cH.js";
2
+ import { A as ActionToolbar, C as ListSkeleton, D as actionsColumnWidth, E as RowSelectCheckbox, M as stickyTabsClasses, N as stickyTabsUnderHeaderClasses, O as listTableFixedProps, P as stickyToolbarClasses, S as ListError, T as NameCell, _ as ListRow, a as ListCount, b as GroupRow, c as ListDisplayMenu, d as isTextEntryContext, f as DEFAULT_ORDER, g as ListPage, h as ListColumns, i as ListPager, j as ToolbarButton, k as listTableProps, l as ListFilterMenu, m as useListView, n as useHoverCard, o as ListSearchControl, p as FAVORITE_ORDER, r as LIST_PAGE_SIZES, s as useListSearch, t as HoverCardSurface, u as listControlButtonClasses, v as ListRowActionsProvider, w as NAME_MIN_WIDTH_PX, x as ListActionsHeader, y as useListNavigate } from "../chunks/list-7k0eaI5N.js";
3
3
  export { ActionToolbar, DEFAULT_ORDER, FAVORITE_ORDER, GroupRow, HoverCardSurface, LIST_PAGE_SIZES, ListActionsHeader, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterMenu, ListPage, ListPager, ListRow, ListRowActionsProvider, ListSearchControl, ListSkeleton, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, actionsColumnWidth, assembleRowMenu, copySubmenu, isTextEntryContext, listControlButtonClasses, listTableFixedProps, listTableProps, rowContextMenuProps, stickyTabsClasses, stickyTabsUnderHeaderClasses, stickyToolbarClasses, toRowMenuItem, toolbarActionToRowAction, useHoverCard, useListNavigate, useListSearch, useListView, useRowMenu, useRowMenuActive };
@@ -45,7 +45,7 @@ export interface ActionDef {
45
45
  defaultPinned?: boolean;
46
46
  }
47
47
  export interface ListViewConfig<T> {
48
- /** localStorage namespace for this page's grouping/columns/filters. */
48
+ /** Persistence namespace for this page's grouping/columns/filters. */
49
49
  storageKey: string;
50
50
  sharedFiltersKey?: string;
51
51
  columns: ColumnDef[];
@@ -1,5 +1,5 @@
1
1
  import { ArrowDownIcon, ArrowUpIcon, CheckIcon, ChevronDownIcon, ChevronRightIcon, ClockIcon, CopyIcon, DownloadIcon, ExpandIcon, ShrinkIcon, XIcon } from "../icons.js";
2
- import { c as useStrings, i as useNotify } from "../chunks/Provider-CbFVFB7O.js";
2
+ import { i as useNotify, u as useStrings } from "../chunks/Provider-DHmZ3v9i.js";
3
3
  import { r as TooltipInfo } from "../chunks/Tooltip-n9w7Tkt1.js";
4
4
  import cx from "classnames";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -237,12 +237,12 @@
237
237
  }
238
238
  }
239
239
 
240
- /* Native controls and labels inside a DynamicForm. The ACTIVATE app declares the
241
- * same rules globally; hosts that only import this package (docs, embeds) get
242
- * unstyled inputs without them. Base layer so field utilities still win. */
240
+ /* Native controls and form labels. The ACTIVATE app used to declare these in
241
+ * its own global stylesheet; they live here so every host that imports the
242
+ * theme gets the same fields. Base layer so utilities still win. */
243
243
  @layer base {
244
- .pw-form input,
245
- .pw-form textarea {
244
+ input,
245
+ textarea {
246
246
  border-radius: 0.25rem;
247
247
  border: 1px solid var(--theme-border, #d1d5db);
248
248
  padding: 0.25rem 0.5rem;
@@ -251,15 +251,17 @@
251
251
  background-color: var(--theme-input-bg, #f9fafb);
252
252
  color: var(--theme-app, #000000);
253
253
  }
254
- .pw-form input:disabled,
255
- .pw-form textarea:disabled {
254
+ input:disabled,
255
+ textarea:disabled,
256
+ input.disabled,
257
+ textarea.disabled {
256
258
  cursor: not-allowed;
257
259
  background-color: var(--theme-input-disabled-bg, #f3f4f6);
258
260
  color: var(--theme-input-disabled-text, #9ca3af);
259
261
  }
260
- .pw-form .form-label,
261
- .pw-form .form-label-compact,
262
- .pw-form .form-label-top {
262
+ .form-label,
263
+ .form-label-compact,
264
+ .form-label-top {
263
265
  display: flex;
264
266
  align-items: center;
265
267
  gap: 0.25rem;
@@ -268,11 +270,11 @@
268
270
  height: 34px;
269
271
  width: 13rem;
270
272
  }
271
- .pw-form .form-label-compact {
273
+ .form-label-compact {
272
274
  width: fit-content;
273
275
  margin-right: 0.5rem;
274
276
  }
275
- .pw-form .form-label-top {
277
+ .form-label-top {
276
278
  height: 20px;
277
279
  }
278
280
  }