@parallelworks/ui 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +5 -0
  2. package/dist/chunks/CodePreviewEditor-CSPRILMp.js +61 -0
  3. package/dist/chunks/Indicator-hBSIxOPK.js +39 -0
  4. package/dist/chunks/Markdown-C5Re2ezs.js +101 -0
  5. package/dist/chunks/{Indicator-fF8AVbjQ.js → Modal-sOUEwebV.js} +1 -38
  6. package/dist/chunks/{Monaco-CP_cL9gp.js → Monaco-CC4ak1JG.js} +3 -31
  7. package/dist/chunks/Provider-DvVvScTQ.js +391 -0
  8. package/dist/chunks/StatusBadge-DXp4zkSd.js +46 -0
  9. package/dist/chunks/{Table-DWuRINhu.js → SwitchToggle-2uRw8ZeJ.js} +2 -132
  10. package/dist/chunks/Table-C5z6qWjM.js +91 -0
  11. package/dist/chunks/editor-D55tumuZ.js +372 -0
  12. package/dist/chunks/list-7PyDF1tz.js +465 -0
  13. package/dist/components/Provider.d.ts +293 -0
  14. package/dist/editor/index.d.ts +1 -0
  15. package/dist/editor/index.js +2 -219
  16. package/dist/editor/useCssIsDark.d.ts +6 -0
  17. package/dist/file-explorer/FileExplorer.d.ts +23 -0
  18. package/dist/file-explorer/FileExplorerContext.d.ts +17 -0
  19. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +6 -0
  20. package/dist/file-explorer/FilePreview/Inline.d.ts +13 -0
  21. package/dist/file-explorer/FilePreview/StreamedBadge.d.ts +1 -0
  22. package/dist/file-explorer/FilePreview/Viewer.d.ts +15 -0
  23. package/dist/file-explorer/FilePreview/index.d.ts +15 -0
  24. package/dist/file-explorer/FilePreview/parse.d.ts +24 -0
  25. package/dist/file-explorer/FilePreview/previewCache.d.ts +26 -0
  26. package/dist/file-explorer/FilePreview/previewType.d.ts +21 -0
  27. package/dist/file-explorer/FilePreview/readCappedBytes.d.ts +37 -0
  28. package/dist/file-explorer/FilePreview/useObjectBlobUrl.d.ts +16 -0
  29. package/dist/file-explorer/FilePreview/useObjectText.d.ts +23 -0
  30. package/dist/file-explorer/FilePreview/usePresignedUrl.d.ts +12 -0
  31. package/dist/file-explorer/FileRow.d.ts +35 -0
  32. package/dist/file-explorer/FileRowsWindow.d.ts +43 -0
  33. package/dist/file-explorer/FileTable.d.ts +26 -0
  34. package/dist/file-explorer/FileTableHeaders.d.ts +13 -0
  35. package/dist/file-explorer/LoadMoreRow.d.ts +15 -0
  36. package/dist/file-explorer/TreeView.d.ts +28 -0
  37. package/dist/file-explorer/helpers.d.ts +47 -0
  38. package/dist/file-explorer/index.d.ts +10 -0
  39. package/dist/file-explorer/index.js +5646 -0
  40. package/dist/file-explorer/lib/batch.d.ts +3 -0
  41. package/dist/file-explorer/lib/errors.d.ts +3 -0
  42. package/dist/file-explorer/lib/fileExplorer.d.ts +32 -0
  43. package/dist/file-explorer/lib/paging.d.ts +93 -0
  44. package/dist/file-explorer/lib/types.d.ts +92 -0
  45. package/dist/file-explorer/lib/utils.d.ts +37 -0
  46. package/dist/file-explorer/toasts.d.ts +9 -0
  47. package/dist/file-explorer/treeRows.d.ts +35 -0
  48. package/dist/file-explorer/useNearEnd.d.ts +7 -0
  49. package/dist/form/index.js +4 -2
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +9 -101
  52. package/dist/list/ListTable.d.ts +63 -0
  53. package/dist/list/RowContextMenu.d.ts +113 -0
  54. package/dist/list/index.d.ts +2 -0
  55. package/dist/list/index.js +2 -0
  56. package/dist/logviewer/index.js +1 -1
  57. package/dist/styles/theme.css +30 -0
  58. package/dist/styles.css +1 -1
  59. package/dist/workflow/index.js +3 -2
  60. package/package.json +20 -3
  61. package/dist/chunks/Provider-C2VtPnh5.js +0 -151
  62. package/dist/chunks/workers-Cjfjb8E7.js +0 -119
