Neon / portal template support (#713)
TODOs: - [x] Do restart when checkout / restore if there is a DB - [x] List all branches (branch id, name, date) - [x] Allow checking out versions with no DB - [x] safeguard to never delete main branches - [x] create app hook for neon template - [x] weird UX with connector on configure panel - [x] tiny neon logo in connector - [x] deploy to vercel - [x] build forgot password page - [x] what about email setup - [x] lots of imgix errors - [x] edit file - db snapshot - [x] DYAD_DISABLE_DB_PUSH - [ ] update portal doc - [x] switch preview branch to be read-only endpoint - [x] disable supabase sys prompt if neon is enabled - [ ] https://payloadcms.com/docs/upload/storage-adapters - [x] need to use main branch... Phase 2? - [x] generate DB migrations
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
} from "@/atoms/appAtoms";
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { AppOutput } from "@/ipc/ipc_types";
|
||||
import { showInputRequest } from "@/lib/toast";
|
||||
|
||||
const useRunAppLoadingAtom = atom(false);
|
||||
|
||||
@@ -18,7 +19,7 @@ export function useRunApp() {
|
||||
const [loading, setLoading] = useAtom(useRunAppLoadingAtom);
|
||||
const [app, setApp] = useAtom(currentAppAtom);
|
||||
const setAppOutput = useSetAtom(appOutputAtom);
|
||||
const [appUrlObj, setAppUrlObj] = useAtom(appUrlAtom);
|
||||
const [, setAppUrlObj] = useAtom(appUrlAtom);
|
||||
const setPreviewPanelKey = useSetAtom(previewPanelKeyAtom);
|
||||
const appId = useAtomValue(selectedAppIdAtom);
|
||||
const setPreviewErrorMessage = useSetAtom(previewErrorMessageAtom);
|
||||
@@ -39,47 +40,78 @@ export function useRunApp() {
|
||||
const originalUrl = originalUrlMatch && originalUrlMatch[1];
|
||||
setAppUrlObj({
|
||||
appUrl: proxyUrl,
|
||||
appId: appId!,
|
||||
appId: output.appId,
|
||||
originalUrl: originalUrl!,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const runApp = useCallback(async (appId: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const ipcClient = IpcClient.getInstance();
|
||||
console.debug("Running app", appId);
|
||||
|
||||
// Clear the URL and add restart message
|
||||
if (appUrlObj?.appId !== appId) {
|
||||
setAppUrlObj({ appUrl: null, appId: null, originalUrl: null });
|
||||
const processAppOutput = useCallback(
|
||||
(output: AppOutput) => {
|
||||
// Handle input requests specially
|
||||
if (output.type === "input-requested") {
|
||||
showInputRequest(output.message, async (response) => {
|
||||
try {
|
||||
const ipcClient = IpcClient.getInstance();
|
||||
await ipcClient.respondToAppInput({
|
||||
appId: output.appId,
|
||||
response,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to respond to app input:", error);
|
||||
}
|
||||
});
|
||||
return; // Don't add to regular output
|
||||
}
|
||||
setAppOutput((prev) => [
|
||||
...prev,
|
||||
{
|
||||
message: "Trying to restart app...",
|
||||
type: "stdout",
|
||||
appId,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]);
|
||||
const app = await ipcClient.getApp(appId);
|
||||
setApp(app);
|
||||
await ipcClient.runApp(appId, (output) => {
|
||||
setAppOutput((prev) => [...prev, output]);
|
||||
processProxyServerOutput(output);
|
||||
});
|
||||
setPreviewErrorMessage(undefined);
|
||||
} catch (error) {
|
||||
console.error(`Error running app ${appId}:`, error);
|
||||
setPreviewErrorMessage(
|
||||
error instanceof Error ? error.message : error?.toString(),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Add to regular app output
|
||||
setAppOutput((prev) => [...prev, output]);
|
||||
|
||||
// Process proxy server output
|
||||
processProxyServerOutput(output);
|
||||
},
|
||||
[setAppOutput],
|
||||
);
|
||||
const runApp = useCallback(
|
||||
async (appId: number) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const ipcClient = IpcClient.getInstance();
|
||||
console.debug("Running app", appId);
|
||||
|
||||
// Clear the URL and add restart message
|
||||
setAppUrlObj((prevAppUrlObj) => {
|
||||
if (prevAppUrlObj?.appId !== appId) {
|
||||
return { appUrl: null, appId: null, originalUrl: null };
|
||||
}
|
||||
return prevAppUrlObj; // No change needed
|
||||
});
|
||||
|
||||
setAppOutput((prev) => [
|
||||
...prev,
|
||||
{
|
||||
message: "Trying to restart app...",
|
||||
type: "stdout",
|
||||
appId,
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]);
|
||||
const app = await ipcClient.getApp(appId);
|
||||
setApp(app);
|
||||
await ipcClient.runApp(appId, processAppOutput);
|
||||
setPreviewErrorMessage(undefined);
|
||||
} catch (error) {
|
||||
console.error(`Error running app ${appId}:`, error);
|
||||
setPreviewErrorMessage(
|
||||
error instanceof Error ? error.message : error?.toString(),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[processAppOutput],
|
||||
);
|
||||
|
||||
const stopApp = useCallback(async (appId: number) => {
|
||||
if (appId === null) {
|
||||
@@ -139,15 +171,15 @@ export function useRunApp() {
|
||||
await ipcClient.restartApp(
|
||||
appId,
|
||||
(output) => {
|
||||
setAppOutput((prev) => [...prev, output]);
|
||||
// Handle HMR updates before processing
|
||||
if (
|
||||
output.message.includes("hmr update") &&
|
||||
output.message.includes("[vite]")
|
||||
) {
|
||||
onHotModuleReload();
|
||||
return;
|
||||
}
|
||||
processProxyServerOutput(output);
|
||||
// Process normally (including input requests)
|
||||
processAppOutput(output);
|
||||
},
|
||||
removeNodeModules,
|
||||
);
|
||||
@@ -161,7 +193,15 @@ export function useRunApp() {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
[appId, setApp, setAppOutput, setAppUrlObj, setPreviewPanelKey],
|
||||
[
|
||||
appId,
|
||||
setApp,
|
||||
setAppOutput,
|
||||
setAppUrlObj,
|
||||
setPreviewPanelKey,
|
||||
processAppOutput,
|
||||
onHotModuleReload,
|
||||
],
|
||||
);
|
||||
|
||||
const refreshAppIframe = useCallback(async () => {
|
||||
|
||||
Reference in New Issue
Block a user