Refresh UI when receiving deep link

This commit is contained in:
Will Chen
2025-04-22 21:56:43 -07:00
parent ae2cb0fc6b
commit 42b759d85c
7 changed files with 90 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
import { SidebarProvider } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/app-sidebar";
import { ThemeProvider } from "../contexts/ThemeContext";
import { DeepLinkProvider } from "../contexts/DeepLinkContext";
import { Toaster } from "sonner";
import { TitleBar } from "./TitleBar";
@@ -13,13 +14,15 @@ export default function RootLayout({
<>
<TitleBar />
<ThemeProvider>
<SidebarProvider>
<AppSidebar />
<div className="flex h-screenish w-full overflow-x-hidden mt-8 mb-4 mr-4 border-t border-l border-border rounded-lg bg-background">
{children}
</div>
<Toaster richColors />
</SidebarProvider>
<DeepLinkProvider>
<SidebarProvider>
<AppSidebar />
<div className="flex h-screenish w-full overflow-x-hidden mt-8 mb-4 mr-4 border-t border-l border-border rounded-lg bg-background">
{children}
</div>
<Toaster richColors />
</SidebarProvider>
</DeepLinkProvider>
</ThemeProvider>
</>
);

View File

@@ -23,12 +23,24 @@ import {
} from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { useLoadApp } from "@/hooks/useLoadApp";
import { useDeepLink } from "@/contexts/DeepLinkContext";
const OAUTH_CLIENT_ID = "bf747de7-60bb-48a2-9015-6494e0b04983";
export function SupabaseConnector({ appId }: { appId: number }) {
const [isConnecting, setIsConnecting] = useState(false);
const { settings } = useSettings();
const { settings, refreshSettings } = useSettings();
const { app, refreshApp } = useLoadApp(appId);
const { lastDeepLink } = useDeepLink();
useEffect(() => {
const handleDeepLink = async () => {
if (lastDeepLink?.type === "supabase-oauth-return") {
await refreshSettings();
await refreshApp();
}
};
handleDeepLink();
}, [lastDeepLink]);
const {
projects,
loading,
@@ -176,7 +188,7 @@ export function SupabaseConnector({ appId }: { appId: number }) {
return (
<div className="flex flex-col space-y-4 p-4 border rounded-md">
<h2 className="text-lg font-semibold">Connect to Supabase</h2>
<h2 className="text-lg font-semibold">Supabase Integration</h2>
<Button
onClick={handleConnect}

View File

@@ -0,0 +1,34 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import { IpcClient, DeepLinkData } from "../ipc/ipc_client";
type DeepLinkContextType = {
lastDeepLink: (DeepLinkData & { timestamp: number }) | null;
};
const DeepLinkContext = createContext<DeepLinkContextType>({
lastDeepLink: null,
});
export function DeepLinkProvider({ children }: { children: React.ReactNode }) {
const [lastDeepLink, setLastDeepLink] = useState<
(DeepLinkData & { timestamp: number }) | null
>(null);
useEffect(() => {
const ipcClient = IpcClient.getInstance();
const unsubscribe = ipcClient.onDeepLinkReceived((data) => {
// Update with timestamp to ensure state change even if same type comes twice
setLastDeepLink({ ...data, timestamp: Date.now() });
});
return unsubscribe;
}, []);
return (
<DeepLinkContext.Provider value={{ lastDeepLink }}>
{children}
</DeepLinkContext.Provider>
);
}
export const useDeepLink = () => useContext(DeepLinkContext);

View File

@@ -98,7 +98,7 @@ export function useSettings() {
);
},
refreshSettings: () => {
loadInitialData();
return loadInitialData();
},
};
}

View File

@@ -45,6 +45,11 @@ export interface GitHubDeviceFlowErrorData {
error: string;
}
export interface DeepLinkData {
type: string;
url?: string;
}
export class IpcClient {
private static instance: IpcClient;
private ipcRenderer: IpcRenderer;
@@ -731,4 +736,17 @@ export class IpcClient {
throw error;
}
}
// Listen for deep link events
public onDeepLinkReceived(
callback: (data: DeepLinkData) => void
): () => void {
const listener = (data: any) => {
callback(data as DeepLinkData);
};
this.ipcRenderer.on("deep-link-received", listener);
return () => {
this.ipcRenderer.removeListener("deep-link-received", listener);
};
}
}

View File

@@ -152,6 +152,13 @@ app.on("open-url", (event, url) => {
function handleDeepLinkReturn(url: string) {
// example url: "dyad://supabase-oauth-return?token=a&refreshToken=b"
const parsed = new URL(url);
// Intentionally do NOT log the full URL which may contain sensitive tokens.
log.log(
"Handling deep link: protocol",
parsed.protocol,
"hostname",
parsed.hostname
);
if (parsed.protocol !== "dyad:") {
dialog.showErrorBox(
"Invalid Protocol",
@@ -170,6 +177,11 @@ function handleDeepLinkReturn(url: string) {
return;
}
handleSupabaseOAuthReturn({ token, refreshToken, expiresIn });
// Send message to renderer to trigger re-render
mainWindow?.webContents.send("deep-link-received", {
type: parsed.hostname,
url,
});
}
}

View File

@@ -56,6 +56,7 @@ const validReceiveChannels = [
"github:flow-update",
"github:flow-success",
"github:flow-error",
"deep-link-received",
] as const;
type ValidInvokeChannel = (typeof validInvokeChannels)[number];