Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ file is the human-readable summary of what changed and why.

### Desktop / Web UI

- **Switching to Work with no sandbox explains itself** — clicking **Work**
before you have a sandbox opens the Add sandbox dialog, which was a dialog
you did not ask for with nothing to say about why it appeared. It now leads
with the reason: Work requires a sandbox environment to run sessions.
Reaching the same dialog deliberately, from Settings, is unchanged.
- **The CPU and memory fields explain themselves** — the Add sandbox dialog
offered two unlabelled optional boxes with no hint of what a sandbox gets if
you leave them empty, and the memory box ran past the edge of the dialog.
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ export const dict = {
"workspace.empty.none": "No sandbox yet. Create one to work in an isolated environment.",
"workspace.empty.starting": "Your sandbox is not running yet. It appears here once it is ready.",
"workspace.empty.stopped": "Your sandbox is stopped. Start it again from Settings → Servers.",
"sandbox.add.workIntro": "Work requires a sandbox environment to run sessions.",
"sandbox.server.add": "Add sandbox",
"sandbox.server.label": "Sandbox",
"sandbox.server.menu.label": "Sandbox",
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ export const dict = {
"workspace.empty.none": "Aún no hay ningún sandbox. Crea uno para trabajar en un entorno aislado.",
"workspace.empty.starting": "Tu sandbox todavía no está en marcha. Aparecerá aquí cuando esté listo.",
"workspace.empty.stopped": "Tu sandbox está detenido. Vuelve a iniciarlo desde Ajustes → Servidores.",
"sandbox.add.workIntro": "Trabajo requiere un entorno de sandbox para ejecutar sesiones.",
"sandbox.server.add": "Añadir sandbox",
"sandbox.server.label": "Sandbox",
"sandbox.server.menu.label": "Sandbox",
Expand Down
31 changes: 28 additions & 3 deletions packages/app/src/sandbox/dialog-add.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { showToast } from "@opencode-ai/ui/toast"
import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2"
import { Dialog, DialogBody, DialogFooter, DialogHeader, DialogTitle } from "@opencode-ai/ui/v2/dialog-v2"
import {
Dialog,
DialogBody,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTitleGroup,
} from "@opencode-ai/ui/v2/dialog-v2"
import { DividerV2 } from "@opencode-ai/ui/v2/divider-v2"
import { LoaderV2 } from "@opencode-ai/ui/v2/loader-v2"
import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2"
Expand All @@ -25,7 +32,13 @@ import {
// need to react to a creation must use it rather than watching the sandbox
// list: that list arrives over a separate IPC event, so it is still empty for
// a beat after add() resolves.
export function DialogAddSandbox(props: { onCreated?: (config: SandboxConfig) => void }) {
export function DialogAddSandbox(props: {
onCreated?: (config: SandboxConfig) => void
// Set when the dialog opened because Work needs a sandbox and there is none,
// rather than because the user asked to add one. That dialog arrives
// unbidden, so it has to say why it is there.
requiredForWork?: boolean
}) {
const language = useLanguage()
const platform = usePlatform()
const dialog = useDialog()
Expand Down Expand Up @@ -193,7 +206,19 @@ export function DialogAddSandbox(props: { onCreated?: (config: SandboxConfig) =>
return (
<Dialog fit>
<DialogHeader hideClose={true}>
<DialogTitle>{language.t("sandbox.server.add")}</DialogTitle>
{/* As a description under the title rather than a line in the body:
it explains the whole dialog, not the field it happens to sit
above, and DialogTitleGroup ties it to the dialog for screen
readers. */}
<Show
when={props.requiredForWork}
fallback={<DialogTitle>{language.t("sandbox.server.add")}</DialogTitle>}
>
<DialogTitleGroup
title={language.t("sandbox.server.add")}
description={language.t("sandbox.add.workIntro")}
/>
</Show>
</DialogHeader>
<DividerV2 />
<DialogBody class="flex flex-col gap-3 px-4 pt-3 pb-1">
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/workspace/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function useWorkspaceSwitch() {
// list arrives on a separate IPC event and is still empty for a beat
// after the create resolves, so checking it here left the user on
// Code until they toggled the tabs by hand.
void dialog.show(() => <module.DialogAddSandbox onCreated={() => enter("work")} />)
void dialog.show(() => <module.DialogAddSandbox requiredForWork onCreated={() => enter("work")} />)
})
return
}
Expand Down
Loading