@exagone313/dsh-podman 0.2.0-rc.4 → 0.3.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 +12 -0
- package/README.zh.md +14 -2
- package/cordis.patch.yml +58 -0
- package/dist/approval-reasons.d.ts +3 -4
- package/dist/approval-reasons.js +40 -49
- package/dist/approval-reasons.test.js +43 -15
- package/dist/approval.js +27 -10
- package/dist/approval.test.js +165 -34
- package/dist/card-route.d.ts +3 -2
- package/dist/card-route.js +103 -35
- package/dist/card-route.test.js +60 -43
- package/dist/card-test-support.js +39 -66
- package/dist/client/ContainerCard.d.ts +1 -1
- package/dist/client/ContainerCard.js +76 -70
- package/dist/client/card-protocol.d.ts +3 -3
- package/dist/client/container-card-caches.js +11 -6
- package/dist/client/container-card-controller.d.ts +13 -18
- package/dist/client/container-card-controller.js +86 -40
- package/dist/client/container-card-create-modal.d.ts +2 -2
- package/dist/client/container-card-create-modal.js +13 -5
- package/dist/client/container-card-default-env.d.ts +10 -0
- package/dist/client/container-card-default-env.js +69 -0
- package/dist/client/container-card-directory.d.ts +2 -2
- package/dist/client/container-card-directory.js +12 -4
- package/dist/client/container-card-editors.d.ts +3 -3
- package/dist/client/container-card-editors.js +104 -32
- package/dist/client/container-card-images.d.ts +4 -4
- package/dist/client/container-card-images.js +19 -6
- package/dist/client/container-card-paths.d.ts +3 -3
- package/dist/client/container-card-paths.js +18 -11
- package/dist/client/container-card-row.d.ts +10 -6
- package/dist/client/container-card-row.js +82 -13
- package/dist/client/container-card-secrets.d.ts +3 -3
- package/dist/client/container-card-secrets.js +8 -6
- package/dist/client/container-card-shared.d.ts +4 -17
- package/dist/client/container-card-shared.js +9 -25
- package/dist/client/container-card-styles.d.ts +2 -8
- package/dist/client/container-card-styles.js +14 -52
- package/dist/client/container-card-volumes.d.ts +2 -2
- package/dist/client/container-card-volumes.js +9 -5
- package/dist/client/container-card-workspace.d.ts +8 -6
- package/dist/client/container-card-workspace.js +9 -3
- package/dist/client/directory-picker.js +2 -1
- package/dist/client/index.js +13109 -2117
- package/dist/client/locales.d.ts +6 -1
- package/dist/client/locales.js +88 -38
- package/dist/client/podman-terminal-guide.d.ts +11 -0
- package/dist/client/podman-terminal-guide.js +208 -0
- package/dist/client/podman-terminal-title.d.ts +7 -0
- package/dist/client/podman-terminal-title.js +30 -0
- package/dist/client/podman-terminal.d.ts +26 -0
- package/dist/client/podman-terminal.js +412 -0
- package/dist/client/read-only-approval.d.ts +2 -2
- package/dist/client/read-only-approval.js +13 -3
- package/dist/client/slot-contract.d.ts +0 -11
- package/dist/client/terminal-preference.d.ts +26 -0
- package/dist/client/terminal-preference.js +67 -0
- package/dist/client/terminal-protocol.d.ts +85 -0
- package/dist/client/terminal-protocol.js +14 -0
- package/dist/client/terminal-tab.d.ts +60 -0
- package/dist/client/terminal-tab.js +35 -0
- package/dist/client/terminal-targets.d.ts +33 -0
- package/dist/client/terminal-targets.js +65 -0
- package/dist/client/terminal-titles.d.ts +23 -0
- package/dist/client/terminal-titles.js +52 -0
- package/dist/client/terminal-transport.d.ts +63 -0
- package/dist/client/terminal-transport.js +207 -0
- package/dist/client/tool-views.js +215 -49
- package/dist/container-env.d.ts +11 -0
- package/dist/container-env.js +96 -0
- package/dist/container-env.test.d.ts +1 -0
- package/dist/container-env.test.js +93 -0
- package/dist/containers.test.js +196 -18
- package/dist/daemons.test.js +18 -4
- package/dist/dsh-version.js +2 -1
- package/dist/env-rows.d.ts +14 -0
- package/dist/env-rows.js +52 -0
- package/dist/env-rows.test.d.ts +1 -0
- package/dist/env-rows.test.js +43 -0
- package/dist/fs-provider.d.ts +1 -0
- package/dist/fs-provider.js +26 -12
- package/dist/fs-provider.test.js +51 -10
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +2 -2
- package/dist/grpc/proto/dshctl/v1/control.proto +8 -1
- package/dist/grpc/proto/dshguest/v1/guest.proto +5 -0
- package/dist/grpc/runtime-client.d.ts +3 -1
- package/dist/grpc/runtime-client.js +90 -17
- package/dist/guest-rpc.d.ts +15 -19
- package/dist/guest-rpc.js +289 -70
- package/dist/guest-rpc.test.d.ts +1 -0
- package/dist/guest-rpc.test.js +241 -0
- package/dist/guest-terminal.d.ts +30 -0
- package/dist/guest-terminal.js +196 -0
- package/dist/images.test.js +10 -3
- package/dist/index.d.ts +11 -16
- package/dist/index.js +42 -36
- package/dist/locales.test.d.ts +1 -0
- package/dist/locales.test.js +34 -0
- package/dist/misc.test.js +38 -10
- package/dist/mount-enums.js +2 -1
- package/dist/mount-input.d.ts +2 -0
- package/dist/mount-input.js +38 -22
- package/dist/mounts.test.js +81 -11
- package/dist/naming.test.d.ts +1 -0
- package/dist/naming.test.js +28 -0
- package/dist/output-reader.js +36 -4
- package/dist/package-deps.test.d.ts +1 -0
- package/dist/package-deps.test.js +49 -0
- package/dist/paths.test.js +4 -2
- package/dist/plugin-meta.test.d.ts +1 -0
- package/dist/plugin-meta.test.js +29 -0
- package/dist/project-path.js +33 -7
- package/dist/project-path.test.js +14 -0
- package/dist/prompts.d.ts +0 -4
- package/dist/prompts.js +15 -84
- package/dist/read-only-shell.js +3 -1
- package/dist/read-only-shell.test.js +80 -25
- package/dist/runtime-client.test.d.ts +1 -0
- package/dist/runtime-client.test.js +53 -0
- package/dist/secrets.test.js +21 -6
- package/dist/settings-commands.test.js +61 -14
- package/dist/settings-create.test.js +32 -10
- package/dist/settings-default-env.test.d.ts +1 -0
- package/dist/settings-default-env.test.js +175 -0
- package/dist/settings-mounts.test.js +46 -7
- package/dist/settings-schema.d.ts +6 -11
- package/dist/settings-schema.js +4 -8
- package/dist/settings-schema.test.d.ts +1 -0
- package/dist/settings-schema.test.js +35 -0
- package/dist/settings-workspaces.test.js +36 -63
- package/dist/spill-store.d.ts +1 -0
- package/dist/spill-store.js +17 -4
- package/dist/spill-store.test.js +31 -8
- package/dist/subprocess.d.ts +4 -0
- package/dist/subprocess.js +148 -162
- package/dist/subprocess.test.js +118 -8
- package/dist/terminal-preference.test.d.ts +1 -0
- package/dist/terminal-preference.test.js +62 -0
- package/dist/terminal-route.d.ts +10 -0
- package/dist/terminal-route.js +270 -0
- package/dist/terminal-route.test.d.ts +1 -0
- package/dist/terminal-route.test.js +265 -0
- package/dist/terminal-sessions.d.ts +69 -0
- package/dist/terminal-sessions.js +252 -0
- package/dist/terminal-shells.d.ts +22 -0
- package/dist/terminal-shells.js +99 -0
- package/dist/terminal-tab.test.d.ts +1 -0
- package/dist/terminal-tab.test.js +58 -0
- package/dist/terminal-targets.test.d.ts +1 -0
- package/dist/terminal-targets.test.js +43 -0
- package/dist/terminal-titles.test.d.ts +1 -0
- package/dist/terminal-titles.test.js +36 -0
- package/dist/test-support.d.ts +35 -5
- package/dist/test-support.js +91 -29
- package/dist/tool-defs.js +19 -4
- package/dist/tool-handlers.js +80 -28
- package/dist/tool-params.js +19 -5
- package/dist/volumes.test.js +1 -1
- package/dist/workspace-binding.d.ts +18 -9
- package/dist/workspace-binding.js +244 -77
- package/dist/workspace-binding.test.js +189 -25
- package/docs/architecture.md +62 -21
- package/docs/architecture.zh.md +57 -13
- package/docs/configuration.md +61 -20
- package/docs/configuration.zh.md +53 -19
- package/docs/development-prompt.md +72 -0
- package/docs/development-prompt.zh.md +69 -0
- package/docs/development.md +141 -21
- package/docs/development.zh.md +125 -17
- package/docs/install-dsh-and-dsh-podman.md +21 -8
- package/docs/install-dsh-and-dsh-podman.zh.md +18 -8
- package/docs/uninstall.md +83 -0
- package/docs/uninstall.zh.md +79 -0
- package/docs/update.md +120 -0
- package/docs/update.zh.md +114 -0
- package/docs/usage.md +108 -61
- package/docs/usage.zh.md +76 -38
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +59 -26
- package/quadlet/dsh-podman-orchestrator.container +46 -0
- package/quadlet/dsh.container +35 -0
- package/LICENSE.pkg +0 -17103
- package/dist/preferences.d.ts +0 -6
- package/dist/preferences.js +0 -27
|
@@ -2,9 +2,9 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
|
|
3
3
|
//
|
|
4
4
|
// SPDX-License-Identifier: MIT
|
|
5
|
-
import { ConfirmButton, Field, namePattern, sanitizeName } from "./container-card-shared.js";
|
|
6
|
-
import { greyId, hint, imageSelect, sectionTitle, wsBody } from "./container-card-styles.js";
|
|
7
|
-
import { Button, DisclosureRow, Input, Modal } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
5
|
+
import { ConfirmButton, Field, namePattern, sanitizeName, } from "./container-card-shared.js";
|
|
6
|
+
import { greyId, hint, imageSelect, sectionTitle, wsBody, } from "./container-card-styles.js";
|
|
7
|
+
import { Button, DisclosureRow, Input, Modal, } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
8
8
|
import { useId, useState } from "react";
|
|
9
9
|
export function SecretRow(props) {
|
|
10
10
|
const { t, name, busy, writable, onSet, onRemove } = props;
|
|
@@ -29,7 +29,7 @@ export function SecretRow(props) {
|
|
|
29
29
|
}, children: name }), _jsx(Input, { type: "password", value: content, disabled: !writable || busy, placeholder: t("setSecret"), onChange: (event) => setContent(event.target.value), onKeyDown: (event) => {
|
|
30
30
|
if (event.key === "Enter")
|
|
31
31
|
submit();
|
|
32
|
-
}, style: { width: "200px" } }), _jsx(ConfirmButton, { t: t, label: t("setSecret"), title: t("confirmTitle"), description: t("confirmSetSecret"), disabled: !writable || !canSave, onConfirm: submit }), _jsx(ConfirmButton, { t: t, label: t("removeSecret"), title: t("confirmTitle"), description: t("confirmRemoveSecret"), disabled: busy, onConfirm: () => onRemove(name) })] }));
|
|
32
|
+
}, style: { width: "200px" } }), _jsx(ConfirmButton, { t: t, label: t("setSecret"), title: t("confirmTitle"), description: t("confirmSetSecret", { secret: name }), disabled: !writable || !canSave, onConfirm: submit }), _jsx(ConfirmButton, { t: t, label: t("removeSecret"), title: t("confirmTitle"), description: t("confirmRemoveSecret", { secret: name }), disabled: !writable || busy, onConfirm: () => onRemove(name) })] }));
|
|
33
33
|
}
|
|
34
34
|
export function SecretsSection(props) {
|
|
35
35
|
const { t, secrets, busy, writable, onCreate, onRemove, onSet } = props;
|
|
@@ -60,12 +60,14 @@ export function SecretsSection(props) {
|
|
|
60
60
|
flexWrap: "wrap",
|
|
61
61
|
alignItems: "center",
|
|
62
62
|
gap: "8px",
|
|
63
|
-
}, children: [_jsx("div", { style: { ...sectionTitle, flex: 1 }, children: t("secretsTitle") }), _jsx(Button, { variant: "outline", size: "sm", disabled: !writable || busy, onClick: () => setOpen(true), children: t("createSecret") })] }), secrets.length === 0 ?
|
|
63
|
+
}, children: [_jsx("div", { style: { ...sectionTitle, flex: 1 }, children: t("secretsTitle") }), _jsx(Button, { variant: "outline", size: "sm", disabled: !writable || busy, onClick: () => setOpen(true), children: t("createSecret") })] }), secrets.length === 0 ? _jsx("p", { style: hint, children: t("none") }) : (secrets.map((secret) => (_jsx(DisclosureRow, { icon: _jsx("span", {}), title: secret.name, open: openSecret === secret.name, expandable: true, onToggle: () => setOpenSecret(openSecret === secret.name ? null : secret.name), children: _jsx("div", { style: wsBody, children: _jsx(SecretRow, { t: t, name: secret.name, busy: busy, writable: writable, onSet: onSet, onRemove: onRemove }) }) }, secret.name)))), _jsx(Modal, { open: open, onClose: () => setOpen(false), title: t("secretsTitle"), closeLabel: t("cancel"), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setOpen(false), children: t("cancel") }), _jsx(Button, { variant: "primary", size: "sm", disabled: !canCreate, onClick: submit, children: t("createSecret") })] }), children: _jsxs("div", { style: {
|
|
64
64
|
display: "flex",
|
|
65
65
|
flexDirection: "column",
|
|
66
66
|
gap: "12px",
|
|
67
67
|
}, children: [_jsxs(Field, { label: t("secretName"), htmlFor: secretNameId, children: [_jsx(Input, { id: secretNameId, value: name, disabled: !writable || busy, autoFocus: true, onChange: (event) => setName(sanitizeName(event.target.value)), onKeyDown: (event) => {
|
|
68
68
|
if (event.key === "Enter")
|
|
69
69
|
submit();
|
|
70
|
-
} }), name !== "" && !namePattern.test(name)
|
|
70
|
+
} }), name !== "" && !namePattern.test(name)
|
|
71
|
+
? _jsx("p", { style: { ...hint, margin: 0 }, children: t("invalidName") })
|
|
72
|
+
: null] }), _jsx(Field, { label: t("secretLength"), htmlFor: secretLengthId, children: _jsx(Input, { id: secretLengthId, type: "number", min: 1, max: 1024, value: length, disabled: !writable || busy, onChange: (event) => setLength(event.target.value) }) }), _jsx(Field, { label: t("secretCharset"), htmlFor: secretCharsetId, children: _jsxs("select", { id: secretCharsetId, style: imageSelect, value: charset, disabled: !writable || busy, onChange: (event) => setCharset(event.target.value), children: [_jsx("option", { value: "alphanumeric", children: "alphanumeric" }), _jsx("option", { value: "hex", children: "hex" }), _jsx("option", { value: "base64url", children: "base64url" })] }) })] }) })] }));
|
|
71
73
|
}
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
import { type MountInput, type ProjectMountView } from "./container-card-controller.js";
|
|
2
|
-
import { type ContainerPluginKey } from "./locales.js";
|
|
2
|
+
import { type ContainerPluginKey, type Translate } from "./locales.js";
|
|
3
3
|
import { type StateDotState } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
4
4
|
import { type ReactNode } from "react";
|
|
5
|
-
export declare function CardChevron({ open }: {
|
|
6
|
-
open: boolean;
|
|
7
|
-
}): ReactNode;
|
|
8
5
|
export declare function containerStateDot(status: string): StateDotState;
|
|
9
|
-
export declare function ConfigField(props: {
|
|
10
|
-
t: (key: ContainerPluginKey) => string;
|
|
11
|
-
label: string;
|
|
12
|
-
value: string;
|
|
13
|
-
current: string;
|
|
14
|
-
writable: boolean;
|
|
15
|
-
onChange: (text: string) => void;
|
|
16
|
-
onSave: () => void;
|
|
17
|
-
onDiscard: () => void;
|
|
18
|
-
}): ReactNode;
|
|
19
6
|
export declare function Field(props: {
|
|
20
7
|
label: string;
|
|
21
8
|
htmlFor: string;
|
|
@@ -31,7 +18,7 @@ export declare const mountViewToInput: (mount: ProjectMountView) => MountInput;
|
|
|
31
18
|
export declare const mountLabel: (t: (key: ContainerPluginKey) => string, mount: MountInput, withMode?: boolean) => string;
|
|
32
19
|
export declare const emptyMount: (kind?: string) => MountInput;
|
|
33
20
|
export declare function ConfirmButton(props: {
|
|
34
|
-
t:
|
|
21
|
+
t: Translate;
|
|
35
22
|
label: string;
|
|
36
23
|
title: string;
|
|
37
24
|
description: string;
|
|
@@ -40,13 +27,13 @@ export declare function ConfirmButton(props: {
|
|
|
40
27
|
onConfirm: () => void;
|
|
41
28
|
}): ReactNode;
|
|
42
29
|
export declare function Chip(props: {
|
|
43
|
-
t:
|
|
30
|
+
t: Translate;
|
|
44
31
|
label: string;
|
|
45
32
|
disabled?: boolean;
|
|
46
33
|
onRemove?: () => void;
|
|
47
34
|
}): ReactNode;
|
|
48
35
|
export declare function TagInput(props: {
|
|
49
|
-
t:
|
|
36
|
+
t: Translate;
|
|
50
37
|
value: readonly string[];
|
|
51
38
|
onChange: (tags: string[]) => void;
|
|
52
39
|
placeholder?: string;
|
|
@@ -3,31 +3,11 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
//
|
|
4
4
|
// SPDX-License-Identifier: MIT
|
|
5
5
|
import { hint } from "./container-card-styles.js";
|
|
6
|
-
import { Button, Input, Modal } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
7
|
-
import {
|
|
8
|
-
export function CardChevron({ open }) {
|
|
9
|
-
return (_jsx("svg", { viewBox: "0 0 14 14", width: "14", height: "14", "aria-hidden": "true", style: {
|
|
10
|
-
flex: "none",
|
|
11
|
-
color: "var(--dsw-alias-label-tertiary)",
|
|
12
|
-
transition: "transform .16s",
|
|
13
|
-
transform: open ? "rotate(180deg)" : undefined,
|
|
14
|
-
}, children: _jsx("path", { d: "M3 5l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
15
|
-
}
|
|
6
|
+
import { Button, Input, Modal, } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
7
|
+
import { useState } from "react";
|
|
16
8
|
export function containerStateDot(status) {
|
|
17
9
|
return status === "running" ? "done" : "error";
|
|
18
10
|
}
|
|
19
|
-
export function ConfigField(props) {
|
|
20
|
-
const { t, label, value, current, writable, onChange, onSave, onDiscard } = props;
|
|
21
|
-
const id = useId();
|
|
22
|
-
const dirty = value !== current;
|
|
23
|
-
return (_jsxs("div", { style: {
|
|
24
|
-
display: "flex",
|
|
25
|
-
flexWrap: "wrap",
|
|
26
|
-
alignItems: "center",
|
|
27
|
-
gap: "8px",
|
|
28
|
-
padding: "8px 0",
|
|
29
|
-
}, children: [_jsx("label", { htmlFor: id, style: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)", minWidth: "110px" }, children: label }), _jsx(Input, { id: id, value: value, disabled: !writable, onChange: (event) => onChange(event.target.value), style: { width: "200px" } }), _jsx(Button, { variant: "outline", size: "sm", disabled: !writable || !dirty, onClick: onSave, children: t("save") }), _jsx(Button, { variant: "ghost", size: "sm", disabled: !dirty, onClick: onDiscard, children: t("discard") })] }));
|
|
30
|
-
}
|
|
31
11
|
export function Field(props) {
|
|
32
12
|
return (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [_jsx("label", { htmlFor: props.htmlFor, style: { fontSize: "13px", color: "var(--dsw-alias-label-secondary)" }, children: props.label }), props.children] }));
|
|
33
13
|
}
|
|
@@ -55,7 +35,7 @@ export const mountViewToInput = (mount) => ({
|
|
|
55
35
|
});
|
|
56
36
|
export const mountLabel = (t, mount, withMode = true) => {
|
|
57
37
|
if (mount.kind === "tmpfs") {
|
|
58
|
-
return
|
|
38
|
+
return `${t("mountTmpfs")}${mount.destination !== "" ? ` ${t("mountAt")} ${mount.destination}` : ""}`;
|
|
59
39
|
}
|
|
60
40
|
if (mount.kind === "volume") {
|
|
61
41
|
return `volume ${mount.volume}${mount.destination !== "" ? ` → ${mount.destination}` : ""}`;
|
|
@@ -63,7 +43,11 @@ export const mountLabel = (t, mount, withMode = true) => {
|
|
|
63
43
|
if (mount.kind === "secret") {
|
|
64
44
|
return `secret ${mount.secret}${mount.destination !== "" ? ` → ${mount.destination}` : ""}`;
|
|
65
45
|
}
|
|
66
|
-
const mode = withMode
|
|
46
|
+
const mode = withMode
|
|
47
|
+
? ` ${t(mount.mode === "read_only"
|
|
48
|
+
? "mountReadOnlySuffix"
|
|
49
|
+
: "mountReadWriteSuffix")}`
|
|
50
|
+
: "";
|
|
67
51
|
return `${mount.project}${mount.destination !== "" ? ` → ${mount.destination}` : ""}${mode}`;
|
|
68
52
|
};
|
|
69
53
|
// Adding a mount defaults to read-only, so granting write access is always a
|
|
@@ -99,7 +83,7 @@ export function Chip(props) {
|
|
|
99
83
|
fontSize: "12px",
|
|
100
84
|
fontFamily: "var(--dsw-alias-font-mono, ui-monospace, monospace)",
|
|
101
85
|
color: "var(--dsw-alias-label-primary)",
|
|
102
|
-
}, children: [label, onRemove === undefined ? null : (_jsx(Button, { variant: "ghost", size: "sm", "aria-label": t("removeTag")
|
|
86
|
+
}, children: [label, onRemove === undefined ? null : (_jsx(Button, { variant: "ghost", size: "sm", "aria-label": `${t("removeTag")} ${label}`, disabled: disabled, onClick: onRemove, style: {
|
|
103
87
|
padding: 0,
|
|
104
88
|
minWidth: "18px",
|
|
105
89
|
height: "18px",
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
export declare const cardStyle: React.CSSProperties;
|
|
2
|
-
export declare const cardOpenStyle: React.CSSProperties;
|
|
3
|
-
export declare const cardHoverStyle: React.CSSProperties;
|
|
4
|
-
export declare const cardHeaderStyle: React.CSSProperties;
|
|
5
|
-
export declare const cardHeadTextStyle: React.CSSProperties;
|
|
6
|
-
export declare const cardNameStyle: React.CSSProperties;
|
|
7
|
-
export declare const cardDescriptionStyle: React.CSSProperties;
|
|
8
|
-
export declare const cardBodyStyle: React.CSSProperties;
|
|
9
1
|
export declare const sectionTitle: React.CSSProperties;
|
|
10
2
|
export declare const banner: React.CSSProperties;
|
|
11
3
|
export declare const greyId: React.CSSProperties;
|
|
12
4
|
export declare const hint: React.CSSProperties;
|
|
5
|
+
export declare const fieldLabel: React.CSSProperties;
|
|
13
6
|
export declare const wsBody: React.CSSProperties;
|
|
14
7
|
export declare const containerRow: React.CSSProperties;
|
|
15
8
|
export declare const containerHeader: React.CSSProperties;
|
|
@@ -19,3 +12,4 @@ export declare const tableStyle: React.CSSProperties;
|
|
|
19
12
|
export declare const thStyle: React.CSSProperties;
|
|
20
13
|
export declare const tdStyle: React.CSSProperties;
|
|
21
14
|
export declare const imageSelect: React.CSSProperties;
|
|
15
|
+
export declare const fieldSelect: React.CSSProperties;
|
|
@@ -1,58 +1,6 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: MIT
|
|
4
|
-
export const cardStyle = {
|
|
5
|
-
listStyle: "none",
|
|
6
|
-
border: "1px solid var(--dsw-alias-border-l2)",
|
|
7
|
-
borderRadius: "12px",
|
|
8
|
-
background: "var(--dsw-alias-bg-layer-3)",
|
|
9
|
-
transition: "border-color .16s, background .16s",
|
|
10
|
-
};
|
|
11
|
-
export const cardOpenStyle = {
|
|
12
|
-
background: "var(--dsw-alias-bg-layer-2)",
|
|
13
|
-
borderColor: "var(--dsw-alias-label-dimmed)",
|
|
14
|
-
};
|
|
15
|
-
export const cardHoverStyle = {
|
|
16
|
-
borderColor: "var(--dsw-alias-label-dimmed)",
|
|
17
|
-
};
|
|
18
|
-
export const cardHeaderStyle = {
|
|
19
|
-
width: "100%",
|
|
20
|
-
appearance: "none",
|
|
21
|
-
border: 0,
|
|
22
|
-
background: "none",
|
|
23
|
-
font: "inherit",
|
|
24
|
-
color: "inherit",
|
|
25
|
-
textAlign: "left",
|
|
26
|
-
cursor: "pointer",
|
|
27
|
-
display: "flex",
|
|
28
|
-
alignItems: "center",
|
|
29
|
-
gap: "12px",
|
|
30
|
-
padding: "14px 16px",
|
|
31
|
-
borderRadius: "12px",
|
|
32
|
-
};
|
|
33
|
-
export const cardHeadTextStyle = {
|
|
34
|
-
flex: 1,
|
|
35
|
-
minWidth: 0,
|
|
36
|
-
display: "flex",
|
|
37
|
-
flexDirection: "column",
|
|
38
|
-
gap: "4px",
|
|
39
|
-
};
|
|
40
|
-
export const cardNameStyle = {
|
|
41
|
-
fontSize: "15px",
|
|
42
|
-
fontWeight: 600,
|
|
43
|
-
lineHeight: 1.4,
|
|
44
|
-
color: "var(--dsw-alias-label-primary)",
|
|
45
|
-
};
|
|
46
|
-
export const cardDescriptionStyle = {
|
|
47
|
-
fontSize: "13px",
|
|
48
|
-
lineHeight: 1.5,
|
|
49
|
-
color: "var(--dsw-alias-label-tertiary)",
|
|
50
|
-
};
|
|
51
|
-
export const cardBodyStyle = {
|
|
52
|
-
borderTop: "1px solid var(--dsw-alias-border-l2)",
|
|
53
|
-
margin: "0 16px",
|
|
54
|
-
paddingBottom: "8px",
|
|
55
|
-
};
|
|
56
4
|
export const sectionTitle = {
|
|
57
5
|
fontWeight: 600,
|
|
58
6
|
margin: "16px 0 8px",
|
|
@@ -78,6 +26,14 @@ export const hint = {
|
|
|
78
26
|
color: "var(--dsw-alias-label-tertiary)",
|
|
79
27
|
margin: "8px 0",
|
|
80
28
|
};
|
|
29
|
+
export const fieldLabel = {
|
|
30
|
+
fontSize: "12px",
|
|
31
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
32
|
+
whiteSpace: "nowrap",
|
|
33
|
+
// Hugs the control when the label fills a grid cell; an auto-width flex item
|
|
34
|
+
// (the tab body's toolbar) is unaffected.
|
|
35
|
+
textAlign: "right",
|
|
36
|
+
};
|
|
81
37
|
export const wsBody = {
|
|
82
38
|
display: "flex",
|
|
83
39
|
flexDirection: "column",
|
|
@@ -141,3 +97,9 @@ export const imageSelect = {
|
|
|
141
97
|
fontSize: "12px",
|
|
142
98
|
maxWidth: "160px",
|
|
143
99
|
};
|
|
100
|
+
// A select that fills its label's row where fields are stacked; the narrow
|
|
101
|
+
// guide card uses it so the container and shell controls share one width.
|
|
102
|
+
export const fieldSelect = {
|
|
103
|
+
...imageSelect,
|
|
104
|
+
width: "100%",
|
|
105
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Translate } from "./locales.js";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
export declare function VolumesSection(props: {
|
|
4
|
-
t:
|
|
4
|
+
t: Translate;
|
|
5
5
|
volumes: readonly {
|
|
6
6
|
name: string;
|
|
7
7
|
}[];
|
|
@@ -2,9 +2,9 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
// SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
|
|
3
3
|
//
|
|
4
4
|
// SPDX-License-Identifier: MIT
|
|
5
|
-
import { ConfirmButton, Field, namePattern, sanitizeName } from "./container-card-shared.js";
|
|
5
|
+
import { ConfirmButton, Field, namePattern, sanitizeName, } from "./container-card-shared.js";
|
|
6
6
|
import { hint, sectionTitle, wsBody } from "./container-card-styles.js";
|
|
7
|
-
import { Button, DisclosureRow, Input, Modal } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
7
|
+
import { Button, DisclosureRow, Input, Modal, } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
8
8
|
import { useId, useState } from "react";
|
|
9
9
|
export function VolumesSection(props) {
|
|
10
10
|
const { t, volumes, busy, writable, onCreate, onRemove } = props;
|
|
@@ -25,13 +25,17 @@ export function VolumesSection(props) {
|
|
|
25
25
|
flexWrap: "wrap",
|
|
26
26
|
alignItems: "center",
|
|
27
27
|
gap: "8px",
|
|
28
|
-
}, children: [_jsx("div", { style: { ...sectionTitle, flex: 1 }, children: t("volumesTitle") }), _jsx(Button, { variant: "outline", size: "sm", disabled: !writable || busy, onClick: () => setOpen(true), children: t("createVolume") })] }), volumes.length === 0 ?
|
|
28
|
+
}, children: [_jsx("div", { style: { ...sectionTitle, flex: 1 }, children: t("volumesTitle") }), _jsx(Button, { variant: "outline", size: "sm", disabled: !writable || busy, onClick: () => setOpen(true), children: t("createVolume") })] }), volumes.length === 0 ? _jsx("p", { style: hint, children: t("none") }) : (volumes.map((volume) => (_jsx(DisclosureRow, { icon: _jsx("span", {}), title: volume.name, open: openVolume === volume.name, expandable: true, onToggle: () => setOpenVolume(openVolume === volume.name ? null : volume.name), children: _jsx("div", { style: wsBody, children: _jsx("div", { style: {
|
|
29
29
|
display: "flex",
|
|
30
30
|
flexWrap: "wrap",
|
|
31
31
|
alignItems: "center",
|
|
32
32
|
gap: "8px",
|
|
33
|
-
}, children: _jsx(ConfirmButton, { t: t, label: t("removeVolume"), title: t("confirmTitle"), description: t("confirmRemoveVolume"
|
|
33
|
+
}, children: _jsx(ConfirmButton, { t: t, label: t("removeVolume"), title: t("confirmTitle"), description: t("confirmRemoveVolume", {
|
|
34
|
+
volume: volume.name,
|
|
35
|
+
}), disabled: busy, onConfirm: () => onRemove(volume.name) }) }) }) }, volume.name)))), _jsx(Modal, { open: open, onClose: () => setOpen(false), title: t("volumesTitle"), closeLabel: t("cancel"), footer: _jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => setOpen(false), children: t("cancel") }), _jsx(Button, { variant: "primary", size: "sm", disabled: !canCreate, onClick: submit, children: t("createVolume") })] }), children: _jsxs(Field, { label: t("volumeName"), htmlFor: volumeId, children: [_jsx(Input, { id: volumeId, value: name, disabled: !writable || busy, autoFocus: true, onChange: (event) => setName(sanitizeName(event.target.value)), onKeyDown: (event) => {
|
|
34
36
|
if (event.key === "Enter")
|
|
35
37
|
submit();
|
|
36
|
-
} }), name !== "" && !namePattern.test(name)
|
|
38
|
+
} }), name !== "" && !namePattern.test(name)
|
|
39
|
+
? _jsx("p", { style: { ...hint, margin: 0 }, children: t("invalidName") })
|
|
40
|
+
: null] }) })] }));
|
|
37
41
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type ContainerCreateConfig, type ContainerView, type ImageView, type MountInput, type WorkspaceView } from "./container-card-controller.js";
|
|
2
2
|
import { type DirectoryPickerFace } from "./directory-picker.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { Translate } from "./locales.js";
|
|
4
4
|
import { type ReactNode } from "react";
|
|
5
5
|
export declare function WorkspaceSection(props: {
|
|
6
|
-
t:
|
|
6
|
+
t: Translate;
|
|
7
7
|
workspace: WorkspaceView;
|
|
8
8
|
containers: readonly ContainerView[];
|
|
9
9
|
images: readonly ImageView[];
|
|
@@ -17,15 +17,17 @@ export declare function WorkspaceSection(props: {
|
|
|
17
17
|
defaultImage: string;
|
|
18
18
|
projectsRoot: string;
|
|
19
19
|
directoryPicker?: DirectoryPickerFace;
|
|
20
|
-
onRemove: (workspace: string) => void;
|
|
20
|
+
onRemove: (workspace: string, container: string) => void;
|
|
21
21
|
onRemoveWorkspace: (workspace: string) => void;
|
|
22
|
-
onRecreate: (workspace: string, image: string, env?: Record<string, string>) => void;
|
|
22
|
+
onRecreate: (workspace: string, container: string, image: string, env?: Record<string, string>) => void;
|
|
23
23
|
onCreate: (workspace: WorkspaceView, config?: ContainerCreateConfig) => void;
|
|
24
24
|
onStartContainer: (workspace: WorkspaceView, container: string, config?: ContainerCreateConfig) => void;
|
|
25
25
|
onAddContainerMount: (workspace: string, container: string, mount: MountInput) => void;
|
|
26
26
|
onRemoveContainerMount: (workspace: string, container: string, mount: MountInput) => void;
|
|
27
27
|
onUpdateContainerMount: (workspace: string, container: string, mount: MountInput) => void;
|
|
28
28
|
onSetContainerPaths: (workspace: string, container: string, paths: readonly string[]) => void;
|
|
29
|
-
onAddContainerSecret: (workspace: string, envVar: string, secret: string) => void;
|
|
30
|
-
onRemoveContainerSecret: (workspace: string, envVar: string) => void;
|
|
29
|
+
onAddContainerSecret: (workspace: string, container: string, envVar: string, secret: string) => void;
|
|
30
|
+
onRemoveContainerSecret: (workspace: string, container: string, envVar: string) => void;
|
|
31
|
+
onSyncDefaults: (workspace: string) => void;
|
|
32
|
+
defaultEnvCount: number;
|
|
31
33
|
}): ReactNode;
|
|
@@ -5,14 +5,20 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
5
5
|
import { ContainerRow, CreateContainerModal } from "./container-card-row.js";
|
|
6
6
|
import { ConfirmButton, containerStateDot } from "./container-card-shared.js";
|
|
7
7
|
import { greyId, hint, wsBody } from "./container-card-styles.js";
|
|
8
|
-
import { Button, DisclosureRow, StateDot } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
8
|
+
import { Button, DisclosureRow, StateDot, } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
9
9
|
import { useState } from "react";
|
|
10
10
|
export function WorkspaceSection(props) {
|
|
11
|
-
const { t, workspace, containers, images, volumes, secrets, busy, defaultImage, projectsRoot, directoryPicker, onRemove, onRemoveWorkspace, onRecreate, onCreate, onStartContainer, onAddContainerMount, onRemoveContainerMount, onUpdateContainerMount, onSetContainerPaths, onAddContainerSecret, onRemoveContainerSecret, } = props;
|
|
11
|
+
const { t, workspace, containers, images, volumes, secrets, busy, defaultImage, projectsRoot, directoryPicker, onRemove, onRemoveWorkspace, onRecreate, onCreate, onStartContainer, onAddContainerMount, onRemoveContainerMount, onUpdateContainerMount, onSetContainerPaths, onAddContainerSecret, onRemoveContainerSecret, onSyncDefaults, defaultEnvCount, } = props;
|
|
12
12
|
const [open, setOpen] = useState(false);
|
|
13
13
|
const [createOpen, setCreateOpen] = useState(null);
|
|
14
14
|
const hasContainer = containers.length > 0;
|
|
15
|
-
return (_jsxs(DisclosureRow, { icon: hasContainer
|
|
15
|
+
return (_jsxs(DisclosureRow, { icon: hasContainer
|
|
16
|
+
? _jsx(StateDot, { state: containerStateDot(containers[0]?.status ?? "") })
|
|
17
|
+
: _jsx("span", {}), title: workspace.projectName, open: open, expandable: true, onToggle: () => setOpen(!open), children: [_jsxs("div", { style: wsBody, children: [_jsx("code", { style: greyId, children: workspace.workspaceSlug }), !hasContainer
|
|
18
|
+
? (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [_jsx("p", { style: { ...hint, margin: 0 }, children: t("noContainers") }), _jsx("div", { children: _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => setCreateOpen("default"), children: t("createContainer") }) })] }))
|
|
19
|
+
: (_jsxs(_Fragment, { children: [containers.map((container) => (_jsx(ContainerRow, { t: t, container: container, images: images, volumes: volumes, secrets: secrets, busy: busy, onRemove: onRemove, onRecreate: onRecreate, onAddContainerMount: onAddContainerMount, onRemoveContainerMount: onRemoveContainerMount, onUpdateContainerMount: onUpdateContainerMount, onSetContainerPaths: onSetContainerPaths, projectName: workspace.projectName, projectsRoot: projectsRoot, directoryPicker: directoryPicker, onAddContainerSecret: onAddContainerSecret, onRemoveContainerSecret: onRemoveContainerSecret }, container.containerName))), _jsx("div", { children: _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => setCreateOpen("named"), children: t("addContainer") }) })] })), _jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "8px" }, children: [_jsx(ConfirmButton, { t: t, label: t("applyDefaults"), title: t("confirmTitle"), description: t("confirmApplyDefaults"), disabled: busy || defaultEnvCount === 0, onConfirm: () => onSyncDefaults(workspace.workspaceSlug) }), _jsx(ConfirmButton, { t: t, label: t("removePod"), title: t("confirmTitle"), description: t("confirmRemovePod", {
|
|
20
|
+
workspace: workspace.projectName,
|
|
21
|
+
}), disabled: busy, onConfirm: () => onRemoveWorkspace(workspace.workspaceSlug) })] })] }), _jsx(CreateContainerModal, { t: t, workspace: workspace, images: images, volumes: volumes, secrets: secrets, busy: busy, defaultImage: defaultImage, projectsRoot: projectsRoot, directoryPicker: directoryPicker, named: createOpen === "named", existing: containers.map((container) => container.containerName), open: createOpen !== null, onClose: () => setCreateOpen(null), onCreate: (container, config) => {
|
|
16
22
|
if (createOpen === "named") {
|
|
17
23
|
onStartContainer(workspace, container, config);
|
|
18
24
|
}
|
|
@@ -17,8 +17,9 @@ export class DirectoryPickerError extends Error {
|
|
|
17
17
|
// then hides the browse affordance and the path stays a plain input).
|
|
18
18
|
export function buildDirectoryPicker(remote) {
|
|
19
19
|
const picker = remote?.directoryPicker;
|
|
20
|
-
if (picker === undefined || typeof picker.list !== "function")
|
|
20
|
+
if (picker === undefined || typeof picker.list !== "function") {
|
|
21
21
|
return undefined;
|
|
22
|
+
}
|
|
22
23
|
return {
|
|
23
24
|
async list(path, signal) {
|
|
24
25
|
const result = await picker.list(path, signal);
|