@parallelworks/ui 0.45.0 → 0.47.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 +16 -5
- package/dist/ai/agent/permissions.d.ts +1 -1
- package/dist/ai/agent/permissions.js +1 -1
- package/dist/ai/ai.css +4 -4
- package/dist/ai/components/ChatInput.js +1 -1
- package/dist/ai/components/ChatStage.d.ts +1 -1
- package/dist/ai/components/ChatStage.js +1 -1
- package/dist/ai/core/pasteLanguage.d.ts +1 -1
- package/dist/ai/core/pasteLanguage.js +1 -1
- package/dist/brandIcons.js +1 -1
- package/dist/components/ColorInput.d.ts +36 -0
- package/dist/components/ColorInput.js +82 -0
- package/dist/components/Combobox.d.ts +5 -2
- package/dist/components/Combobox.js +12 -11
- package/dist/components/CreateModal.js +2 -2
- package/dist/components/DatePicker.d.ts +5 -1
- package/dist/components/DatePicker.js +7 -7
- package/dist/components/Field.d.ts +19 -5
- package/dist/components/Field.js +21 -4
- package/dist/components/Input.d.ts +11 -1
- package/dist/components/Input.js +9 -6
- package/dist/components/Loader.d.ts +1 -1
- package/dist/components/MenuEntries.js +1 -1
- package/dist/components/NumberInput.d.ts +1 -0
- package/dist/components/OneTimeCodeInput.d.ts +23 -0
- package/dist/components/OneTimeCodeInput.js +39 -0
- package/dist/components/Provider.d.ts +15 -6
- package/dist/components/Provider.js +17 -5
- package/dist/components/SearchInput.d.ts +1 -0
- package/dist/components/Section.d.ts +7 -2
- package/dist/components/Section.js +58 -39
- package/dist/components/SegmentedControl.d.ts +4 -2
- package/dist/components/SegmentedControl.js +4 -2
- package/dist/components/Select.d.ts +2 -1
- package/dist/components/Select.js +1 -1
- package/dist/components/StatusBadge.d.ts +2 -2
- package/dist/components/StatusBadge.js +1 -1
- package/dist/components/Tabs.js +1 -0
- package/dist/components/ThemeEditor.js +15 -52
- package/dist/components/Toast.js +1 -1
- package/dist/components/ToggleGroup.d.ts +42 -0
- package/dist/components/ToggleGroup.js +69 -0
- package/dist/components/comboboxItems.d.ts +1 -1
- package/dist/components/fieldBox.js +1 -1
- package/dist/components/tone.d.ts +1 -1
- package/dist/editing.d.ts +1 -1
- package/dist/file-explorer/FileExplorerContext.js +11 -11
- package/dist/file-explorer/FilePreview/useObjectBlobUrl.js +4 -4
- package/dist/file-explorer/FilePreview/useObjectText.js +4 -4
- package/dist/file-explorer/FilePreview/usePresignedUrl.js +4 -4
- package/dist/file-explorer/lib/types.d.ts +2 -2
- package/dist/file-explorer/toasts.js +9 -9
- package/dist/form/Fields/BooleanField.js +1 -1
- package/dist/form/Fields/ColorField.js +6 -10
- package/dist/form/Fields/DropdownField.js +1 -1
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Fields/MultiDropdownField.js +1 -1
- package/dist/form/Fields/StringField.js +1 -1
- package/dist/form/Fields/TextAreaField.js +1 -1
- package/dist/form/Form.js +1 -1
- package/dist/form/utils/fieldItems.d.ts +1 -1
- package/dist/graph/GraphEditorDialogs.js +1 -1
- package/dist/graph/InputDialog.js +2 -2
- package/dist/graph/SuggestionInput.d.ts +1 -1
- package/dist/graph/SuggestionInput.js +1 -1
- package/dist/graph/WorkflowSettingsDialog.js +1 -1
- package/dist/graph/editorFields.js +2 -2
- package/dist/graph/editorPrimitives.d.ts +2 -2
- package/dist/graph/editorPrimitives.js +1 -1
- package/dist/graph/editorStrings.d.ts +2 -2
- package/dist/graph/editorStrings.js +4 -4
- package/dist/graph/inputRefs.js +2 -2
- package/dist/graph/stepWith.js +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +14 -10
- package/dist/list/ListViewControls.js +1 -1
- package/dist/list/listSearch.js +1 -1
- package/dist/logviewer/segments.d.ts +1 -1
- package/dist/logviewer/segments.js +1 -1
- package/dist/styles/theme.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +3 -0
- package/dist/theme/derive.js +11 -7
- package/package.json +1 -1
package/dist/components/Toast.js
CHANGED
|
@@ -135,7 +135,7 @@ function ToastViewport() {
|
|
|
135
135
|
return /* @__PURE__ */ jsx(Toast.Portal, { children: /* @__PURE__ */ jsx(Toast.Viewport, {
|
|
136
136
|
"data-toast-viewport": "",
|
|
137
137
|
"aria-label": common.notifications,
|
|
138
|
-
className: "fixed inset-
|
|
138
|
+
className: "fixed top-[calc(var(--app-inset-top,0px)+0.75rem)] right-0 left-(--app-inset-start,0px) z-(--layer-toast) mx-auto w-[calc(100vw-var(--app-inset-start,0px)-2rem)] outline-none sm:w-96",
|
|
139
139
|
children: /* @__PURE__ */ jsx(ToastList, {})
|
|
140
140
|
}) });
|
|
141
141
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface ToggleGroupOption<T extends string> {
|
|
3
|
+
value: T;
|
|
4
|
+
label: string;
|
|
5
|
+
/** Before the label, such as a `StatusDot` in the status's tone or a provider's logo. */
|
|
6
|
+
icon?: ReactNode;
|
|
7
|
+
/** How many items the option matches, after the label. */
|
|
8
|
+
count?: number | undefined;
|
|
9
|
+
disabled?: boolean | undefined;
|
|
10
|
+
testId?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ToggleGroupProps<T extends string> {
|
|
13
|
+
/** Names the group for assistive technology. Leave it out inside a
|
|
14
|
+
* `Field group`, whose legend names it. */
|
|
15
|
+
label?: string | undefined;
|
|
16
|
+
options: readonly ToggleGroupOption<T>[];
|
|
17
|
+
/** The pressed options. Empty filters nothing out. */
|
|
18
|
+
value: readonly T[];
|
|
19
|
+
/** Called with the pressed options in the order `options` lists them. */
|
|
20
|
+
onValueChange: (value: T[]) => void;
|
|
21
|
+
/** Several options may be pressed at once; `false` allows one or none. */
|
|
22
|
+
multiple?: boolean | undefined;
|
|
23
|
+
/** Leads with an "All" option, pressed while nothing else is, that clears
|
|
24
|
+
* the others. `{ count }` shows the total beside it. */
|
|
25
|
+
all?: boolean | {
|
|
26
|
+
count?: number | undefined;
|
|
27
|
+
} | undefined;
|
|
28
|
+
size?: 'sm' | 'md' | undefined;
|
|
29
|
+
disabled?: boolean | undefined;
|
|
30
|
+
testId?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Options that narrow a list, such as run statuses or job states, as a row of
|
|
33
|
+
* toggle buttons that wraps on a narrow screen. Pressing one adds it to the
|
|
34
|
+
* filter and pressing it again takes it out, so an empty filter shows
|
|
35
|
+
* everything; with `multiple={false}` pressing one replaces the last. Each
|
|
36
|
+
* option may carry an icon, such as a status dot, and a count.
|
|
37
|
+
*
|
|
38
|
+
* Use `SegmentedControl` instead for a setting that always has exactly one
|
|
39
|
+
* value, such as a time range, what to group by, or which view of the same
|
|
40
|
+
* data to show. A filter that may be off, or takes several values, is a
|
|
41
|
+
* `ToggleGroup`. */
|
|
42
|
+
export declare function ToggleGroup<T extends string>({ label, options, value, onValueChange, multiple, all, size, disabled, testId, }: ToggleGroupProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { cx } from "../cx.js";
|
|
2
|
+
import { buttonClasses } from "./buttonClasses.js";
|
|
3
|
+
import { useStrings } from "./Provider.js";
|
|
4
|
+
import { formatCount } from "../format.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Toggle } from "@base-ui/react/toggle";
|
|
7
|
+
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
8
|
+
//#region src/components/ToggleGroup.tsx
|
|
9
|
+
var ALL = "\0all";
|
|
10
|
+
/** Options that narrow a list, such as run statuses or job states, as a row of
|
|
11
|
+
* toggle buttons that wraps on a narrow screen. Pressing one adds it to the
|
|
12
|
+
* filter and pressing it again takes it out, so an empty filter shows
|
|
13
|
+
* everything; with `multiple={false}` pressing one replaces the last. Each
|
|
14
|
+
* option may carry an icon, such as a status dot, and a count.
|
|
15
|
+
*
|
|
16
|
+
* Use `SegmentedControl` instead for a setting that always has exactly one
|
|
17
|
+
* value, such as a time range, what to group by, or which view of the same
|
|
18
|
+
* data to show. A filter that may be off, or takes several values, is a
|
|
19
|
+
* `ToggleGroup`. */
|
|
20
|
+
function ToggleGroup$1({ label, options, value, onValueChange, multiple = true, all = false, size = "sm", disabled = false, testId }) {
|
|
21
|
+
const strings = useStrings();
|
|
22
|
+
const allCount = typeof all === "object" ? all.count : void 0;
|
|
23
|
+
const pressed = all && value.length === 0 ? [ALL] : value;
|
|
24
|
+
return /* @__PURE__ */ jsxs(ToggleGroup, {
|
|
25
|
+
"aria-label": label,
|
|
26
|
+
"data-testid": testId,
|
|
27
|
+
className: "flex flex-wrap items-center gap-1",
|
|
28
|
+
multiple,
|
|
29
|
+
disabled,
|
|
30
|
+
value: pressed,
|
|
31
|
+
onValueChange: (next) => {
|
|
32
|
+
if (next.includes(ALL) && !pressed.includes(ALL)) {
|
|
33
|
+
onValueChange([]);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
onValueChange(options.filter((option) => next.includes(option.value)).map((option) => option.value));
|
|
37
|
+
},
|
|
38
|
+
children: [all && /* @__PURE__ */ jsx(Chip, {
|
|
39
|
+
value: ALL,
|
|
40
|
+
label: strings.common.all,
|
|
41
|
+
count: allCount,
|
|
42
|
+
size
|
|
43
|
+
}), options.map((option) => /* @__PURE__ */ jsx(Chip, {
|
|
44
|
+
...option,
|
|
45
|
+
size
|
|
46
|
+
}, option.value))]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function Chip({ value, label, icon, count, disabled, testId, size }) {
|
|
50
|
+
return /* @__PURE__ */ jsxs(Toggle, {
|
|
51
|
+
value,
|
|
52
|
+
disabled,
|
|
53
|
+
"data-testid": testId,
|
|
54
|
+
className: cx("group aria-pressed:bg-(--theme-accent-subtle)", buttonClasses({
|
|
55
|
+
variant: "outline",
|
|
56
|
+
size
|
|
57
|
+
})),
|
|
58
|
+
children: [
|
|
59
|
+
icon,
|
|
60
|
+
label,
|
|
61
|
+
count !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
62
|
+
className: "tabular-nums text-(--theme-muted-text-color) group-aria-pressed:text-(--theme-app)",
|
|
63
|
+
children: formatCount(count)
|
|
64
|
+
})
|
|
65
|
+
]
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ToggleGroup$1 as ToggleGroup };
|
|
@@ -15,7 +15,7 @@ export interface ComboboxGroup<Value = string> {
|
|
|
15
15
|
/** Empty for a group that only reports a status; a search finds it by its heading. */
|
|
16
16
|
items: readonly ComboboxLeaf<Value>[];
|
|
17
17
|
}
|
|
18
|
-
/** One item: an option, or a bare string
|
|
18
|
+
/** One item: an option, or a bare string labeled by its value. */
|
|
19
19
|
export type ComboboxLeaf<Value = string> = ComboboxItem<Value> | (Value & string);
|
|
20
20
|
/** Items, groups under headings, or both: items between groups list where they sit, without a heading. */
|
|
21
21
|
export type ComboboxItems<Value = string> = readonly (ComboboxLeaf<Value> | ComboboxGroup<Value>)[];
|
|
@@ -16,7 +16,7 @@ var sizes = {
|
|
|
16
16
|
text: "text-sm"
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
-
var base = "w-full min-w-0 rounded-md border border-(--theme-border) bg-(--theme-input-bg) text-(--theme-app) outline-none transition-colors placeholder:text-(--theme-
|
|
19
|
+
var base = "w-full min-w-0 rounded-md border border-(--theme-border) bg-(--theme-input-bg) text-(--theme-app) outline-none transition-colors placeholder:text-(--theme-placeholder)";
|
|
20
20
|
var own = cx("focus-visible:border-(--theme-accent) focus-visible:ring-1 focus-visible:ring-(--theme-accent)", "aria-invalid:border-(--theme-error) aria-invalid:focus-visible:ring-(--theme-error)", "disabled:cursor-not-allowed disabled:bg-(--theme-input-disabled-bg) disabled:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
|
|
21
21
|
var inside = cx("has-[:focus-visible]:border-(--theme-accent) has-[:focus-visible]:ring-1 has-[:focus-visible]:ring-(--theme-accent)", "has-[[aria-invalid=true]]:border-(--theme-error) has-[[aria-invalid=true]:focus-visible]:ring-(--theme-error)", "has-[input:disabled]:cursor-not-allowed has-[input:disabled]:bg-(--theme-input-disabled-bg) has-[input:disabled]:text-(--theme-placeholder)", "data-disabled:cursor-not-allowed data-disabled:bg-(--theme-input-disabled-bg) data-disabled:text-(--theme-placeholder)");
|
|
22
22
|
/** The box every input-like control draws: text inputs, textareas, and the triggers of
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** How a status reads: its
|
|
1
|
+
/** How a status reads: its colors come from the theme's tone tokens, so every
|
|
2
2
|
* theme, dark ones included, sets them once. */
|
|
3
3
|
export type Tone = 'default' | 'success' | 'warning' | 'error' | 'info' | 'muted';
|
|
4
4
|
/** Text in the tone, for a status line beside a dot or icon. */
|
package/dist/editing.d.ts
CHANGED
|
@@ -320,7 +320,7 @@ export type SettingsYamlProblem = {
|
|
|
320
320
|
/** A key or list index on the way down to a YAML node. */
|
|
321
321
|
export type YamlSegment = string | number;
|
|
322
322
|
type UnknownRecord = Record<string, unknown>;
|
|
323
|
-
/** One input a built-in action takes in its step's `with`,
|
|
323
|
+
/** One input a built-in action takes in its step's `with`, labeled in the reader's language. */
|
|
324
324
|
export interface WorkflowActionInput {
|
|
325
325
|
key: string;
|
|
326
326
|
kind: 'text' | 'textarea' | 'number' | 'any' | 'list' | 'bool' | 'choice' | 'flags' | 'target';
|
|
@@ -107,7 +107,7 @@ function FileExplorerProvider({ children }) {
|
|
|
107
107
|
const fileProgress = session.progress.allFiles.get(relativePath);
|
|
108
108
|
if (fileProgress?.abortController && (fileProgress.status === "pending" || fileProgress.status === "uploading")) {
|
|
109
109
|
fileProgress.abortController.abort();
|
|
110
|
-
updateFileProgressInUploadSession(session, relativePath, { status: "
|
|
110
|
+
updateFileProgressInUploadSession(session, relativePath, { status: "canceled" });
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
113
|
const handleSessionCancel = (session) => {
|
|
@@ -116,12 +116,12 @@ function FileExplorerProvider({ children }) {
|
|
|
116
116
|
fileProgress.abortController.abort();
|
|
117
117
|
session.progress?.allFiles?.set(relativePath, {
|
|
118
118
|
...fileProgress,
|
|
119
|
-
status: "
|
|
119
|
+
status: "canceled"
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
});
|
|
123
123
|
session.abortController?.abort();
|
|
124
|
-
session.status = "
|
|
124
|
+
session.status = "canceled";
|
|
125
125
|
};
|
|
126
126
|
const startUploadSession = async (sessionId) => {
|
|
127
127
|
const session = getUploadSessionById(sessionId);
|
|
@@ -157,7 +157,7 @@ function FileExplorerProvider({ children }) {
|
|
|
157
157
|
const results = await mapWithConcurrency(session.uploadNodes, UPLOAD_CONCURRENCY, async (node) => {
|
|
158
158
|
const fileProgress = session.progress?.allFiles?.get(node.relativePath);
|
|
159
159
|
if (!fileProgress) return;
|
|
160
|
-
if (fileProgress.status === "
|
|
160
|
+
if (fileProgress.status === "canceled") throw new Error("Upload canceled by user");
|
|
161
161
|
updateFileProgressInUploadSession(session, node.relativePath, {
|
|
162
162
|
status: "uploading",
|
|
163
163
|
loadedBytes: 0,
|
|
@@ -172,11 +172,11 @@ function FileExplorerProvider({ children }) {
|
|
|
172
172
|
}
|
|
173
173
|
const input = uploadFileInput(session.storageName, objectPath, node.file);
|
|
174
174
|
const onProgress = (progress) => {
|
|
175
|
-
if (session.status === "
|
|
175
|
+
if (session.status === "canceled" || !session.progress?.allFiles) return;
|
|
176
176
|
const currentFileProgress = session.progress.allFiles.get(node.relativePath);
|
|
177
177
|
if (!currentFileProgress || [
|
|
178
178
|
"failed",
|
|
179
|
-
"
|
|
179
|
+
"canceled",
|
|
180
180
|
"completed"
|
|
181
181
|
].includes(currentFileProgress.status ?? "")) return;
|
|
182
182
|
updateFileProgressInUploadSession(session, node.relativePath, {
|
|
@@ -205,8 +205,8 @@ function FileExplorerProvider({ children }) {
|
|
|
205
205
|
updateFileProgressInUploadSession(session, node.relativePath, { status: "completed" });
|
|
206
206
|
} catch (error) {
|
|
207
207
|
const errorMessage = error instanceof Error ? error.message : String(error ?? "");
|
|
208
|
-
const
|
|
209
|
-
updateFileProgressInUploadSession(session, node.relativePath, { status:
|
|
208
|
+
const isCanceled = errorMessage.toLowerCase().includes("abort") || errorMessage.toLowerCase().includes("cancel");
|
|
209
|
+
updateFileProgressInUploadSession(session, node.relativePath, { status: isCanceled ? "canceled" : "failed" });
|
|
210
210
|
toast.update(sessionId, {
|
|
211
211
|
message: progressToast({
|
|
212
212
|
...session,
|
|
@@ -218,7 +218,7 @@ function FileExplorerProvider({ children }) {
|
|
|
218
218
|
}
|
|
219
219
|
}),
|
|
220
220
|
icon: false,
|
|
221
|
-
dismissible: session.status === "failed" || session.status === "
|
|
221
|
+
dismissible: session.status === "failed" || session.status === "canceled",
|
|
222
222
|
timeout: false
|
|
223
223
|
});
|
|
224
224
|
throw error;
|
|
@@ -267,12 +267,12 @@ function FileExplorerProvider({ children }) {
|
|
|
267
267
|
else if (abortedCount > 0 && successfulCount > 0) toast.update(sessionId, {
|
|
268
268
|
message: /* @__PURE__ */ jsxs("div", {
|
|
269
269
|
className: "w-full flex flex-col gap-1",
|
|
270
|
-
children: [/* @__PURE__ */ jsx("div", { children: t.upload.someUploaded(successfulCount) }), /* @__PURE__ */ jsx("div", { children: t.upload.
|
|
270
|
+
children: [/* @__PURE__ */ jsx("div", { children: t.upload.someUploaded(successfulCount) }), /* @__PURE__ */ jsx("div", { children: t.upload.someCanceled(abortedCount) })]
|
|
271
271
|
}),
|
|
272
272
|
tone: "success"
|
|
273
273
|
});
|
|
274
274
|
else if (abortedCount > 0 && successfulCount === 0) toast.update(sessionId, {
|
|
275
|
-
message: t.upload.
|
|
275
|
+
message: t.upload.allCanceled(abortedCount),
|
|
276
276
|
tone: "info"
|
|
277
277
|
});
|
|
278
278
|
else toast.update(sessionId, {
|
|
@@ -34,7 +34,7 @@ function useObjectBlobUrl(url, { maxBytes, knownSize, mimeType, cacheKey }) {
|
|
|
34
34
|
});
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
let
|
|
37
|
+
let canceled = false;
|
|
38
38
|
const record = loadPreviewContent(cacheKey, async (signal) => {
|
|
39
39
|
const response = await fetchPreviewObject(cacheKey, url, signal);
|
|
40
40
|
const { bytes, tooLarge: exceeded } = await readCappedBytes(response, maxBytes);
|
|
@@ -52,17 +52,17 @@ function useObjectBlobUrl(url, { maxBytes, knownSize, mimeType, cacheKey }) {
|
|
|
52
52
|
loading: true
|
|
53
53
|
});
|
|
54
54
|
record.promise.then((result) => {
|
|
55
|
-
if (!
|
|
55
|
+
if (!canceled) setState(toState(result));
|
|
56
56
|
}).catch((err) => {
|
|
57
57
|
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
58
|
-
if (!
|
|
58
|
+
if (!canceled) setState({
|
|
59
59
|
...IDLE,
|
|
60
60
|
error: err instanceof Error ? err.message : "Failed to load file",
|
|
61
61
|
corsError: err instanceof CorsError
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
return () => {
|
|
65
|
-
|
|
65
|
+
canceled = true;
|
|
66
66
|
};
|
|
67
67
|
}, [
|
|
68
68
|
url,
|
|
@@ -60,7 +60,7 @@ function useObjectText(url, { maxBytes, maxLines, knownSize, cacheKey, tail = fa
|
|
|
60
60
|
});
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
let
|
|
63
|
+
let canceled = false;
|
|
64
64
|
const record = loadPreviewContent(key, (signal) => readObjectText(signal, {
|
|
65
65
|
url,
|
|
66
66
|
cacheKey,
|
|
@@ -74,17 +74,17 @@ function useObjectText(url, { maxBytes, maxLines, knownSize, cacheKey, tail = fa
|
|
|
74
74
|
loading: true
|
|
75
75
|
});
|
|
76
76
|
record.promise.then((result) => {
|
|
77
|
-
if (!
|
|
77
|
+
if (!canceled) setState(toState(result));
|
|
78
78
|
}).catch((err) => {
|
|
79
79
|
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
80
|
-
if (!
|
|
80
|
+
if (!canceled) setState({
|
|
81
81
|
...IDLE,
|
|
82
82
|
error: err instanceof Error ? err.message : "Failed to load file",
|
|
83
83
|
corsError: err instanceof CorsError
|
|
84
84
|
});
|
|
85
85
|
});
|
|
86
86
|
return () => {
|
|
87
|
-
|
|
87
|
+
canceled = true;
|
|
88
88
|
};
|
|
89
89
|
}, [
|
|
90
90
|
url,
|
|
@@ -46,7 +46,7 @@ function usePresignedUrl(node, getPresignedUrl, { enabled, linkErrorMessage }) {
|
|
|
46
46
|
});
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
let
|
|
49
|
+
let canceled = false;
|
|
50
50
|
const record = loadPreviewUrl(path, () => getUrlRef.current(node));
|
|
51
51
|
setState(record.value ? toState(record.value, linkErrorRef.current) : {
|
|
52
52
|
url: null,
|
|
@@ -54,16 +54,16 @@ function usePresignedUrl(node, getPresignedUrl, { enabled, linkErrorMessage }) {
|
|
|
54
54
|
error: null
|
|
55
55
|
});
|
|
56
56
|
record.promise.then((result) => {
|
|
57
|
-
if (!
|
|
57
|
+
if (!canceled) setState(toState(result, linkErrorRef.current));
|
|
58
58
|
}).catch((err) => {
|
|
59
|
-
if (!
|
|
59
|
+
if (!canceled) setState({
|
|
60
60
|
url: null,
|
|
61
61
|
loading: false,
|
|
62
62
|
error: err instanceof Error ? err.message : linkErrorRef.current
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
65
|
return () => {
|
|
66
|
-
|
|
66
|
+
canceled = true;
|
|
67
67
|
};
|
|
68
68
|
}, [path]);
|
|
69
69
|
const cached = path ? peekPreviewUrl(path) : void 0;
|
|
@@ -79,14 +79,14 @@ export interface UploadFileProgress {
|
|
|
79
79
|
totalBytes?: number;
|
|
80
80
|
percentage?: number;
|
|
81
81
|
abortController?: AbortController;
|
|
82
|
-
status?: 'pending' | 'uploading' | 'completed' | 'failed' | '
|
|
82
|
+
status?: 'pending' | 'uploading' | 'completed' | 'failed' | 'canceled';
|
|
83
83
|
}
|
|
84
84
|
export interface UploadSession {
|
|
85
85
|
id: string;
|
|
86
86
|
storageName: string;
|
|
87
87
|
targetPath: string;
|
|
88
88
|
uploadNodes: UploadNode[];
|
|
89
|
-
status: 'queued' | 'uploading' | 'completed' | 'failed' | '
|
|
89
|
+
status: 'queued' | 'uploading' | 'completed' | 'failed' | 'canceled';
|
|
90
90
|
queueIndex: number;
|
|
91
91
|
client: IFileExplorerClient;
|
|
92
92
|
provider: IFileExplorerProvider;
|
|
@@ -42,9 +42,9 @@ function getSessionStatusInfo(session, queueLength, strings) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
function barTone({ isCompleted,
|
|
45
|
+
function barTone({ isCompleted, isCanceled, isFailed }) {
|
|
46
46
|
if (isCompleted) return "success";
|
|
47
|
-
if (
|
|
47
|
+
if (isCanceled) return "muted";
|
|
48
48
|
return isFailed ? "error" : "accent";
|
|
49
49
|
}
|
|
50
50
|
function FileProgressBar({ fileProgress, fileName, onCancelFile }) {
|
|
@@ -55,9 +55,9 @@ function FileProgressBar({ fileProgress, fileName, onCancelFile }) {
|
|
|
55
55
|
const loadedBytes = fileProgress.loadedBytes || 0;
|
|
56
56
|
const totalBytes = fileProgress.fileSizeBytes || fileProgress.totalBytes || 0;
|
|
57
57
|
const isCompleted = percentage === 100 || fileProgress.status === "completed";
|
|
58
|
-
const
|
|
58
|
+
const isCanceled = fileProgress.status === "canceled";
|
|
59
59
|
const isFailed = fileProgress.status === "failed";
|
|
60
|
-
const isSettled = isCompleted ||
|
|
60
|
+
const isSettled = isCompleted || isCanceled || isFailed;
|
|
61
61
|
const canCancel = !!fileProgress.abortController && !isSettled;
|
|
62
62
|
const stop = (e, then) => {
|
|
63
63
|
e.stopPropagation();
|
|
@@ -71,11 +71,11 @@ function FileProgressBar({ fileProgress, fileName, onCancelFile }) {
|
|
|
71
71
|
value: percentage,
|
|
72
72
|
tone: barTone({
|
|
73
73
|
isCompleted,
|
|
74
|
-
|
|
74
|
+
isCanceled,
|
|
75
75
|
isFailed
|
|
76
76
|
}),
|
|
77
77
|
label: fileName,
|
|
78
|
-
status:
|
|
78
|
+
status: isCanceled ? strings.canceled : isCompleted ? strings.completed : isFailed ? strings.failed : void 0,
|
|
79
79
|
detail: !isSettled && totalBytes > 0 ? `${formatBytes(loadedBytes)} / ${formatBytes(totalBytes)}` : void 0
|
|
80
80
|
}),
|
|
81
81
|
!showCancelConfirm && canCancel && /* @__PURE__ */ jsx(IconButton, {
|
|
@@ -120,14 +120,14 @@ function UploadSessionToast({ session, queueLength, onCancel, onCancelFile }) {
|
|
|
120
120
|
const statusInfo = getSessionStatusInfo(session, queueLength, strings);
|
|
121
121
|
const targetPath = `${session.targetPath}/`;
|
|
122
122
|
const isCompleted = session.status === "completed";
|
|
123
|
-
const
|
|
123
|
+
const isCanceled = session.status === "canceled";
|
|
124
124
|
const isFailed = session.status === "failed";
|
|
125
|
-
const isUploading = !isCompleted && !
|
|
125
|
+
const isUploading = !isCompleted && !isCanceled && !isFailed;
|
|
126
126
|
const totalProgress = session.progress?.overallProgress || 0;
|
|
127
127
|
const totalSize = session.progress?.totalSizeBytes || 0;
|
|
128
128
|
const sessionTone = barTone({
|
|
129
129
|
isCompleted,
|
|
130
|
-
|
|
130
|
+
isCanceled,
|
|
131
131
|
isFailed
|
|
132
132
|
});
|
|
133
133
|
const allFiles = session.progress?.allFiles ? Array.from(session.progress.allFiles.values()) : [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Tooltip } from "../../components/Tooltip.js";
|
|
2
|
-
import { Switch } from "../../components/Switch.js";
|
|
3
2
|
import { Field } from "../../components/Field.js";
|
|
3
|
+
import { Switch } from "../../components/Switch.js";
|
|
4
4
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
5
|
import { useFieldValue } from "../useFieldValue.js";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { cx } from "../../cx.js";
|
|
2
|
-
import { fieldBox } from "../../components/fieldBox.js";
|
|
3
1
|
import { Field } from "../../components/Field.js";
|
|
2
|
+
import { ColorInput } from "../../components/ColorInput.js";
|
|
4
3
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
4
|
import { useFieldValue } from "../useFieldValue.js";
|
|
6
5
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -8,20 +7,17 @@ import { jsx } from "react/jsx-runtime";
|
|
|
8
7
|
function ColorField(props) {
|
|
9
8
|
const { field, disabled, onChange } = props;
|
|
10
9
|
const [value, change] = useFieldValue(field.name ?? "");
|
|
11
|
-
const handleChange = (e) => {
|
|
12
|
-
onChange?.(e.target.value);
|
|
13
|
-
change(e.target.value);
|
|
14
|
-
};
|
|
15
10
|
return /* @__PURE__ */ jsx(Field, {
|
|
16
11
|
...fieldFrame(props),
|
|
17
|
-
children: (control) => /* @__PURE__ */ jsx(
|
|
12
|
+
children: (control) => /* @__PURE__ */ jsx(ColorInput, {
|
|
18
13
|
...control,
|
|
19
|
-
className: cx(fieldBox(), "w-18 cursor-pointer p-1"),
|
|
20
14
|
name: field.name,
|
|
21
15
|
value: value || "#fbbf24",
|
|
22
|
-
type: "color",
|
|
23
16
|
disabled,
|
|
24
|
-
|
|
17
|
+
onValueChange: (color) => {
|
|
18
|
+
onChange?.(color);
|
|
19
|
+
change(color);
|
|
20
|
+
}
|
|
25
21
|
})
|
|
26
22
|
});
|
|
27
23
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Autocomplete, Combobox } from "../../components/Combobox.js";
|
|
2
1
|
import { Field } from "../../components/Field.js";
|
|
2
|
+
import { Autocomplete, Combobox } from "../../components/Combobox.js";
|
|
3
3
|
import { toFieldItems } from "../utils/fieldItems.js";
|
|
4
4
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
5
|
import { useChoiceField } from "../useChoiceField.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useStrings } from "../../components/Provider.js";
|
|
2
2
|
import { Checkbox } from "../../components/Checkbox.js";
|
|
3
|
-
import { fieldBox } from "../../components/fieldBox.js";
|
|
4
3
|
import { Field, FieldOption } from "../../components/Field.js";
|
|
4
|
+
import { fieldBox } from "../../components/fieldBox.js";
|
|
5
5
|
import { fieldFrame } from "../fieldFrame.js";
|
|
6
6
|
import { useFieldValue } from "../useFieldValue.js";
|
|
7
7
|
import { formatDurationText, parseDurationText } from "../utils/duration.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Combobox } from "../../components/Combobox.js";
|
|
2
1
|
import { Field } from "../../components/Field.js";
|
|
2
|
+
import { Combobox } from "../../components/Combobox.js";
|
|
3
3
|
import { toFieldItems } from "../utils/fieldItems.js";
|
|
4
4
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
5
|
import { useFieldValue } from "../useFieldValue.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cx } from "../../cx.js";
|
|
2
|
-
import { fieldBox } from "../../components/fieldBox.js";
|
|
3
2
|
import { Field, RevealToggle } from "../../components/Field.js";
|
|
3
|
+
import { fieldBox } from "../../components/fieldBox.js";
|
|
4
4
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
5
|
import { useFieldValue } from "../useFieldValue.js";
|
|
6
6
|
import { getPlaceholder } from "../utils/getPlaceholder.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cx } from "../../cx.js";
|
|
2
|
-
import { fieldBox } from "../../components/fieldBox.js";
|
|
3
2
|
import { Field } from "../../components/Field.js";
|
|
3
|
+
import { fieldBox } from "../../components/fieldBox.js";
|
|
4
4
|
import { fieldFrame } from "../fieldFrame.js";
|
|
5
5
|
import { useFieldValue } from "../useFieldValue.js";
|
|
6
6
|
import { getPlaceholder } from "../utils/getPlaceholder.js";
|
package/dist/form/Form.js
CHANGED
|
@@ -2,8 +2,8 @@ import { cx } from "../cx.js";
|
|
|
2
2
|
import { Loader } from "../components/Loader.js";
|
|
3
3
|
import { useStrings, useWorkflowEngine } from "../components/Provider.js";
|
|
4
4
|
import { Button } from "../components/Button.js";
|
|
5
|
-
import { InfoTip } from "../components/InfoTip.js";
|
|
6
5
|
import { FieldRowContext } from "../components/Field.js";
|
|
6
|
+
import { InfoTip } from "../components/InfoTip.js";
|
|
7
7
|
import { Section } from "../components/Section.js";
|
|
8
8
|
import { parseWizardConfig } from "./Wizard/utils.js";
|
|
9
9
|
import { inputWidth, resolvedFlag } from "./lib.js";
|
|
@@ -17,7 +17,7 @@ export interface FieldOptionGroup<Value = string> {
|
|
|
17
17
|
category?: string | undefined;
|
|
18
18
|
options: readonly (FieldOptionItem<Value> | string)[];
|
|
19
19
|
}
|
|
20
|
-
/** A dropdown option: a bare string is a choice
|
|
20
|
+
/** A dropdown option: a bare string is a choice labeled by its value. */
|
|
21
21
|
export type FieldOption<Value = string> = string | FieldOptionItem<Value> | FieldOptionGroup<Value>;
|
|
22
22
|
/** A picker item that also sets other fields when chosen, through `secondaryField`. */
|
|
23
23
|
export type ChoiceItem<Value = unknown> = ComboboxItem<Value> & {
|
|
@@ -3,8 +3,8 @@ import { withPositionKeys } from "../components/keys.js";
|
|
|
3
3
|
import { useWorkflowActions, useWorkflowEditing } from "../components/Provider.js";
|
|
4
4
|
import { Checkbox } from "../components/Checkbox.js";
|
|
5
5
|
import { ErrorText, FieldOption } from "../components/Field.js";
|
|
6
|
-
import { IconButton } from "../components/IconButton.js";
|
|
7
6
|
import { Input } from "../components/Input.js";
|
|
7
|
+
import { IconButton } from "../components/IconButton.js";
|
|
8
8
|
import { Select } from "../components/Select.js";
|
|
9
9
|
import { useGraphEditorStrings } from "./editorStrings.js";
|
|
10
10
|
import { asRecord } from "./records.js";
|
|
@@ -3,10 +3,10 @@ import { ArrowDownIcon, ArrowUpIcon, EditIcon, RemoveIcon, TrashIcon } from "../
|
|
|
3
3
|
import { withPositionKeys } from "../components/keys.js";
|
|
4
4
|
import { useWorkflowEditing, useWorkflowEngine } from "../components/Provider.js";
|
|
5
5
|
import { Checkbox, CheckboxGroup } from "../components/Checkbox.js";
|
|
6
|
-
import { Combobox } from "../components/Combobox.js";
|
|
7
6
|
import { ErrorText, Field, FieldOption } from "../components/Field.js";
|
|
8
|
-
import { IconButton } from "../components/IconButton.js";
|
|
9
7
|
import { Input, Textarea } from "../components/Input.js";
|
|
8
|
+
import { Combobox } from "../components/Combobox.js";
|
|
9
|
+
import { IconButton } from "../components/IconButton.js";
|
|
10
10
|
import { useGraphEditorStrings, useInputsEditorStrings } from "./editorStrings.js";
|
|
11
11
|
import { asRecord } from "./records.js";
|
|
12
12
|
import { INPUT_YAML_PATH } from "../editor/settingsYaml.js";
|
|
@@ -4,7 +4,7 @@ export interface Suggestion {
|
|
|
4
4
|
value: string;
|
|
5
5
|
label?: string | undefined;
|
|
6
6
|
}
|
|
7
|
-
/** A
|
|
7
|
+
/** A labeled suggestion shows its meaning, with the value it writes beneath. */
|
|
8
8
|
export declare function suggestionItems(suggestions: Suggestion[]): ComboboxItem[];
|
|
9
9
|
/** A field that takes any typed value, offering `suggestions` as it's typed. */
|
|
10
10
|
export declare function SuggestionInput({ suggestions, ...props }: Omit<AutocompleteProps, 'items' | 'defaultValue'> & {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Autocomplete } from "../components/Combobox.js";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/graph/SuggestionInput.tsx
|
|
4
|
-
/** A
|
|
4
|
+
/** A labeled suggestion shows its meaning, with the value it writes beneath. */
|
|
5
5
|
function suggestionItems(suggestions) {
|
|
6
6
|
return suggestions.map(({ value, label }) => label ? {
|
|
7
7
|
value,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { RemoveIcon } from "../icons.js";
|
|
2
2
|
import { useWorkflowEditing } from "../components/Provider.js";
|
|
3
3
|
import { ErrorText } from "../components/Field.js";
|
|
4
|
-
import { IconButton } from "../components/IconButton.js";
|
|
5
4
|
import { Input } from "../components/Input.js";
|
|
5
|
+
import { IconButton } from "../components/IconButton.js";
|
|
6
6
|
import { useGraphEditorStrings, useInputsEditorStrings } from "./editorStrings.js";
|
|
7
7
|
import { asRecord } from "./records.js";
|
|
8
8
|
import { SETTINGS_YAML_PATH } from "../editor/settingsYaml.js";
|
|
@@ -3,11 +3,11 @@ import { withPositionKeys } from "../components/keys.js";
|
|
|
3
3
|
import { Tooltip } from "../components/Tooltip.js";
|
|
4
4
|
import { Button } from "../components/Button.js";
|
|
5
5
|
import { Checkbox } from "../components/Checkbox.js";
|
|
6
|
+
import { ErrorText, Field } from "../components/Field.js";
|
|
7
|
+
import { Input, Textarea } from "../components/Input.js";
|
|
6
8
|
import { Modal, ModalTitle } from "../components/Modal.js";
|
|
7
9
|
import { Switch } from "../components/Switch.js";
|
|
8
|
-
import { ErrorText, Field } from "../components/Field.js";
|
|
9
10
|
import { IconButton } from "../components/IconButton.js";
|
|
10
|
-
import { Input, Textarea } from "../components/Input.js";
|
|
11
11
|
import { Section } from "../components/Section.js";
|
|
12
12
|
import { SegmentedControl } from "../components/SegmentedControl.js";
|
|
13
13
|
import { useGraphEditorStrings } from "./editorStrings.js";
|
|
@@ -33,7 +33,7 @@ interface DragOptions {
|
|
|
33
33
|
onMove?: (client: Point) => void;
|
|
34
34
|
/** The release; `dragged` tells a drag from a click. */
|
|
35
35
|
onEnd?: (client: Point, dragged: boolean) => void;
|
|
36
|
-
/** A
|
|
36
|
+
/** A canceled pointer, or Escape when `escape` is on. */
|
|
37
37
|
onCancel?: (dragged: boolean) => void;
|
|
38
38
|
/** Escape cancels the press, and goes no further. */
|
|
39
39
|
escape?: boolean;
|
|
@@ -42,7 +42,7 @@ interface DragOptions {
|
|
|
42
42
|
/** The click after the release: swallowed always, only after a drag, or never. */
|
|
43
43
|
swallowClick?: 'always' | 'drag' | 'never';
|
|
44
44
|
}
|
|
45
|
-
/** Follows a press from `start` until it's released or
|
|
45
|
+
/** Follows a press from `start` until it's released or canceled. */
|
|
46
46
|
export declare function trackDrag(start: Point, { onMove, onEnd, onCancel, escape: cancelOnEscape, holdText, swallowClick, }: DragOptions): void;
|
|
47
47
|
export declare function place(box: Box): {
|
|
48
48
|
left: number;
|
|
@@ -69,7 +69,7 @@ function suppressNextClick() {
|
|
|
69
69
|
window.addEventListener("click", swallow, true);
|
|
70
70
|
setTimeout(() => window.removeEventListener("click", swallow, true), 0);
|
|
71
71
|
}
|
|
72
|
-
/** Follows a press from `start` until it's released or
|
|
72
|
+
/** Follows a press from `start` until it's released or canceled. */
|
|
73
73
|
function trackDrag(start, { onMove, onEnd, onCancel, escape: cancelOnEscape = false, holdText, swallowClick = "never" }) {
|
|
74
74
|
let dragged = false;
|
|
75
75
|
const cleanup = () => {
|
|
@@ -203,14 +203,14 @@ export declare const GRAPH_EDITOR_STRINGS: {
|
|
|
203
203
|
default: string;
|
|
204
204
|
always: string;
|
|
205
205
|
failure: string;
|
|
206
|
-
|
|
206
|
+
canceled: string;
|
|
207
207
|
success: string;
|
|
208
208
|
};
|
|
209
209
|
jobConditions: {
|
|
210
210
|
default: string;
|
|
211
211
|
always: string;
|
|
212
212
|
failure: string;
|
|
213
|
-
|
|
213
|
+
canceled: string;
|
|
214
214
|
success: string;
|
|
215
215
|
};
|
|
216
216
|
modeFromInput: string;
|