Support dyad add integration flow

This commit is contained in:
Will Chen
2025-04-22 17:04:12 -07:00
parent 4294ce5767
commit 2a08f72378
3 changed files with 93 additions and 3 deletions

View File

@@ -0,0 +1,73 @@
import React from "react";
import { useNavigate } from "@tanstack/react-router";
import { Button } from "@/components/ui/button";
import { selectedAppIdAtom } from "@/atoms/appAtoms";
import { useAtomValue, atom, useAtom } from "jotai";
import { showError } from "@/lib/toast";
import { useStreamChat } from "@/hooks/useStreamChat";
import { selectedChatIdAtom } from "@/atoms/chatAtoms";
interface DyadAddIntegrationProps {
node: {
properties: {
provider: string;
};
};
children: React.ReactNode;
}
const isSetupAtom = atom(false);
export const DyadAddIntegration: React.FC<DyadAddIntegrationProps> = ({
node,
children,
}) => {
const { streamMessage } = useStreamChat();
const [isSetup, setIsSetup] = useAtom(isSetupAtom);
const navigate = useNavigate();
const { provider } = node.properties;
const appId = useAtomValue(selectedAppIdAtom);
const selectedChatId = useAtomValue(selectedChatIdAtom);
const handleSetupClick = () => {
if (!appId) {
showError("No app ID found");
return;
}
navigate({ to: "/app-details", search: { appId } });
setIsSetup(true);
};
if (isSetup) {
return (
<Button
onClick={() => {
setIsSetup(false);
if (!selectedChatId) {
showError("No chat ID found");
return;
}
streamMessage({
prompt: "OK, I've setup Supabase. Continue",
chatId: selectedChatId,
});
}}
className="my-1"
>
Continue | I've setup {provider}
</Button>
);
}
return (
<div className="flex flex-col gap-2 my-2 p-3 border rounded-md bg-secondary/10">
<div className="text-sm">
<div className="font-medium">Integrate with {provider}?</div>
<div className="text-muted-foreground text-xs">{children}</div>
</div>
<Button onClick={handleSetupClick} className="self-start w-full">
Set up {provider}
</Button>
</div>
);
};

View File

@@ -6,6 +6,7 @@ import { DyadRename } from "./DyadRename";
import { DyadDelete } from "./DyadDelete"; import { DyadDelete } from "./DyadDelete";
import { DyadAddDependency } from "./DyadAddDependency"; import { DyadAddDependency } from "./DyadAddDependency";
import { DyadExecuteSql } from "./DyadExecuteSql"; import { DyadExecuteSql } from "./DyadExecuteSql";
import { DyadAddIntegration } from "./DyadAddIntegration";
import { CodeHighlight } from "./CodeHighlight"; import { CodeHighlight } from "./CodeHighlight";
import { useAtomValue } from "jotai"; import { useAtomValue } from "jotai";
import { isStreamingAtom } from "@/atoms/chatAtoms"; import { isStreamingAtom } from "@/atoms/chatAtoms";
@@ -75,6 +76,7 @@ function preprocessUnclosedTags(content: string): {
"dyad-delete", "dyad-delete",
"dyad-add-dependency", "dyad-add-dependency",
"dyad-execute-sql", "dyad-execute-sql",
"dyad-add-integration",
]; ];
let processedContent = content; let processedContent = content;
@@ -134,6 +136,7 @@ function parseCustomTags(content: string): ContentPiece[] {
"dyad-delete", "dyad-delete",
"dyad-add-dependency", "dyad-add-dependency",
"dyad-execute-sql", "dyad-execute-sql",
"dyad-add-integration",
]; ];
const tagPattern = new RegExp( const tagPattern = new RegExp(
@@ -287,6 +290,19 @@ function renderCustomTag(
</DyadExecuteSql> </DyadExecuteSql>
); );
case "dyad-add-integration":
return (
<DyadAddIntegration
node={{
properties: {
provider: attributes.provider || "",
},
}}
>
{content}
</DyadAddIntegration>
);
default: default:
return null; return null;
} }

View File

@@ -1,4 +1,4 @@
import { useNavigate, useSearch } from "@tanstack/react-router"; import { useNavigate, useRouter, useSearch } from "@tanstack/react-router";
import { useAtom, useAtomValue } from "jotai"; import { useAtom, useAtomValue } from "jotai";
import { appBasePathAtom, appsListAtom } from "@/atoms/appAtoms"; import { appBasePathAtom, appsListAtom } from "@/atoms/appAtoms";
import { IpcClient } from "@/ipc/ipc_client"; import { IpcClient } from "@/ipc/ipc_client";
@@ -32,6 +32,7 @@ import { SupabaseConnector } from "@/components/SupabaseConnector";
export default function AppDetailsPage() { export default function AppDetailsPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const router = useRouter();
const search = useSearch({ from: "/app-details" as const }); const search = useSearch({ from: "/app-details" as const });
const [appsList] = useAtom(appsListAtom); const [appsList] = useAtom(appsListAtom);
const { refreshApps } = useLoadApps(); const { refreshApps } = useLoadApps();
@@ -142,7 +143,7 @@ export default function AppDetailsPage() {
return ( return (
<div className="relative min-h-screen p-8"> <div className="relative min-h-screen p-8">
<Button <Button
onClick={() => navigate({ to: "/", search: {} })} onClick={() => router.history.back()}
variant="outline" variant="outline"
size="sm" size="sm"
className="absolute top-4 left-4 flex items-center gap-2 bg-(--background-lightest) py-5" className="absolute top-4 left-4 flex items-center gap-2 bg-(--background-lightest) py-5"
@@ -160,7 +161,7 @@ export default function AppDetailsPage() {
return ( return (
<div className="relative min-h-screen p-8 w-full"> <div className="relative min-h-screen p-8 w-full">
<Button <Button
onClick={() => navigate({ to: "/", search: {} })} onClick={() => router.history.back()}
variant="outline" variant="outline"
size="sm" size="sm"
className="absolute top-4 left-4 flex items-center gap-2 bg-(--background-lightest) py-5" className="absolute top-4 left-4 flex items-center gap-2 bg-(--background-lightest) py-5"