Support dyad docker (#674)

TODOs:
- [ ] clean-up docker images

https://claude.ai/chat/13b2c5d3-0d46-49e3-a771-d10edf1e29f4
This commit is contained in:
Will Chen
2025-08-26 11:07:40 -07:00
committed by GitHub
parent e6c92a24ed
commit 9869fefbcb
6 changed files with 455 additions and 47 deletions

View File

@@ -0,0 +1,74 @@
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useSettings } from "@/hooks/useSettings";
import { showError } from "@/lib/toast";
import { IpcClient } from "@/ipc/ipc_client";
export function RuntimeModeSelector() {
const { settings, updateSettings } = useSettings();
if (!settings) {
return null;
}
const isDockerMode = settings?.runtimeMode2 === "docker";
const handleRuntimeModeChange = async (value: "host" | "docker") => {
try {
await updateSettings({ runtimeMode2: value });
} catch (error: any) {
showError(`Failed to update runtime mode: ${error.message}`);
}
};
return (
<div className="space-y-2">
<div className="space-y-1">
<div className="flex items-center space-x-2">
<Label className="text-sm font-medium" htmlFor="runtime-mode">
Runtime Mode
</Label>
<Select
value={settings.runtimeMode2 ?? "host"}
onValueChange={handleRuntimeModeChange}
>
<SelectTrigger className="w-48" id="runtime-mode">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="host">Local (default)</SelectItem>
<SelectItem value="docker">Docker (experimental)</SelectItem>
</SelectContent>
</Select>
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
Choose whether to run apps directly on the local machine or in Docker
containers
</div>
</div>
{isDockerMode && (
<div className="text-sm text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 p-2 rounded">
Docker mode is <b>experimental</b> and requires{" "}
<button
type="button"
className="underline font-medium cursor-pointer"
onClick={() =>
IpcClient.getInstance().openExternalUrl(
"https://www.docker.com/products/docker-desktop/",
)
}
>
Docker Desktop
</button>{" "}
to be installed and running
</div>
)}
</div>
);
}

View File

@@ -51,10 +51,11 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => {
const [isCollapsed, setIsCollapsed] = useState(true);
const { isStreaming } = useStreamChat();
if (!error) return null;
const isDockerError = error.includes("Cannot connect to the Docker");
const getTruncatedError = () => {
const firstLine = error.split("\n")[0];
const snippetLength = 200;
const snippetLength = 250;
const snippet = error.substring(0, snippetLength);
return firstLine.length < snippet.length
? firstLine
@@ -97,23 +98,27 @@ const ErrorBanner = ({ error, onDismiss, onAIFix }: ErrorBannerProps) => {
<Lightbulb size={16} className=" text-red-800 dark:text-red-300" />
</div>
<span className="text-sm text-red-700 dark:text-red-200">
<span className="font-medium">Tip: </span>Check if restarting the
app fixes the error.
<span className="font-medium">Tip: </span>
{isDockerError
? "Make sure Docker Desktop is running and try restarting the app."
: "Check if restarting the app fixes the error."}
</span>
</div>
</div>
{/* AI Fix button at the bottom */}
<div className="mt-2 flex justify-end">
<button
disabled={isStreaming}
onClick={onAIFix}
className="cursor-pointer flex items-center space-x-1 px-2 py-0.5 bg-red-500 dark:bg-red-600 text-white rounded text-sm hover:bg-red-600 dark:hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
<Sparkles size={14} />
<span>Fix error with AI</span>
</button>
</div>
{!isDockerError && (
<div className="mt-2 flex justify-end">
<button
disabled={isStreaming}
onClick={onAIFix}
className="cursor-pointer flex items-center space-x-1 px-2 py-0.5 bg-red-500 dark:bg-red-600 text-white rounded text-sm hover:bg-red-600 dark:hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed"
>
<Sparkles size={14} />
<span>Fix error with AI</span>
</button>
</div>
)}
</div>
);
};