@@ -0,0 +1,3 @@
1
+ export declare function paginate<TPage>(fetchPage: (cursor?: string) => Promise<TPage>, nextCursor: (page: TPage) => string | undefined): AsyncGenerator<TPage>;
2
+ export declare function chunk<T>(items: readonly T[], size: number): T[][];
3
+ export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, worker: (item: T) => Promise<R>): Promise<PromiseSettledResult<R>[]>;
@@ -0,0 +1,3 @@
1
+ export declare class CorsError extends Error {
2
+ constructor(message?: string);
3
+ }
@@ -0,0 +1,32 @@
1
+ import type { TListPageRequest } from './paging.js';
2
+ import type { TreeNode, TStorage, TStorageObject } from './types.js';
3
+ /** Every provider resolves get-file as a [url, error] tuple. */
4
+ export type FileExplorerGetFileResult = [string | null, Error | null];
5
+ /** The UI only checks Errors?.length; each provider's richer error entries
6
+ * satisfy this structurally. */
7
+ export interface FileExplorerDeleteFilesResult {
8
+ Errors?: unknown[];
9
+ }
10
+ export interface IFileExplorerClient {
11
+ getStorageName(): string;
12
+ getExpiresAt(): Date;
13
+ getFile(input: unknown): Promise<FileExplorerGetFileResult>;
14
+ listDirectory(input: unknown): Promise<unknown>;
15
+ deleteFiles(input: unknown): Promise<FileExplorerDeleteFilesResult>;
16
+ uploadFile(input: unknown, onProgress?: (progress: {
17
+ loadedBytes: number;
18
+ totalBytes: number;
19
+ percentage: number;
20
+ }) => void, abortController?: AbortController): Promise<unknown>;
21
+ }
22
+ export interface IFileExplorerProvider {
23
+ createClient: ((organization: string, username: string, name: string) => Promise<IFileExplorerClient | null>) | null;
24
+ convertDataToStorageObjects?(data: unknown): TStorageObject[];
25
+ /** Absent ⇒ the explorer treats one page as the whole directory. Method syntax for
26
+ * the same bivariance reason as the two above. */
27
+ nextPageCursor?(data: unknown): string | undefined;
28
+ listDirectoryInput?: ((storage: TStorage, dir_path?: string, page?: TListPageRequest) => unknown) | null;
29
+ getFileInput?: ((storageName: string, node: TreeNode, presignedUrlExpiresIn?: number) => unknown) | null;
30
+ deleteFilesInput?: ((storageName: string, nodes: TreeNode[]) => unknown) | null;
31
+ uploadFileInput?: ((storageName: string, objectPath: string, file: File | Blob) => unknown) | null;
32
+ }
@@ -0,0 +1,93 @@
1
+ import type { TStorageObject } from './types.js';
2
+ /** Both providers already cap an unqualified list at 1,000, so stating it leaves
3
+ * single-page directories byte-identical. */
4
+ export declare const LIST_PAGE_SIZE = 1000;
5
+ export type TListPageRequest = {
6
+ cursor?: string;
7
+ /** Overridable so a test can page without seeding 2,000 objects. */
8
+ pageSize?: number;
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. */
12
+ export type TDirectoryListing = {
13
+ /** Present ⇒ more entries exist and the provider can resume from here. */
14
+ cursor?: string;
15
+ /** 0 ⇒ never listed, which is what tells "empty" apart from "not asked yet". */
16
+ pagesLoaded: number;
17
+ /** Not `loadingPaths`, which swaps the whole table for a skeleton and would blank
18
+ * the rows being read. */
19
+ loadingMore: boolean;
20
+ /** The storage-level error surfaces only on an empty folder, so without this a
21
+ * failure mid-folder is invisible. */
22
+ error?: string;
23
+ };
24
+ /** Uncapped, opening a 200k-object folder and scrolling would walk all of it. */
25
+ export declare const MAX_AUTO_PAGES = 5;
26
+ export type TListings = ReadonlyMap<string, TDirectoryListing>;
27
+ export declare function isListed(listings: TListings, path: string): boolean;
28
+ /** True even while a request is in flight, so the sentinel stays put. */
29
+ export declare function hasMore(listings: TListings, path: string): boolean;
30
+ /** Auto-load stops at the cap; past it the user asks for each page. */
31
+ export declare function canAutoLoadMore(listings: TListings, path: string): boolean;
32
+ export declare function isLoadingMore(listings: TListings, path: string): boolean;
33
+ export declare function loadMoreError(listings: TListings, path: string): string | undefined;
34
+ 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. */
42
+ 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/`. */
45
+ 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
+ /** Tree paths whose children should keep arrival order, since sorting them would
50
+ * reshuffle rows under the user mid-scroll. */
51
+ export declare function incompletePaths(listings: TListings): Set<string>;
52
+ /** Reached only when the target is deep inside a directory of well over 20,000
53
+ * entries, where the alternative is draining it all. */
54
+ export declare const MAX_HYDRATION_PAGES = 20;
55
+ type THydrationStep =
56
+ /** List this directory's first page. */
57
+ {
58
+ kind: 'fetch';
59
+ path: string;
60
+ }
61
+ /** Pull another page; the target is not in what we have. */
62
+ | {
63
+ kind: 'more';
64
+ path: string;
65
+ } | {
66
+ kind: 'stuck';
67
+ }
68
+ /** Either resolved, or a request is already in flight. */
69
+ | {
70
+ kind: 'done';
71
+ };
72
+ /** 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, }: {
74
+ targetResolved: boolean;
75
+ /** Directory paths from the storage root down to the target. */
76
+ ancestors: readonly string[];
77
+ /** False above the storage root, and false for a directory a page has not
78
+ * introduced yet. */
79
+ isListableDir: (path: string) => boolean;
80
+ 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
+ pagesPulled: number;
86
+ }): 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
+ export {};
@@ -0,0 +1,92 @@
1
+ import type { IFileExplorerClient, IFileExplorerProvider } from './fileExplorer.js';
2
+ export type TStorage = {
3
+ id: string;
4
+ name: string;
5
+ bucketName?: string;
6
+ user: string;
7
+ displayName?: string;
8
+ type?: string;
9
+ created?: string;
10
+ modified?: string;
11
+ region?: string;
12
+ csp?: string;
13
+ imageUrl?: string;
14
+ canWrite?: boolean | undefined;
15
+ canUpload?: boolean | undefined;
16
+ canShare?: boolean | undefined;
17
+ canManageAccess?: boolean | undefined;
18
+ supportsPwUri?: boolean | undefined;
19
+ objects?: TStorageObject[];
20
+ };
21
+ export type TStorageObject = {
22
+ path: string;
23
+ type: 'file' | 'directory';
24
+ key?: string;
25
+ size?: number;
26
+ created?: string;
27
+ modified?: string;
28
+ contentType?: string;
29
+ hash?: string;
30
+ storageClass?: string;
31
+ };
32
+ export type TreeNode = {
33
+ name: string;
34
+ displayName?: string;
35
+ path: string;
36
+ relativePath?: string;
37
+ type: 'file' | 'directory';
38
+ size?: number;
39
+ created?: string;
40
+ modified?: string;
41
+ contentType?: string;
42
+ hash?: string;
43
+ storageClass?: string;
44
+ storageId?: string;
45
+ storageName?: string;
46
+ storageNodeIcon?: string;
47
+ storageImageUrl?: string;
48
+ storageType?: string;
49
+ root?: boolean;
50
+ };
51
+ export type TreeMap = {
52
+ [path: string]: TreeNode;
53
+ };
54
+ export type UploadNode = {
55
+ name: string;
56
+ file: File | Blob;
57
+ relativePath: string;
58
+ };
59
+ export interface UploadFileProgress {
60
+ fileKey: string;
61
+ fileSizeBytes: number;
62
+ loadedBytes?: number;
63
+ totalBytes?: number;
64
+ percentage?: number;
65
+ abortController?: AbortController;
66
+ status?: 'pending' | 'uploading' | 'completed' | 'failed' | 'cancelled';
67
+ }
68
+ export interface UploadSession {
69
+ id: string;
70
+ storageName: string;
71
+ targetPath: string;
72
+ uploadNodes: UploadNode[];
73
+ status: 'queued' | 'uploading' | 'completed' | 'failed' | 'cancelled';
74
+ queueIndex: number;
75
+ client: IFileExplorerClient;
76
+ provider: IFileExplorerProvider;
77
+ progress?: {
78
+ completedFiles: number;
79
+ totalFiles: number;
80
+ totalSizeBytes: number;
81
+ allFiles?: Map<string, UploadFileProgress>;
82
+ overallProgress?: number;
83
+ totalLoadedBytes?: number;
84
+ lastProgressTime?: number;
85
+ lastProgressBytes?: number;
86
+ estimatedSecondsLeft?: number;
87
+ };
88
+ toastId: string;
89
+ abortController?: AbortController;
90
+ targetNode: TreeNode;
91
+ refreshTargetNode: (targetNode: TreeNode) => Promise<unknown>;
92
+ }
@@ -0,0 +1,37 @@
1
+ import type { IFileExplorerClient } from './fileExplorer.js';
2
+ import type { TStorage, TreeMap, TreeNode, UploadNode } from './types.js';
3
+ export declare function formatFileSize(bytes: number): string;
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
+ }): {
9
+ treeMap: TreeMap;
10
+ parentToChildrenMap: Record<string, TreeNode[]>;
11
+ };
12
+ export declare function getNodeChildren(parentToChildrenMap: Record<string, TreeNode[]>, parentPath: string): TreeNode[];
13
+ export declare function getParentPath(currentPath: string): string;
14
+ export type DirectoryNameError = 'reserved' | 'separator' | 'exists';
15
+ export declare function getDirectoryNameError(name: string, siblings: TreeNode[]): DirectoryNameError | null;
16
+ export declare function getDirectoryObjectPath(parentNode: TreeNode, directoryName: string): string;
17
+ export declare function getUploadNodesFromDataTransferItems(items: DataTransferItemList): Promise<{
18
+ uploadNodes: UploadNode[];
19
+ totalSize: number;
20
+ }>;
21
+ export declare function calculateUploadNodesTotalSize(uploadNodes: UploadNode[]): number;
22
+ export declare function getObjectKeyFromNode(node: TreeNode): string;
23
+ export declare function getDirectoryPrefixFromNode(node: TreeNode): string;
24
+ export declare function pruneNodesInsideSelectedDirectories(nodes: TreeNode[]): TreeNode[];
25
+ export declare function collectObjectKeysToDelete(nodes: TreeNode[], listKeysUnderPrefix: (prefix: string) => Promise<string[]>): Promise<string[]>;
26
+ export declare function getPwUri(username: string, pwName: string, key: string): string;
27
+ export declare function getCspUri(csp: string, cspBucketName: string, key: string): string | null;
28
+ export declare function removeLeadingSlash(path: string): string;
29
+ export declare function removeLeadingAndTrailingSlashes(path: string): string;
30
+ export declare function isClientValid(client: IFileExplorerClient): boolean;
31
+ export declare function getUploadSessionETA(totalLoadedBytes: number, totalSizeBytes: number, lastProgressTime?: number, lastProgressBytes?: number): {
32
+ estimatedSecondsLeft?: number;
33
+ lastProgressTime: number;
34
+ lastProgressBytes: number;
35
+ shouldUpdateETA: boolean;
36
+ };
37
+ export declare function formatETA(seconds: number): string;
@@ -0,0 +1,9 @@
1
+ import type { UploadSession } from './lib/types.js';
2
+ interface UploadSessionToastProps {
3
+ session: UploadSession;
4
+ queueLength: number;
5
+ onCancel?: () => void;
6
+ onCancelFile?: (relativePath: string) => void;
7
+ }
8
+ export declare function UploadSessionToast({ session, queueLength, onCancel, onCancelFile, }: UploadSessionToastProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,35 @@
1
+ import type { TreeNode } from './lib/types.js';
2
+ /** 10,000 file rows render cheaply but stand 300,000px tall, burying the folder's
3
+ * next sibling. Directories are never held back. */
4
+ export declare const TREE_FILE_CAP = 50;
5
+ /** One visible line in the sidebar tree. */
6
+ export interface TreeRow {
7
+ kind: 'node' | 'skeleton' | 'more';
8
+ /** Non-node rows suffix the parent path after a NUL, which object keys effectively
9
+ * never contain; nothing is derived from the key, so a collision only warns. */
10
+ key: string;
11
+ node: TreeNode;
12
+ /** Roots are 0. Drives indent and aria-level (which is 1-based). */
13
+ depth: number;
14
+ posInSet: number;
15
+ /** The true sibling count, which aria-setsize wants even when the cap shows fewer. */
16
+ setSize: number;
17
+ isExpanded: boolean;
18
+ /** `more` rows only: files held back by the cap, 0 when only pages remain. */
19
+ hiddenFiles?: number;
20
+ }
21
+ interface FlattenTreeOptions {
22
+ loadingPaths?: ReadonlySet<string>;
23
+ incompletePaths?: ReadonlySet<string>;
24
+ /** Absent means `TREE_FILE_CAP`. */
25
+ fileLimits?: ReadonlyMap<string, number>;
26
+ }
27
+ /** Flattens the tree to exactly the rows that should be on screen, so the sidebar
28
+ * can be windowed and keyboard navigation can move by index instead of by DOM. */
29
+ export declare function flattenTreeRows(roots: TreeNode[], parentToChildrenMap: Record<string, TreeNode[]>, expandedPaths: ReadonlySet<string>, options?: FlattenTreeOptions): TreeRow[];
30
+ export declare function nextFileLimit(current: number | undefined): number;
31
+ /** Index of `path` among the visible rows, or -1. */
32
+ export declare function findRowIndex(rows: readonly TreeRow[], path: string): number;
33
+ /** The next selectable row in `direction`, skipping skeleton and more rows. */
34
+ export declare function stepRow(rows: readonly TreeRow[], from: number, direction: 1 | -1): TreeRow | undefined;
35
+ export {};
@@ -0,0 +1,7 @@
1
+ import { type RefObject } from 'react';
2
+ /** Fires once the element comes within 100px of the bottom of `root`. */
3
+ export declare function useNearEnd(ref: RefObject<Element | null>, { active, root, onNear, }: {
4
+ active: boolean;
5
+ root: HTMLElement | null;
6
+ onNear: () => void;
7
+ }): void;
@@ -1,8 +1,10 @@
1
1
  import { AngleRightIcon, EyeIcon, EyeOffIcon, SuccessCheckmark, TrashIcon } from "../icons.js";
2
- import { a as useSlots, o as useStrings } from "../chunks/Provider-C2VtPnh5.js";
2
+ import { c as useStrings, s as useSlots } from "../chunks/Provider-DvVvScTQ.js";
3
3
  import { n as TOOLTIP_ID, r as TooltipInfo } from "../chunks/Tooltip-WgbiC_nd.js";
4
- import { a as StatusDot, d as CustomListbox, f as Dropdown, g as isCategory, l as UncontrolledCollapsiblePanel, n as Table, o as SectionHeader, r as SwitchToggle, s as ControlledCollapsiblePanel, u as MultiSelectDropdown } from "../chunks/Table-DWuRINhu.js";
4
+ import { a as UncontrolledCollapsiblePanel, c as Dropdown, f as isCategory, n as SectionHeader, o as MultiSelectDropdown, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle } from "../chunks/SwitchToggle-2uRw8ZeJ.js";
5
5
  import { t as Loader } from "../chunks/Loader-DQiZ75fa.js";
6
+ import { n as StatusDot } from "../chunks/StatusBadge-DXp4zkSd.js";
7
+ import { n as Table } from "../chunks/Table-C5z6qWjM.js";
6
8
  import { a as resolvedFlag, c as FieldWrapper, i as initializeValues, n as flattenGroups, o as applySecondaryField, r as impureSetValueFromPath, s as findSecondaryOption, t as enforceOneMustBeTrue } from "../chunks/lib-DTgL8klR.js";
7
9
  import cx from "classnames";
8
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ export type { MarkdownProps } from './components/Markdown.js';
16
16
  export { default as Modal, type ModalProps } from './components/Modal.js';
17
17
  export { default as MultiSelectDropdown } from './components/MultiSelect.js';
18
18
  export { Overview } from './components/Overview.js';
19
- export { UIProvider, useNavigation, useNotify, useRunFile, useSlots, useStrings, useWorkflowJsonResolver, type RunFileResult, type WorkflowJsonRef, type UIData, type UINavigation, type UINotify, type UISlots, type UIStrings, } from './components/Provider.js';
19
+ 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';
20
20
  export { Indicator } from './components/Indicator.js';
21
21
  export { ControlledCollapsiblePanel, MaybeCollapsible, UncontrolledCollapsiblePanel, } from './components/CollapsiblePanel.js';
22
22
  export { default as SectionHeader } from './components/SectionHeader.js';
package/dist/index.js CHANGED
@@ -1,98 +1,18 @@
1
1
  import { DEFAULT_PRESET, THEME_PRESETS, THEME_TOKENS, applyTheme, contrastRatio, deriveTheme, isDarkColor } from "./theme/index.js";
2
- import { AlertIcon, CheckIcon, ClipboardIcon, CopyIcon, HiddenFalseIcon, HiddenTrueIcon, InfoIcon } from "./icons.js";
3
- import { a as useSlots, i as useRunFile, n as useNavigation, o as useStrings, r as useNotify, s as useWorkflowJsonResolver, t as UIProvider } from "./chunks/Provider-C2VtPnh5.js";
2
+ import { i as Callout, n as CopyCodeBlock, r as CopyToClipboard, t as Markdown } from "./chunks/Markdown-C5Re2ezs.js";
3
+ import { a as useProvisionCorsRules, c as useStrings, i as useNotify, l as useWorkflowJsonResolver, o as useRunFile, r as useNavigation, s as useSlots, t as UIProvider } from "./chunks/Provider-DvVvScTQ.js";
4
4
  import { i as formatTooltipContent, n as TOOLTIP_ID, r as TooltipInfo, t as GlobalTooltip } from "./chunks/Tooltip-WgbiC_nd.js";
5
- import { _ as isOption, a as StatusDot, c as MaybeCollapsible, d as CustomListbox, f as Dropdown, g as isCategory, h as flattenOptions, i as StatusBadge, l as UncontrolledCollapsiblePanel, m as filterOption, n as Table, o as SectionHeader, p as DropdownCaret, r as SwitchToggle, s as ControlledCollapsiblePanel, t as CompactTable, u as MultiSelectDropdown } from "./chunks/Table-DWuRINhu.js";
5
+ import { a as UncontrolledCollapsiblePanel, c as Dropdown, d as flattenOptions, f as isCategory, i as MaybeCollapsible, l as DropdownCaret, n as SectionHeader, o as MultiSelectDropdown, p as isOption, r as ControlledCollapsiblePanel, s as CustomListbox, t as SwitchToggle, u as filterOption } from "./chunks/SwitchToggle-2uRw8ZeJ.js";
6
6
  import { t as Loader } from "./chunks/Loader-DQiZ75fa.js";
7
- import { n as Modal, t as Indicator } from "./chunks/Indicator-fF8AVbjQ.js";
7
+ import { t as Modal } from "./chunks/Modal-sOUEwebV.js";
8
+ import { t as Indicator } from "./chunks/Indicator-hBSIxOPK.js";
8
9
  import { t as SwitchToggleSmall } from "./chunks/SwitchToggleSmall-FcsaYSTs.js";
10
+ import { n as StatusDot, t as StatusBadge } from "./chunks/StatusBadge-DXp4zkSd.js";
11
+ import { n as Table, t as CompactTable } from "./chunks/Table-C5z6qWjM.js";
9
12
  import cx from "classnames";
10
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
- import React, { Suspense, lazy, useState } from "react";
14
+ import React from "react";
12
15
  import Skeleton from "react-loading-skeleton";
13
- //#region src/components/Callout.tsx
14
- function CalloutIcon({ type }) {
15
- if (type === "warning" || type === "error") return /* @__PURE__ */ jsx(AlertIcon, { className: "h-6 w-6 mr-4 text-lg" });
16
- else return /* @__PURE__ */ jsx(InfoIcon, { className: "h-6 w-6 mr-4 text-lg" });
17
- }
18
- function Callout({ type, className = "", children }) {
19
- return /* @__PURE__ */ jsx("div", {
20
- className: cx(className, type === "warning" && "bg-orange-100 border-orange-500 text-orange-700", type === "error" && "bg-red-100 border-red-500 text-red-700", type === "info" && "bg-blue-100 border-blue-500 text-blue-700", "border-t-4 rounded-b px-4 py-3 shadow-md my-4"),
21
- role: "alert",
22
- children: /* @__PURE__ */ jsxs("div", {
23
- className: "flex",
24
- children: [/* @__PURE__ */ jsx("div", {
25
- className: "py-1",
26
- children: /* @__PURE__ */ jsx(CalloutIcon, { type })
27
- }), /* @__PURE__ */ jsx("div", { children })]
28
- })
29
- });
30
- }
31
- //#endregion
32
- //#region src/components/CopyToClipboard.tsx
33
- function CopyToClipboard({ as = "div", text, className, children, showIcon = true }) {
34
- const notify = useNotify();
35
- const handleCopy = async () => {
36
- try {
37
- await navigator.clipboard.writeText(text);
38
- notify.info("Copied to clipboard");
39
- } catch {
40
- notify.error("Failed to copy to clipboard");
41
- }
42
- };
43
- return /* @__PURE__ */ jsxs(as, {
44
- className,
45
- onClick: handleCopy,
46
- ...as === "button" ? { type: "button" } : {},
47
- children: [showIcon && /* @__PURE__ */ jsx(ClipboardIcon, {}), children]
48
- });
49
- }
50
- function CopyCodeBlock({ textToCopy, children, secret = false, isRevealed = false, onRevealToggle }) {
51
- const notify = useNotify();
52
- const [copied, setCopied] = useState(false);
53
- const handleCopy = async () => {
54
- if (copied) return;
55
- try {
56
- await navigator.clipboard.writeText(textToCopy);
57
- setCopied(true);
58
- notify.info("Copied to clipboard");
59
- setTimeout(() => setCopied(false), 2e3);
60
- } catch {
61
- notify.error("Failed to copy to clipboard");
62
- }
63
- };
64
- return /* @__PURE__ */ jsxs("div", {
65
- className: "group relative",
66
- onClick: handleCopy,
67
- children: [/* @__PURE__ */ jsx("pre", {
68
- className: `p-4 theme-hover border rounded-lg text-left font-mono text-sm overflow-x-auto ${secret ? "pr-24" : "pr-12"}`,
69
- children
70
- }), /* @__PURE__ */ jsxs("div", {
71
- className: "absolute top-0 right-0 bottom-0 flex items-center gap-1 pl-8 pr-2 bg-gradient-to-l from-[var(--color-panel)] from-70% to-transparent rounded-r-lg",
72
- children: [secret && /* @__PURE__ */ jsx("button", {
73
- type: "button",
74
- onClick: (e) => {
75
- e.stopPropagation();
76
- onRevealToggle?.();
77
- },
78
- className: "p-2 rounded-md opacity-0 group-hover:opacity-100 transition-all duration-150",
79
- "aria-label": isRevealed ? "Hide secret" : "Reveal secret",
80
- title: isRevealed ? "Hide secret" : "Reveal secret",
81
- children: isRevealed ? /* @__PURE__ */ jsx(HiddenFalseIcon, {}) : /* @__PURE__ */ jsx(HiddenTrueIcon, {})
82
- }), /* @__PURE__ */ jsx("button", {
83
- type: "button",
84
- onClick: (e) => {
85
- e.stopPropagation();
86
- handleCopy();
87
- },
88
- className: "p-2 rounded-md opacity-0 group-hover:opacity-100 transition-all duration-150",
89
- "aria-label": copied ? "Copied" : "Copy to clipboard",
90
- children: copied ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-green-400" }) : /* @__PURE__ */ jsx(CopyIcon, {})
91
- })]
92
- })]
93
- });
94
- }
95
- //#endregion
96
16
  //#region src/components/DescriptionList.tsx
97
17
  function DescriptionListItem({ label, children, tooltip, className, ...props }) {
98
18
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("dt", {
@@ -155,18 +75,6 @@ function EmptyState({ title, description, action, icon: Icon }) {
155
75
  });
156
76
  }
157
77
  //#endregion
158
- //#region src/components/Markdown.tsx
159
- var MarkdownImpl = lazy(() => import("./chunks/MarkdownImpl-Bq4QhrtA.js"));
160
- function Markdown(props) {
161
- return /* @__PURE__ */ jsx(Suspense, {
162
- fallback: /* @__PURE__ */ jsx("div", {
163
- className: "markdown whitespace-pre-wrap text-start w-full",
164
- children: props.children
165
- }),
166
- children: /* @__PURE__ */ jsx(MarkdownImpl, { ...props })
167
- });
168
- }
169
- //#endregion
170
78
  //#region src/components/Overview.tsx
171
79
  function Overview({ Icon, name, type, children, right, className, loading, iconSize = 75 }) {
172
80
  return /* @__PURE__ */ jsxs("div", {
@@ -202,4 +110,4 @@ function Overview({ Icon, name, type, children, right, className, loading, iconS
202
110
  });
203
111
  }
204
112
  //#endregion
205
- export { Callout, CompactTable, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, GlobalTooltip, Indicator, Loader, Markdown, MaybeCollapsible, Modal, MultiSelectDropdown, Overview, SectionHeader, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, contrastRatio, deriveTheme, filterOption, flattenOptions, formatTooltipContent, isCategory, isDarkColor, isOption, useNavigation, useNotify, useRunFile, useSlots, useStrings, useWorkflowJsonResolver };
113
+ export { Callout, CompactTable, ControlledCollapsiblePanel, CopyCodeBlock, CopyToClipboard, CustomListbox, DEFAULT_PRESET, DescriptionList, DescriptionListItem, Dropdown, DropdownCaret, EmptyState, GlobalTooltip, Indicator, Loader, Markdown, MaybeCollapsible, Modal, MultiSelectDropdown, Overview, SectionHeader, StatusBadge, StatusDot, SwitchToggle, SwitchToggleSmall, THEME_PRESETS, THEME_TOKENS, TOOLTIP_ID, Table, TooltipInfo, UIProvider, UncontrolledCollapsiblePanel, applyTheme, contrastRatio, deriveTheme, filterOption, flattenOptions, formatTooltipContent, isCategory, isDarkColor, isOption, useNavigation, useNotify, useProvisionCorsRules, useRunFile, useSlots, useStrings, useWorkflowJsonResolver };
@@ -0,0 +1,63 @@
1
+ import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
2
+ /** table-auto + horizontal scroll; the name column has a min-width floor so it can't be crushed. */
3
+ export declare const listTableProps: {
4
+ readonly borderless: true;
5
+ readonly panel: false;
6
+ readonly rounded: false;
7
+ readonly theadClassName: 'text-(--theme-muted-text-color)';
8
+ readonly tbodyClassName: 'divide-y border-b border-(--theme-border) divide-(--theme-border)';
9
+ readonly className: 'table-auto w-full [&_td:first-child]:pl-4 [&_th:first-child]:pl-4 [&_td:last-child]:pr-4 [&_th:last-child]:pr-4';
10
+ };
11
+ /** Widths come only from the header row, so a windowed body cannot shift the
12
+ * columns as different content scrolls into view. */
13
+ export declare const listTableFixedProps: {
14
+ readonly borderless: true;
15
+ readonly panel: false;
16
+ readonly rounded: false;
17
+ readonly theadClassName: 'text-(--theme-muted-text-color)';
18
+ readonly tbodyClassName: 'divide-y border-b border-(--theme-border) divide-(--theme-border)';
19
+ readonly className: string;
20
+ };
21
+ export declare function NameCell({ icon, name, subtitle, href, }: {
22
+ icon: ReactNode;
23
+ name: string;
24
+ subtitle?: string;
25
+ href: string | null;
26
+ }): import("react").JSX.Element;
27
+ export declare function GroupRow({ label, count, colSpan, }: {
28
+ label: string;
29
+ count: number;
30
+ colSpan: number;
31
+ }): import("react").JSX.Element;
32
+ export declare function ListError({ error, noun, }: {
33
+ error: unknown;
34
+ noun?: string;
35
+ }): import("react").JSX.Element;
36
+ export declare function ListSkeleton({ rows }: {
37
+ rows?: number;
38
+ }): import("react").JSX.Element;
39
+ /** Prevents the name column from being crushed under table-auto layout during horizontal overflow. */
40
+ export declare const NAME_MIN_WIDTH_PX = 200;
41
+ /** Width the trailing actions column reserves for `count` always-visible
42
+ * buttons plus the hover `⋯` trigger. */
43
+ export declare function actionsColumnWidth(count: number): number;
44
+ /** Shared leading selection checkbox for multi-select rows: stops the row-click
45
+ * and suppresses shift-click text selection. Wrap in <Table.Item> for `leading`. */
46
+ export declare function RowSelectCheckbox({ checked, label, onToggle, }: {
47
+ checked: boolean;
48
+ label: string;
49
+ onToggle: (e: ReactMouseEvent) => void;
50
+ }): import("react").JSX.Element;
51
+ /** Sizes to fit pinned buttons + ⋯; below ~44rem only ⋯ remains. Pass a view's
52
+ * chrome (structurally: showActions + actionsWidth) or actionCount. */
53
+ export declare function ListActionsHeader({ view, actionCount, className, }: {
54
+ view?: {
55
+ showActions: boolean;
56
+ actionsWidth: number;
57
+ };
58
+ actionCount?: number;
59
+ className?: string;
60
+ }): import("react").JSX.Element | null;
61
+ export declare namespace ListActionsHeader {
62
+ var isTableHeader: boolean;
63
+ }
@@ -0,0 +1,113 @@
1
+ import type { ComponentType, MouseEvent as ReactMouseEvent, ReactNode } from 'react';
2
+ export type RowMenuItem = {
3
+ kind: 'link';
4
+ label: string;
5
+ to: string;
6
+ icon?: ReactNode;
7
+ destructive?: boolean;
8
+ } | {
9
+ kind: 'action';
10
+ label: string;
11
+ onSelect?: () => void;
12
+ icon?: ReactNode;
13
+ destructive?: boolean;
14
+ disabled?: boolean;
15
+ /** Trailing checkmark, e.g. the active option in a radio-style submenu. */
16
+ selected?: boolean;
17
+ /** Declarative clipboard copy: the menu performs it and notifies, so
18
+ * builders like copySubmenu need no toast or clipboard access. */
19
+ copy?: {
20
+ text: string;
21
+ label: string;
22
+ };
23
+ } | {
24
+ kind: 'submenu';
25
+ label: string;
26
+ icon?: ReactNode;
27
+ items: RowMenuItem[];
28
+ } | {
29
+ kind: 'divider';
30
+ };
31
+ export type OpenMenu = (x: number, y: number, items: RowMenuItem[], onClose?: () => void) => void;
32
+ /** The shared shape every entity action hook's per-row actions boil down to.
33
+ * Each hook's bespoke `*RowAction` type is structurally assignable to this. */
34
+ export interface RowAction {
35
+ key: string;
36
+ label: string;
37
+ icon: ReactNode;
38
+ onSelect?: () => void;
39
+ to?: string;
40
+ disabled?: boolean;
41
+ destructive?: boolean;
42
+ }
43
+ /** Converts a single row action to a menu item: a `to` makes it a link, otherwise an action. */
44
+ export declare function toRowMenuItem(action: RowAction): RowMenuItem;
45
+ /** Bridges a toolbar action (icon component, `onClick`/`href`) onto the shared
46
+ * `RowAction` shape. Typed structurally so any toolbar action shape matching
47
+ * these fields is assignable. */
48
+ export declare function toolbarActionToRowAction(action: {
49
+ key: string;
50
+ label: string;
51
+ icon: ComponentType<{
52
+ className?: string;
53
+ }>;
54
+ onClick?: () => void;
55
+ href?: string;
56
+ disabled?: boolean;
57
+ }): RowAction;
58
+ /** Assembles a row's context menu in the shared order: leading link(s) → middle
59
+ * actions → extra items → Copy submenu → trailing (destructive) actions last. */
60
+ export declare function assembleRowMenu({ lead, actions, exclude, order, trailing, extra, copy, }: {
61
+ /** Pre-built leading link(s), e.g. "View details". */
62
+ lead?: RowMenuItem[];
63
+ /** The row's full action list. */
64
+ actions: RowAction[];
65
+ /** Keys already rendered in `lead`/`extra`; dropped from the middle. */
66
+ exclude?: string[];
67
+ /** Explicit middle order; keys absent from `actions` are skipped, keys absent from `order` are dropped. */
68
+ order?: string[];
69
+ /** Keys rendered last, in this order (default `['delete']`). */
70
+ trailing?: string[];
71
+ /** Items inserted after the middle actions and before Copy, e.g. a marketplace link. */
72
+ extra?: RowMenuItem[];
73
+ /** The Copy submenu from `copySubmenu(...)`. */
74
+ copy?: RowMenuItem;
75
+ }): RowMenuItem[];
76
+ export declare function useRowMenu(): {
77
+ openMenu: OpenMenu;
78
+ contextMenu: import("react").JSX.Element;
79
+ };
80
+ /** The full-screen menu overlay drops CSS :hover on the triggering row; wrap openMenu here to substitute a JS-driven `active` highlight. */
81
+ export declare function useRowMenuActive(openMenu: OpenMenu): {
82
+ active: boolean;
83
+ openMenu: OpenMenu;
84
+ };
85
+ export declare function rowContextMenuProps(openMenu: OpenMenu, items: RowMenuItem[]): {
86
+ onContextMenu: (e: ReactMouseEvent) => void;
87
+ };
88
+ /** Builds the Copy submenu entries for whichever fields a row has, in stable
89
+ * order. The menu itself performs the copy and notifies; `t` is an optional
90
+ * host translator for the field labels (falls back to the provider defaults'
91
+ * English). */
92
+ export declare function copySubmenu({ name, nameLabel, email, username, uid, id, url, extra, t, }: {
93
+ name?: string | null;
94
+ /** Overrides the "name" label (raw, pre-translated) for entities whose primary field isn't a name, e.g. "domain". */
95
+ nameLabel?: string;
96
+ email?: string | null;
97
+ username?: string | null;
98
+ uid?: string | number | null;
99
+ id?: string | null;
100
+ url?: string | null;
101
+ extra?: {
102
+ label: string;
103
+ value?: string | null;
104
+ icon?: ReactNode;
105
+ }[];
106
+ t?: (key: string, values?: Record<string, string | number>) => string;
107
+ }): RowMenuItem;
108
+ /** Stays visible while active (menu open) so it doesn't vanish behind the overlay. */
109
+ export declare function MoreButton({ onOpen, active, className, }: {
110
+ onOpen: (x: number, y: number) => void;
111
+ active?: boolean;
112
+ className?: string;
113
+ }): import("react").JSX.Element;