Refresh UI when receiving deep link
This commit is contained in:
@@ -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,6 +14,7 @@ export default function RootLayout({
|
||||
<>
|
||||
<TitleBar />
|
||||
<ThemeProvider>
|
||||
<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">
|
||||
@@ -20,6 +22,7 @@ export default function RootLayout({
|
||||
</div>
|
||||
<Toaster richColors />
|
||||
</SidebarProvider>
|
||||
</DeepLinkProvider>
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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}
|
||||
|
||||
34
src/contexts/DeepLinkContext.tsx
Normal file
34
src/contexts/DeepLinkContext.tsx
Normal 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);
|
||||
@@ -98,7 +98,7 @@ export function useSettings() {
|
||||
);
|
||||
},
|
||||
refreshSettings: () => {
|
||||
loadInitialData();
|
||||
return loadInitialData();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
12
src/main.ts
12
src/main.ts
@@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user