@parallelworks/ui 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -6
- package/dist/ai/adapter/memoryStore.d.ts +8 -0
- package/dist/ai/adapter/mock/index.d.ts +2 -0
- package/dist/ai/adapter/mock/index.js +81 -0
- package/dist/ai/adapter/mock/mockAdapter.d.ts +4 -0
- package/dist/ai/adapter/openai/createOpenAIStream.d.ts +9 -0
- package/dist/ai/adapter/openai/errors.d.ts +3 -0
- package/dist/ai/adapter/openai/index.d.ts +6 -0
- package/dist/ai/adapter/openai/index.js +334 -0
- package/dist/ai/adapter/openai/openaiAdapter.d.ts +9 -0
- package/dist/ai/adapter/openai/responses.d.ts +4 -0
- package/dist/ai/adapter/openai/sse.d.ts +24 -0
- package/dist/ai/adapter/openai/wire.d.ts +40 -0
- package/dist/ai/adapter/types.d.ts +131 -0
- package/dist/ai/agent/classifier.d.ts +2 -0
- package/dist/ai/agent/diff.d.ts +35 -0
- package/dist/ai/agent/diffHighlight.d.ts +6 -0
- package/dist/ai/agent/index.d.ts +6 -0
- package/dist/ai/agent/permissions.d.ts +11 -0
- package/dist/ai/agent/toolfmt.d.ts +18 -0
- package/dist/ai/agent/transcript.d.ts +38 -0
- package/dist/ai/ai.css +325 -0
- package/dist/ai/components/AllocationSelector.d.ts +4 -0
- package/dist/ai/components/AttachmentManager.d.ts +1 -0
- package/dist/ai/components/AttachmentUpload.d.ts +24 -0
- package/dist/ai/components/BlockedGroupBanner.d.ts +1 -0
- package/dist/ai/components/BranchNavigator.d.ts +8 -0
- package/dist/ai/components/ChatEmptyState.d.ts +3 -0
- package/dist/ai/components/ChatInput.d.ts +45 -0
- package/dist/ai/components/ChatLayout.d.ts +5 -0
- package/dist/ai/components/ChatMessage.d.ts +24 -0
- package/dist/ai/components/ChatMessageList.d.ts +35 -0
- package/dist/ai/components/ChatSidebar.d.ts +5 -0
- package/dist/ai/components/ChatThread.d.ts +3 -0
- package/dist/ai/components/ComposerChrome.d.ts +18 -0
- package/dist/ai/components/ComposerFrame.d.ts +16 -0
- package/dist/ai/components/DragOverlay.d.ts +5 -0
- package/dist/ai/components/ModelSelector.d.ts +6 -0
- package/dist/ai/components/ShareDialog.d.ts +11 -0
- package/dist/ai/components/SlashMenu.d.ts +28 -0
- package/dist/ai/components/agent/ActivityLine.d.ts +21 -0
- package/dist/ai/components/agent/AgentMessageParts.d.ts +54 -0
- package/dist/ai/components/agent/PermissionPicker.d.ts +11 -0
- package/dist/ai/components/attachmentKeys.d.ts +4 -0
- package/dist/ai/core/ChatProvider.d.ts +66 -0
- package/dist/ai/core/KeyboardShortcutsProvider.d.ts +5 -0
- package/dist/ai/core/chatReducer.d.ts +114 -0
- package/dist/ai/core/config.d.ts +47 -0
- package/dist/ai/core/events.d.ts +1 -0
- package/dist/ai/core/exportConversation.d.ts +4 -0
- package/dist/ai/core/greeting.d.ts +3 -0
- package/dist/ai/core/parts.d.ts +11 -0
- package/dist/ai/core/useDragDrop.d.ts +14 -0
- package/dist/ai/core/useKeyboardShortcuts.d.ts +12 -0
- package/dist/ai/core/useSSEStream.d.ts +34 -0
- package/dist/ai/index.d.ts +40 -0
- package/dist/ai/index.js +6645 -0
- package/dist/ai/strings.d.ts +167 -0
- package/dist/ai/types.d.ts +236 -0
- package/dist/ai/ui/Avatar.d.ts +8 -0
- package/dist/ai/ui/Dropdown.d.ts +31 -0
- package/dist/ai/ui/Markdown.d.ts +8 -0
- package/dist/ai/ui/Notice.d.ts +21 -0
- package/dist/ai/ui/buttons.d.ts +1 -0
- package/dist/ai/ui/codeBreaks.d.ts +16 -0
- package/dist/ai/ui/prose.d.ts +1 -0
- package/dist/ai/ui/sidebar.d.ts +81 -0
- package/dist/ai/utils.d.ts +4 -0
- package/dist/assets/{editor.worker-CuBRIwi-.js → editor.worker-BmHUIVG4.js} +194 -163
- package/dist/assets/{json.worker-8ytS02vz.js → json.worker-D8bJ92nw.js} +384 -338
- package/dist/assets/{yaml.worker-DJC-VUcv.js → yaml.worker-C4gyGAko.js} +15657 -13823
- package/dist/chunks/{CodePreviewEditor-UAtnpmOV.js → CodePreviewEditor-YqQBz1YL.js} +2 -2
- package/dist/chunks/ConfirmModal-aOR4O1QE.js +79 -0
- package/dist/chunks/{lib-CUTRDpa6.js → FieldWrapper-Cszwg-4B.js} +52 -55
- package/dist/chunks/{CreateModal-BbV5cTj7.js → Markdown-CM-FenNE.js} +25 -97
- package/dist/chunks/Monaco-DJ8MW-Dq.js +110 -0
- package/dist/chunks/{PageHeader-MxuOs9cH.js → PageHeader-0kG_iypP.js} +170 -105
- package/dist/chunks/{Provider-DHmZ3v9i.js → Provider-CDYurraE.js} +60 -24
- package/dist/chunks/{SwitchToggle-BRQoEwLZ.js → SwitchToggle-DShNdcao.js} +143 -140
- package/dist/chunks/{Table-C6JdFFiJ.js → Table-DU2MW8xz.js} +6 -4
- package/dist/chunks/{Tooltip-n9w7Tkt1.js → Tooltip-K5HJr4_p.js} +32 -5
- package/dist/chunks/duration-BOv8Phl8.js +17 -0
- package/dist/chunks/{editor-mNznodJN.js → editor-Dk1rbV75.js} +33 -19
- package/dist/chunks/focus-D_iZJTW1.js +7 -0
- package/dist/chunks/{list-7k0eaI5N.js → list-CJm875m7.js} +497 -379
- package/dist/chunks/logviewer-BTKuQWzw.js +828 -0
- package/dist/chunks/memoryStore-CC91S5LP.js +152 -0
- package/dist/chunks/types-Yy0NrerF.js +11 -0
- package/dist/components/AddMenu.d.ts +1 -0
- package/dist/components/Avatar.d.ts +13 -0
- package/dist/components/Breadcrumbs.d.ts +1 -1
- package/dist/components/Dropdown.d.ts +3 -1
- package/dist/components/EmptyState.d.ts +1 -1
- package/dist/components/Indicator.d.ts +2 -2
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/LetterBadge.d.ts +1 -1
- package/dist/components/MarkdownImpl.d.ts +1 -1
- package/dist/components/Provider.d.ts +18 -65
- package/dist/components/SettingRow.d.ts +1 -1
- package/dist/components/SettingsGroup.d.ts +1 -1
- package/dist/components/focus.d.ts +2 -0
- package/dist/components/keys.d.ts +12 -0
- package/dist/duration.d.ts +3 -0
- package/dist/editor/Monaco.d.ts +1 -20
- package/dist/editor/index.d.ts +2 -1
- package/dist/editor/index.js +2 -2
- package/dist/editor/yaml.d.ts +5 -0
- package/dist/engine.d.ts +98 -0
- package/dist/file-explorer/FileExplorer.d.ts +11 -2
- package/dist/file-explorer/FileExplorerContext.d.ts +1 -1
- package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +1 -1
- package/dist/file-explorer/FilePreview/previewType.d.ts +1 -1
- package/dist/file-explorer/FileRow.d.ts +1 -1
- package/dist/file-explorer/helpers.d.ts +4 -4
- package/dist/file-explorer/index.d.ts +3 -3
- package/dist/file-explorer/index.js +632 -665
- package/dist/file-explorer/lib/types.d.ts +6 -1
- package/dist/file-explorer/lib/utils.d.ts +1 -3
- package/dist/file-explorer/useNearEnd.d.ts +1 -1
- package/dist/form/FieldWrapper.d.ts +2 -1
- package/dist/form/Fields/ResourceOptionIcon.d.ts +1 -1
- package/dist/form/Form.d.ts +7 -22
- package/dist/form/index.d.ts +11 -12
- package/dist/form/index.js +1333 -1454
- package/dist/form/lib.d.ts +6 -1
- package/dist/form/types/fieldComponentTypes.d.ts +4 -2
- package/dist/form/types/fieldTypes.d.ts +6 -20
- package/dist/form/useParsedOpts.d.ts +2 -2
- package/dist/form/utils/{slurmDuration.d.ts → duration.d.ts} +2 -2
- package/dist/{workflow → graph}/MatrixGroup.d.ts +2 -2
- package/dist/{workflow → graph}/index.d.ts +1 -1
- package/dist/{workflow → graph}/index.js +220 -185
- package/dist/{workflow → graph}/types.d.ts +3 -3
- package/dist/icons.d.ts +20 -21
- package/dist/icons.js +3 -3
- package/dist/index.d.ts +38 -39
- package/dist/index.js +355 -354
- package/dist/list/ListTable.d.ts +1 -1
- package/dist/list/ListViewControls.d.ts +2 -2
- package/dist/list/RowContextMenu.d.ts +9 -9
- package/dist/list/UserHoverCard.d.ts +45 -0
- package/dist/list/index.d.ts +9 -8
- package/dist/list/index.js +3 -3
- package/dist/logviewer/LogViewer.d.ts +1 -1
- package/dist/logviewer/index.d.ts +1 -0
- package/dist/logviewer/index.js +2 -742
- package/dist/logviewer/segments.d.ts +9 -0
- package/dist/styles/Geist-Variable.woff2 +0 -0
- package/dist/styles/GeistMono-Variable.woff2 +0 -0
- package/dist/styles/base.css +57 -0
- package/dist/styles/fonts.css +15 -0
- package/dist/styles/theme.css +9 -41
- package/dist/styles.css +1 -1
- package/dist/theme/index.js +2 -2
- package/package.json +45 -20
- package/LICENSE +0 -21
- package/dist/chunks/Monaco-DVyIpyv4.js +0 -1046
- package/dist/editor/usesGitlab.d.ts +0 -97
- package/dist/form/Fields/BucketReadOnlyField.d.ts +0 -7
- package/dist/form/types/workflow-schema.d.ts +0 -1145
- package/dist/form/utils/pwResolver.d.ts +0 -18
- package/dist/chunks/{BareModal-BqroLbZ5.js → BareModal-BtRiQezg.js} +1 -1
- package/dist/chunks/{MarkdownImpl-Bq4QhrtA.js → MarkdownImpl-CyeTVvSt.js} +1 -1
- /package/dist/{workflow → graph}/AnnotationBanner.d.ts +0 -0
- /package/dist/{workflow → graph}/Collapse.d.ts +0 -0
- /package/dist/{workflow → graph}/DependencyGraph.d.ts +0 -0
- /package/dist/{workflow → graph}/JobSummary.d.ts +0 -0
- /package/dist/{workflow → graph}/Reveal.d.ts +0 -0
- /package/dist/{workflow → graph}/TreeView.d.ts +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { t as ChatAdapterError } from "./types-Yy0NrerF.js";
|
|
2
|
+
//#region src/ai/adapter/memoryStore.ts
|
|
3
|
+
function newId() {
|
|
4
|
+
return crypto.randomUUID();
|
|
5
|
+
}
|
|
6
|
+
function createMemoryConversationStore(options) {
|
|
7
|
+
const storageKey = options?.storageKey;
|
|
8
|
+
let conversations = [];
|
|
9
|
+
if (storageKey) try {
|
|
10
|
+
const raw = globalThis.localStorage?.getItem(storageKey);
|
|
11
|
+
if (raw) conversations = JSON.parse(raw);
|
|
12
|
+
} catch {
|
|
13
|
+
conversations = [];
|
|
14
|
+
}
|
|
15
|
+
const persist = () => {
|
|
16
|
+
if (storageKey) try {
|
|
17
|
+
globalThis.localStorage?.setItem(storageKey, JSON.stringify(conversations));
|
|
18
|
+
} catch {}
|
|
19
|
+
};
|
|
20
|
+
const find = (id) => {
|
|
21
|
+
const conversation = conversations.find((c) => c.id === id);
|
|
22
|
+
if (!conversation) throw new ChatAdapterError("Conversation not found", { status: 404 });
|
|
23
|
+
return conversation;
|
|
24
|
+
};
|
|
25
|
+
const toSummary = (c) => ({
|
|
26
|
+
id: c.id,
|
|
27
|
+
...c.title !== null ? { title: c.title } : {},
|
|
28
|
+
messageCount: c.messages.length,
|
|
29
|
+
createdAt: c.createdAt,
|
|
30
|
+
updatedAt: c.updatedAt,
|
|
31
|
+
isOwner: true,
|
|
32
|
+
canCollaborate: true
|
|
33
|
+
});
|
|
34
|
+
const recordUser = (req) => {
|
|
35
|
+
const conversation = conversations.find((c) => c.id === req.conversationId);
|
|
36
|
+
if (!conversation) return;
|
|
37
|
+
const last = req.messages[req.messages.length - 1];
|
|
38
|
+
const userContent = typeof last?.content === "string" ? last.content : "";
|
|
39
|
+
conversation.messages.push({
|
|
40
|
+
id: req.userMessageId,
|
|
41
|
+
role: "user",
|
|
42
|
+
content: userContent,
|
|
43
|
+
parentId: req.parentMessageId ?? null,
|
|
44
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
45
|
+
});
|
|
46
|
+
conversation.activeBranchId = req.userMessageId;
|
|
47
|
+
conversation.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
48
|
+
persist();
|
|
49
|
+
};
|
|
50
|
+
const recordAssistant = (req, assistant) => {
|
|
51
|
+
const conversation = conversations.find((c) => c.id === req.conversationId);
|
|
52
|
+
if (!conversation) return;
|
|
53
|
+
conversation.messages.push({
|
|
54
|
+
...assistant,
|
|
55
|
+
role: "assistant"
|
|
56
|
+
});
|
|
57
|
+
conversation.activeBranchId = assistant.id;
|
|
58
|
+
conversation.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
59
|
+
persist();
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
conversations: {
|
|
63
|
+
async list() {
|
|
64
|
+
return [...conversations].sort((a, b) => b.createdAt.localeCompare(a.createdAt)).map(toSummary);
|
|
65
|
+
},
|
|
66
|
+
async get(id) {
|
|
67
|
+
const c = find(id);
|
|
68
|
+
return {
|
|
69
|
+
id: c.id,
|
|
70
|
+
title: c.title,
|
|
71
|
+
messages: [...c.messages],
|
|
72
|
+
activeBranchId: c.activeBranchId,
|
|
73
|
+
createdAt: c.createdAt,
|
|
74
|
+
updatedAt: c.updatedAt,
|
|
75
|
+
isOwner: true,
|
|
76
|
+
canCollaborate: true
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async create(title) {
|
|
80
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
81
|
+
const conversation = {
|
|
82
|
+
id: newId(),
|
|
83
|
+
title: title ?? null,
|
|
84
|
+
createdAt: now,
|
|
85
|
+
updatedAt: now,
|
|
86
|
+
activeBranchId: null,
|
|
87
|
+
messages: []
|
|
88
|
+
};
|
|
89
|
+
conversations.push(conversation);
|
|
90
|
+
persist();
|
|
91
|
+
return toSummary(conversation);
|
|
92
|
+
},
|
|
93
|
+
async rename(id, title) {
|
|
94
|
+
find(id).title = title;
|
|
95
|
+
persist();
|
|
96
|
+
},
|
|
97
|
+
async remove(id) {
|
|
98
|
+
conversations = conversations.filter((c) => c.id !== id);
|
|
99
|
+
persist();
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
recordingStream(inner) {
|
|
103
|
+
return async (req, handlers, signal) => {
|
|
104
|
+
let partialContent = "";
|
|
105
|
+
let partialReasoning = "";
|
|
106
|
+
const wrappedHandlers = {
|
|
107
|
+
...handlers,
|
|
108
|
+
onContent: (chunk) => {
|
|
109
|
+
partialContent += chunk;
|
|
110
|
+
handlers.onContent(chunk);
|
|
111
|
+
},
|
|
112
|
+
onReasoning: (chunk) => {
|
|
113
|
+
partialReasoning += chunk;
|
|
114
|
+
handlers.onReasoning?.(chunk);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
recordUser(req);
|
|
118
|
+
try {
|
|
119
|
+
const result = await inner(req, wrappedHandlers, signal);
|
|
120
|
+
const assistantId = result.messageId || newId();
|
|
121
|
+
recordAssistant(req, {
|
|
122
|
+
id: assistantId,
|
|
123
|
+
content: result.content || null,
|
|
124
|
+
parentId: req.userMessageId,
|
|
125
|
+
model: result.model ?? req.model,
|
|
126
|
+
...result.reasoning ? { reasoning: result.reasoning } : {},
|
|
127
|
+
...result.responsesOutput.length ? { responsesOutput: result.responsesOutput } : {},
|
|
128
|
+
...result.toolCalls.length ? { toolCalls: result.toolCalls } : {},
|
|
129
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
...result,
|
|
133
|
+
messageId: assistantId
|
|
134
|
+
};
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (error instanceof DOMException && error.name === "AbortError" && (partialContent || partialReasoning)) recordAssistant(req, {
|
|
137
|
+
id: newId(),
|
|
138
|
+
content: partialContent || null,
|
|
139
|
+
parentId: req.userMessageId,
|
|
140
|
+
model: req.model,
|
|
141
|
+
...partialReasoning ? { reasoning: partialReasoning } : {},
|
|
142
|
+
stopped: true,
|
|
143
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
144
|
+
});
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { createMemoryConversationStore as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/ai/adapter/types.ts
|
|
2
|
+
var ChatAdapterError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message, options?.cause === void 0 ? {} : { cause: options.cause });
|
|
6
|
+
this.name = "ChatAdapterError";
|
|
7
|
+
this.status = options?.status;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { ChatAdapterError as t };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type AvatarSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
|
2
|
+
export type AvatarStatus = 'online' | 'offline' | 'busy' | 'away';
|
|
3
|
+
export interface AvatarProps {
|
|
4
|
+
/** Image URL; absent or failing to load shows the initials of `name`. */
|
|
5
|
+
src?: string | null | undefined;
|
|
6
|
+
name?: string | undefined;
|
|
7
|
+
size?: AvatarSize | undefined;
|
|
8
|
+
status?: AvatarStatus | undefined;
|
|
9
|
+
className?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Up to two initials: the first and last word of a name split on spaces and dots. */
|
|
12
|
+
export declare function avatarInitials(name: string | undefined): string;
|
|
13
|
+
export declare function Avatar({ src, name, size, status, className }: AvatarProps): import("react").JSX.Element;
|
|
@@ -20,7 +20,7 @@ interface BreadcrumbContextType {
|
|
|
20
20
|
claimedPath: React.MutableRefObject<string | null>;
|
|
21
21
|
}
|
|
22
22
|
export declare const useBreadcrumb: () => BreadcrumbContextType;
|
|
23
|
-
export declare function BreadcrumbProvider({ children
|
|
23
|
+
export declare function BreadcrumbProvider({ children }: {
|
|
24
24
|
children: React.ReactNode;
|
|
25
25
|
}): React.JSX.Element;
|
|
26
26
|
export declare function useSetBreadcrumbs(getBreadcrumbs: (() => IBreadcrumbItem[]) | IBreadcrumbItem[]): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SetStateAction } from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ICategory, type IOptions } from './dropdownUtils.js';
|
|
3
3
|
export interface IProps {
|
|
4
4
|
options: (ICategory | IOptions | string)[];
|
|
5
5
|
onActiveChange?: (option: unknown) => void;
|
|
@@ -24,5 +24,7 @@ export interface IProps {
|
|
|
24
24
|
/** Label for the toggle row hiding a category's collapsible options. */
|
|
25
25
|
collapsedLabel?: (count: number) => string;
|
|
26
26
|
portalEl?: HTMLElement;
|
|
27
|
+
/** Smaller option rows and text, for dense toolbars. */
|
|
28
|
+
compact?: boolean | undefined;
|
|
27
29
|
}
|
|
28
30
|
export default function Dropdown(props: IProps): import("react").JSX.Element;
|
|
@@ -7,5 +7,5 @@ interface EmptyStateProps {
|
|
|
7
7
|
className?: string;
|
|
8
8
|
}>;
|
|
9
9
|
}
|
|
10
|
-
export default function EmptyState({ title, description, action, icon: Icon
|
|
10
|
+
export default function EmptyState({ title, description, action, icon: Icon }: EmptyStateProps): React.JSX.Element;
|
|
11
11
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { InputHTMLAttributes,
|
|
1
|
+
import type { InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from 'react';
|
|
2
2
|
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
3
3
|
label?: ReactNode;
|
|
4
4
|
error?: string | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** A compact letter badge ("AI", "PUB", "SSH") used as a type mark in place of
|
|
2
2
|
* an icon. Size the box and text via className (e.g. "h-5 w-5 text-[8px]"). */
|
|
3
|
-
export declare function LetterBadge({ text, className
|
|
3
|
+
export declare function LetterBadge({ text, className }: {
|
|
4
4
|
text: string;
|
|
5
5
|
className?: string;
|
|
6
6
|
}): import("react").JSX.Element;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { MarkdownProps } from './Markdown.js';
|
|
2
|
-
export default function Markdown({ children, isStreaming, controls
|
|
2
|
+
export default function Markdown({ children, isStreaming, controls }: MarkdownProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { WorkflowEngine } from '../engine.js';
|
|
3
|
+
import type { RunLink } from '../graph/types.js';
|
|
3
4
|
export type UIToastId = string | number;
|
|
4
5
|
export interface UIToastOptions {
|
|
5
6
|
toastId?: UIToastId;
|
|
@@ -55,6 +56,7 @@ export interface UIStrings {
|
|
|
55
56
|
create: string;
|
|
56
57
|
remove: string;
|
|
57
58
|
sort: string;
|
|
59
|
+
userAvatar: string;
|
|
58
60
|
};
|
|
59
61
|
dropdown: {
|
|
60
62
|
select: (type: string) => string;
|
|
@@ -243,6 +245,7 @@ export interface UIStrings {
|
|
|
243
245
|
collapse: string;
|
|
244
246
|
upload: string;
|
|
245
247
|
download: string;
|
|
248
|
+
downloadFromBrowser: string;
|
|
246
249
|
access: string;
|
|
247
250
|
manageAccess: string;
|
|
248
251
|
delete: string;
|
|
@@ -317,10 +320,6 @@ export interface UIStrings {
|
|
|
317
320
|
invalidDuration: string;
|
|
318
321
|
durationOutOfRange: (min: string, max: string) => string;
|
|
319
322
|
durationBelowMin: (min: string) => string;
|
|
320
|
-
readOnly: string;
|
|
321
|
-
readWrite: string;
|
|
322
|
-
readOnlyDescription: string;
|
|
323
|
-
readOnlyForced: string;
|
|
324
323
|
};
|
|
325
324
|
time: {
|
|
326
325
|
now: string;
|
|
@@ -330,6 +329,7 @@ export interface UIStrings {
|
|
|
330
329
|
years: (n: number) => string;
|
|
331
330
|
};
|
|
332
331
|
list: {
|
|
332
|
+
copyMenu: string;
|
|
333
333
|
copy: (label: string) => string;
|
|
334
334
|
copied: (label: string) => string;
|
|
335
335
|
couldntCopy: (label: string) => string;
|
|
@@ -371,18 +371,11 @@ export interface UIStrings {
|
|
|
371
371
|
}
|
|
372
372
|
export interface UINavigation {
|
|
373
373
|
goTo: (to: string) => void;
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
/** Opens the source of a step that runs another workflow, named by its `uses`;
|
|
375
|
+
* `sourceUrl` is a page the server resolved for it, when there is one. */
|
|
376
|
+
openStepSource: (uses: string, sourceUrl?: string) => void;
|
|
376
377
|
openExternal: (href: string) => void;
|
|
377
378
|
}
|
|
378
|
-
export type WorkflowJsonRef = {
|
|
379
|
-
kind: 'marketplace';
|
|
380
|
-
slug: string;
|
|
381
|
-
version: string;
|
|
382
|
-
} | {
|
|
383
|
-
kind: 'workflow';
|
|
384
|
-
name: string;
|
|
385
|
-
};
|
|
386
379
|
export interface RunFileResult {
|
|
387
380
|
data: string | undefined;
|
|
388
381
|
isLoading: boolean;
|
|
@@ -398,11 +391,6 @@ export interface UIData {
|
|
|
398
391
|
useRunFile: (slug: string, path: string | null, options?: {
|
|
399
392
|
refreshInterval?: number;
|
|
400
393
|
}) => RunFileResult;
|
|
401
|
-
/**
|
|
402
|
-
* Resolves a workflow reference to its parsed JSON definition, for the YAML
|
|
403
|
-
* editor's input completion. Absent, that completion silently no-ops.
|
|
404
|
-
*/
|
|
405
|
-
resolveWorkflowJson?: (ref: WorkflowJsonRef) => Promise<unknown>;
|
|
406
394
|
/**
|
|
407
395
|
* Provisions browser-access CORS rules on a storage. Absent, the storage
|
|
408
396
|
* explorer hides its "add CORS rules" affordance.
|
|
@@ -416,48 +404,6 @@ export interface UIData {
|
|
|
416
404
|
error?: string;
|
|
417
405
|
}>;
|
|
418
406
|
usePersistedState: PersistedStateHook;
|
|
419
|
-
/**
|
|
420
|
-
* Repository completions for `uses:`, bound by the host because the credential
|
|
421
|
-
* lives on the platform. Absent, those completions no-op.
|
|
422
|
-
*/
|
|
423
|
-
repoSuggestions?: {
|
|
424
|
-
refs: (repo: string) => Promise<RepoRef[]>;
|
|
425
|
-
files: (repo: string, ref: string, path: string) => Promise<RepoEntry[]>;
|
|
426
|
-
file: (repo: string, ref: string, path: string) => Promise<string>;
|
|
427
|
-
repos: (owner: string) => Promise<RepoSummary[]>;
|
|
428
|
-
gitlabProjects: (search: string, host?: string) => Promise<GitlabProject[]>;
|
|
429
|
-
owners: (provider: 'github' | 'gitlab', search: string, host?: string) => Promise<RepoOwner[]>;
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
/** One branch, tag or commit a `uses:` reference can name. */
|
|
433
|
-
export interface RepoRef {
|
|
434
|
-
name: string;
|
|
435
|
-
kind: string;
|
|
436
|
-
detail: string;
|
|
437
|
-
}
|
|
438
|
-
/** One repository in an owner listing. */
|
|
439
|
-
export interface RepoSummary {
|
|
440
|
-
name: string;
|
|
441
|
-
description: string;
|
|
442
|
-
private: boolean;
|
|
443
|
-
}
|
|
444
|
-
/** One account, organization or group a repository can live under. */
|
|
445
|
-
export interface RepoOwner {
|
|
446
|
-
name: string;
|
|
447
|
-
kind: string;
|
|
448
|
-
host?: string | undefined;
|
|
449
|
-
}
|
|
450
|
-
/** One GitLab project, with the server a $host must name to reach it. */
|
|
451
|
-
export interface GitlabProject {
|
|
452
|
-
path: string;
|
|
453
|
-
host: string;
|
|
454
|
-
description: string;
|
|
455
|
-
private: boolean;
|
|
456
|
-
}
|
|
457
|
-
/** One entry in a repository directory listing. */
|
|
458
|
-
export interface RepoEntry {
|
|
459
|
-
path: string;
|
|
460
|
-
type: 'blob' | 'tree';
|
|
461
407
|
}
|
|
462
408
|
import type { FieldComponent } from '../form/fieldRegistry.js';
|
|
463
409
|
import type { PageHeaderCrumb } from './PageHeader.js';
|
|
@@ -528,25 +474,31 @@ export interface UISlots {
|
|
|
528
474
|
* trail — the host's app-nav toggle. Absent hides it. */
|
|
529
475
|
navToggle?: () => ReactNode;
|
|
530
476
|
}
|
|
477
|
+
/** An engine, or a loader so the host can keep the engine out of its first-load bundle. */
|
|
478
|
+
export type WorkflowEngineSource = WorkflowEngine | (() => Promise<WorkflowEngine>);
|
|
531
479
|
export interface UIProviderValue {
|
|
532
480
|
notify: UINotify;
|
|
533
481
|
strings: UIStrings;
|
|
534
482
|
navigation: UINavigation;
|
|
535
483
|
data: UIData;
|
|
536
484
|
slots: UISlots;
|
|
485
|
+
engine?: WorkflowEngineSource | undefined;
|
|
537
486
|
}
|
|
538
487
|
export declare function useNotify(): UINotify;
|
|
539
488
|
export declare function useStrings(): UIStrings;
|
|
540
489
|
export declare function useNavigation(): UINavigation;
|
|
541
490
|
export declare function useSlots(): UISlots;
|
|
542
|
-
|
|
491
|
+
/** The engine when one is provided and `enabled`; suspends while a loader resolves. */
|
|
492
|
+
export declare function useOptionalWorkflowEngine(enabled?: boolean): WorkflowEngine | undefined;
|
|
493
|
+
export declare function useWorkflowEngine(): WorkflowEngine;
|
|
494
|
+
/** Resolves the engine without suspending, for async callers such as editor completions. */
|
|
495
|
+
export declare function useWorkflowEngineLoader(): () => Promise<WorkflowEngine | undefined>;
|
|
543
496
|
export declare function useProvisionCorsRules(): UIData['provisionCorsRules'];
|
|
544
|
-
export declare function useRepoSuggestions(): UIData['repoSuggestions'];
|
|
545
497
|
export declare function useRunFile(slug: string, path: string | null, options?: {
|
|
546
498
|
refreshInterval?: number;
|
|
547
499
|
}): RunFileResult;
|
|
548
500
|
export declare function usePersistedState<T>(key: string, defaultValue: T): [T, Dispatch<SetStateAction<T>>];
|
|
549
|
-
export declare function UIProvider({ notify, strings, navigation, data, slots, children, }: {
|
|
501
|
+
export declare function UIProvider({ notify, strings, navigation, data, slots, engine, children, }: {
|
|
550
502
|
notify?: Partial<UINotify>;
|
|
551
503
|
strings?: {
|
|
552
504
|
[G in keyof UIStrings]?: UIStrings[G] extends object ? Partial<UIStrings[G]> : UIStrings[G];
|
|
@@ -554,5 +506,6 @@ export declare function UIProvider({ notify, strings, navigation, data, slots, c
|
|
|
554
506
|
navigation?: Partial<UINavigation>;
|
|
555
507
|
data?: Partial<UIData>;
|
|
556
508
|
slots?: UISlots;
|
|
509
|
+
engine?: WorkflowEngineSource;
|
|
557
510
|
children: React.ReactNode;
|
|
558
511
|
}): import("react").JSX.Element;
|
|
@@ -12,7 +12,7 @@ export declare function SettingRow({ label, htmlFor, helpText, children, isFirst
|
|
|
12
12
|
* double toggle. */
|
|
13
13
|
onClick?: () => void;
|
|
14
14
|
}): import("react").JSX.Element;
|
|
15
|
-
export declare function SettingSection({ title, isFirst
|
|
15
|
+
export declare function SettingSection({ title, isFirst }: {
|
|
16
16
|
title: string;
|
|
17
17
|
isFirst?: boolean;
|
|
18
18
|
}): import("react").JSX.Element;
|
|
@@ -4,5 +4,5 @@ interface SettingsGroupProps {
|
|
|
4
4
|
children: React.ReactNode;
|
|
5
5
|
className?: string;
|
|
6
6
|
}
|
|
7
|
-
export default function SettingsGroup({ title, children, className
|
|
7
|
+
export default function SettingsGroup({ title, children, className }: SettingsGroupProps): React.JSX.Element;
|
|
8
8
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Pairs each item with a React key from its content, suffixing repeats so keys stay unique. */
|
|
2
|
+
export declare function keyedByContent<T>(items: readonly T[], toKey: (item: T) => string): {
|
|
3
|
+
key: string;
|
|
4
|
+
item: T;
|
|
5
|
+
}[];
|
|
6
|
+
/** Keys for a list whose position is its identity, such as placeholder rows or a fixed grid. */
|
|
7
|
+
export declare function positionKeys(count: number, prefix?: string): string[];
|
|
8
|
+
/** Pairs each item of a list that never reorders with a key from its position. */
|
|
9
|
+
export declare function withPositionKeys<T>(items: readonly T[], prefix?: string): {
|
|
10
|
+
key: string;
|
|
11
|
+
item: T;
|
|
12
|
+
}[];
|
package/dist/editor/Monaco.d.ts
CHANGED
|
@@ -1,20 +1,4 @@
|
|
|
1
1
|
import * as monaco from 'monaco-editor';
|
|
2
|
-
export interface EditorMarketplaceItem {
|
|
3
|
-
readonly slug?: string;
|
|
4
|
-
readonly name?: string | null;
|
|
5
|
-
readonly description?: string | null;
|
|
6
|
-
readonly type?: string | null;
|
|
7
|
-
readonly subtype?: string | null;
|
|
8
|
-
readonly versions?: readonly string[] | null;
|
|
9
|
-
}
|
|
10
|
-
export interface EditorWorkflowItem {
|
|
11
|
-
readonly name?: string;
|
|
12
|
-
readonly displayName?: string | null;
|
|
13
|
-
readonly description?: string | null;
|
|
14
|
-
readonly type?: string | null;
|
|
15
|
-
}
|
|
16
|
-
type MarketplaceItem = EditorMarketplaceItem;
|
|
17
|
-
type WorkflowItem = EditorWorkflowItem;
|
|
18
2
|
export type ISchemaError = monaco.editor.IMarker;
|
|
19
3
|
export interface IEditorProps extends monaco.editor.IStandaloneEditorConstructionOptions {
|
|
20
4
|
className?: string;
|
|
@@ -24,8 +8,5 @@ export interface IEditorProps extends monaco.editor.IStandaloneEditorConstructio
|
|
|
24
8
|
width?: string | number;
|
|
25
9
|
height?: string | number;
|
|
26
10
|
path?: 'file:///workflow.yaml' | string;
|
|
27
|
-
marketplaceItems?: MarketplaceItem[];
|
|
28
|
-
workflows?: WorkflowItem[];
|
|
29
11
|
}
|
|
30
|
-
export default function MonacoEditor({ className, disabled, onChange, onValidate, width, height, path,
|
|
31
|
-
export {};
|
|
12
|
+
export default function MonacoEditor({ className, disabled, onChange, onValidate, width, height, path, ...options }: IEditorProps): import("react").JSX.Element;
|
package/dist/editor/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as Editor } from './Editor.js';
|
|
2
2
|
export { default as EditorField, type IEditorField } from './EditorField.js';
|
|
3
3
|
export { default as FormCodePanel } from './FormCodePanel.js';
|
|
4
|
-
export type {
|
|
4
|
+
export type { IEditorProps, ISchemaError } from './Monaco.js';
|
|
5
5
|
export { defineEditorThemes, getThemeName } from './themes.js';
|
|
6
6
|
export { setupMonacoWorkers } from './workers.js';
|
|
7
|
+
export { configureEditorYaml } from './yaml.js';
|
package/dist/editor/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { Editor, EditorField, FormCodePanel, defineEditorThemes, getThemeName, setupMonacoWorkers };
|
|
1
|
+
import { a as getThemeName, c as Editor, i as defineEditorThemes, o as FormCodePanel, r as setupMonacoWorkers, s as EditorField, t as configureEditorYaml } from "../chunks/editor-Dk1rbV75.js";
|
|
2
|
+
export { Editor, EditorField, FormCodePanel, configureEditorYaml, defineEditorThemes, getThemeName, setupMonacoWorkers };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SchemasSettings } from 'monaco-yaml';
|
|
2
|
+
/** Adds JSON schemas that validate and complete YAML models whose URI matches. */
|
|
3
|
+
export declare function configureEditorYaml(added: SchemasSettings[]): void;
|
|
4
|
+
/** Lets the loaded editor pick up schemas added before or after it loads. */
|
|
5
|
+
export declare function onYamlSchemas(listener: (schemas: SchemasSettings[]) => void): void;
|
package/dist/engine.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export type RunStatus = 'started' | 'running' | 'completed' | 'error' | 'failed' | 'canceled' | 'skipped' | 'faulted' | 'canceling' | 'skipped-failed' | '' | undefined;
|
|
2
|
+
export interface MatrixGroup {
|
|
3
|
+
originaljob: string;
|
|
4
|
+
members: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface LogSegment {
|
|
7
|
+
content: string;
|
|
8
|
+
className: string;
|
|
9
|
+
highlighted?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface LogCommand {
|
|
12
|
+
type: 'error' | 'warning' | 'notice' | 'debug' | 'group' | 'endgroup';
|
|
13
|
+
message: string;
|
|
14
|
+
params?: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
export interface ProcessedLogLine {
|
|
17
|
+
index: number;
|
|
18
|
+
segments: LogSegment[];
|
|
19
|
+
command?: LogCommand;
|
|
20
|
+
groupDepth: number;
|
|
21
|
+
groupId?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface WorkflowVariable {
|
|
24
|
+
key?: string;
|
|
25
|
+
value?: string | null;
|
|
26
|
+
secret?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export type WorkflowVariables = Record<string, WorkflowVariable>;
|
|
29
|
+
export interface EvaluateOptions<T> {
|
|
30
|
+
inputs: unknown;
|
|
31
|
+
obj: T;
|
|
32
|
+
path?: string[];
|
|
33
|
+
schema?: unknown;
|
|
34
|
+
orgVars?: WorkflowVariables | undefined;
|
|
35
|
+
userVars?: Record<string, string>;
|
|
36
|
+
remoteVars?: Record<string, string | undefined> | undefined;
|
|
37
|
+
secretKeys?: string[];
|
|
38
|
+
appInfo?: Record<string, unknown>;
|
|
39
|
+
sessionInfo?: Record<string, string>;
|
|
40
|
+
index?: number | undefined;
|
|
41
|
+
}
|
|
42
|
+
export interface ExpansionKeys {
|
|
43
|
+
subworkflowKeys: string[];
|
|
44
|
+
jobKeys: string[];
|
|
45
|
+
matrixKeys: string[];
|
|
46
|
+
}
|
|
47
|
+
export interface EngineJob {
|
|
48
|
+
status?: RunStatus;
|
|
49
|
+
needs?: string[];
|
|
50
|
+
if?: boolean | string;
|
|
51
|
+
steps?: unknown[];
|
|
52
|
+
_matrix?: {
|
|
53
|
+
originaljob?: string;
|
|
54
|
+
index?: number;
|
|
55
|
+
};
|
|
56
|
+
_matrixGroup?: MatrixGroup;
|
|
57
|
+
}
|
|
58
|
+
export interface EngineStep {
|
|
59
|
+
name?: string | undefined;
|
|
60
|
+
run?: string;
|
|
61
|
+
uses?: string;
|
|
62
|
+
subworkflow?: unknown;
|
|
63
|
+
}
|
|
64
|
+
/** The workflow semantics the form, graph, editor and log viewer defer to. */
|
|
65
|
+
export interface WorkflowEngine {
|
|
66
|
+
/** Starts loading the expression runtime; safe to call repeatedly. */
|
|
67
|
+
init(): void;
|
|
68
|
+
isReady(): boolean;
|
|
69
|
+
/** Calls back when readiness changes; returns an unsubscribe function. */
|
|
70
|
+
onReady(listener: (ready: boolean) => void): () => void;
|
|
71
|
+
/** Resolves every `${{ }}` expression in `obj`. */
|
|
72
|
+
evaluate<T>(options: EvaluateOptions<T>): T;
|
|
73
|
+
/** Turns a workflow's input definitions into the form's field tree. */
|
|
74
|
+
convertInputs(inputs: Record<string, unknown>): Record<string, unknown>;
|
|
75
|
+
inputDependencies(obj: unknown): {
|
|
76
|
+
inputDeps: Set<string>;
|
|
77
|
+
hasExpressions: boolean;
|
|
78
|
+
};
|
|
79
|
+
jobDependencies(jobName: string, jobs: Record<string, {
|
|
80
|
+
needs?: string[];
|
|
81
|
+
}>, memo?: Record<string, Set<string>>): Set<string>;
|
|
82
|
+
matrixGroups(jobs: Record<string, EngineJob> | undefined): Record<string, MatrixGroup>;
|
|
83
|
+
/** Rewrites `visibleJobs` in place so each matrix group lays out as one node. */
|
|
84
|
+
collapseMatrixGroups(groups: Record<string, MatrixGroup>, visibleJobs: Record<string, EngineJob>): void;
|
|
85
|
+
expansionKeys(jobs: Record<string, EngineJob> | undefined, pathPrefix?: string): ExpansionKeys;
|
|
86
|
+
matrixStatus(statuses: RunStatus[]): {
|
|
87
|
+
aggStatus: RunStatus;
|
|
88
|
+
statusLabel: string;
|
|
89
|
+
};
|
|
90
|
+
stepLabel(step: EngineStep, index?: number): string;
|
|
91
|
+
stepLogPath(subworkflowPrefix: string, jobName: string, stepIndex: number | string): string;
|
|
92
|
+
isRunActive(status: string | null | undefined): boolean;
|
|
93
|
+
processLogLines(lines: {
|
|
94
|
+
index: number;
|
|
95
|
+
segments: LogSegment[];
|
|
96
|
+
}[], rawLines: string[]): ProcessedLogLine[];
|
|
97
|
+
toYaml(value: unknown): string;
|
|
98
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IFileExplorerClient, IFileExplorerProvider } from './lib/fileExplorer.js';
|
|
2
|
-
import type { TreeNode, TStorage } from './lib/types.js';
|
|
2
|
+
import type { ExplorerObject, TreeNode, TStorage } from './lib/types.js';
|
|
3
3
|
interface IFileExplorerProps {
|
|
4
4
|
storages: TStorage[];
|
|
5
5
|
/** Resolves the storage's injected provider pair; the host owns caching. */
|
|
@@ -33,6 +33,15 @@ interface IFileExplorerProps {
|
|
|
33
33
|
initialExpandedPaths?: readonly string[];
|
|
34
34
|
/** Fires whenever the expanded folders change, for the host to persist. */
|
|
35
35
|
onExpandedPathsChange?: (paths: string[]) => void;
|
|
36
|
+
/** URIs that name an object, shown on its details and offered under Copy;
|
|
37
|
+
* the first is what Copy URI copies. None hides them. */
|
|
38
|
+
objectUris?: ((storage: TStorage, key: string) => string[]) | undefined;
|
|
39
|
+
/** A shell command that downloads files, offered beside the browser
|
|
40
|
+
* download. An empty command hides it for that selection. */
|
|
41
|
+
downloadCommand?: {
|
|
42
|
+
label: string;
|
|
43
|
+
build: (objects: ExplorerObject[]) => string;
|
|
44
|
+
} | undefined;
|
|
36
45
|
}
|
|
37
|
-
export default function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHierarchy, groups, groupsLoading, selectedPath, onPathChange, getProviderAndClient, treeOnly, initialExpandedPaths, onExpandedPathsChange, }: IFileExplorerProps): import("react").JSX.Element;
|
|
46
|
+
export default function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHierarchy, groups, groupsLoading, selectedPath, onPathChange, getProviderAndClient, treeOnly, initialExpandedPaths, onExpandedPathsChange, objectUris, downloadCommand, }: IFileExplorerProps): import("react").JSX.Element;
|
|
38
47
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TreeNode, UploadFileProgress, UploadNode, UploadSession } from './lib/types.js';
|
|
2
1
|
import type { IFileExplorerClient, IFileExplorerProvider } from './lib/fileExplorer.js';
|
|
2
|
+
import type { TreeNode, UploadFileProgress, UploadNode, UploadSession } from './lib/types.js';
|
|
3
3
|
interface IFileExplorerContextValue {
|
|
4
4
|
uploadSessionMap: Map<string, UploadSession>;
|
|
5
5
|
uploadQueue: string[];
|
|
@@ -2,5 +2,5 @@ interface CodePreviewEditorProps {
|
|
|
2
2
|
value: string;
|
|
3
3
|
language: string;
|
|
4
4
|
}
|
|
5
|
-
export default function CodePreviewEditor({ value, language
|
|
5
|
+
export default function CodePreviewEditor({ value, language }: CodePreviewEditorProps): import("react").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getFileExtension } from '../lib/utils.js';
|
|
2
1
|
import type { TreeNode } from '../lib/types.js';
|
|
2
|
+
import { getFileExtension } from '../lib/utils.js';
|
|
3
3
|
export { getFileExtension };
|
|
4
4
|
export type PreviewKind = 'image' | 'video' | 'audio' | 'pdf' | 'code' | 'csv' | 'notebook' | 'archive' | 'unsupported';
|
|
5
5
|
/** Short-lived so the link doesn't linger; an hour covers a viewing session. */
|