diff --git a/frontend/electron/main/index.ts b/frontend/electron/main/index.ts index fe5cb72e..f3ff41c1 100644 --- a/frontend/electron/main/index.ts +++ b/frontend/electron/main/index.ts @@ -7,7 +7,7 @@ import { release } from 'node:os'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import "../../polyfill/crypto"; -import { startExpressServer } from "../../server/express.mjs"; +import { gracefullyStopAnvil, startExpressServer } from "../../server/express.mjs"; import { update } from './update'; import sourcemap from 'source-map-support'; @@ -44,6 +44,16 @@ if (targetIndex !== -1) { process.env.VITE_ZETAFORGE_IS_DEV = 'False' } +const isPip = '--is_pip' + +const targetPipIndex = process.argv.indexOf(isPip) + +if(targetPipIndex !== -1) { + process.env.VITE_IS_PIP = 'True' +} else { + process.env.VITE_IS_PIP = 'False' +} + // Disable GPU Acceleration for Windows 7 if (release().startsWith('6.1')) app.disableHardwareAcceleration() @@ -66,6 +76,7 @@ const preload = join(__dirname, '../preload/index.mjs') const url = process.env.VITE_DEV_SERVER_URL const indexHtml = join(process.env.DIST, 'index.html') + const isMac = process.platform === 'darwin' const menuTemplate: Electron.MenuItemConstructorOptions[] = [ ...(isMac? @@ -161,10 +172,16 @@ async function createWindow() { app.whenReady().then(createWindow) app.on('window-all-closed', () => { + console.log("WINDOW ALL CLOSED!!!!") win = null if (process.platform !== 'darwin') app.quit() }) +app.on('will-quit', () => { + console.log("QUITTING ANVIL...") + gracefullyStopAnvil() +}) + app.on('second-instance', () => { if (win) { // Focus on the main window if the user tried to open another @@ -177,8 +194,10 @@ app.on('activate', () => { const allWindows = BrowserWindow.getAllWindows() if (allWindows.length) { allWindows[0].focus() + allWindows[0].webContents.send('missing-config') } else { createWindow() + win?.webContents.send('missing-config') } }) diff --git a/frontend/server/express.mjs b/frontend/server/express.mjs index d2dca90c..e65d1418 100644 --- a/frontend/server/express.mjs +++ b/frontend/server/express.mjs @@ -1,5 +1,5 @@ import bodyParser from "body-parser"; -import { spawn } from "child_process"; +import { spawn, exec } from "child_process"; import compression from "compression"; import cors from "cors"; import "dotenv/config"; @@ -12,14 +12,30 @@ import path from "path"; import sha256 from "sha256"; import getMAC from "getmac"; import { BLOCK_SPECS_FILE_NAME } from "../src/utils/constants"; +import axios from "axios" + +let anvilProcess = null + + +function gracefullyStopAnvil() { + if(anvilProcess !== null) { + anvilProcess.kill("SIGINT") + const sleep = new Promise(((resolve) => setTimeout(resolve, 5000))) + sleep().then(res => { + console.log("schleepy shleep") + }) + } +} function startExpressServer() { const app = express(); const port = 3330; - - app.use(cors()); + + app.use(cors({ + origin: '*' + })) app.use(compression()); - + // http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header app.disable("x-powered-by"); //app.use(express.static(path.join(__dirname, '..', '..', 'backup_frontend'))); @@ -35,6 +51,7 @@ function startExpressServer() { app.use(express.static("public")); app.use(bodyParser.json()); + // OpenAI const configuration = new Configuration({ apiKey: process.env.OPENAI_API_KEY, @@ -165,6 +182,31 @@ function startExpressServer() { }); }); + app.get("/get-kube-contexts", async (req, res) => { + async function getKubectlContexts() { + return new Promise((resolve, reject) => { + exec('kubectl config get-contexts -o name', (error, stdout, stderr) => { + if (error) { + return reject(`Error executing kubectl command: ${error.message}`); + } + if (stderr) { + return reject(`Error in kubectl command output: ${stderr}`); + } + // Split the output into an array of contexts + const contexts = stdout.trim().split('\n'); + resolve(contexts); + }); + }); + } + try { + const contexts = await getKubectlContexts() + res.status(200).json(contexts) + } catch(err) { + console.log(err) + res.sendStatus(500) + } + }) + app.post("/api/call-agent", async (req, res) => { const { userMessage, agentName, conversationHistory, apiKey } = req.body; console.log("USER MESSAGE", userMessage); @@ -229,6 +271,499 @@ function startExpressServer() { res.status(500).send({ error: "Error reading directory" }); } }); + + app.get("/get-anvil-config", (req, res) => { + if(!electronApp.isPackaged) { + const response = {has_config: false} + res.status(200).send(response) + } + const anvilDir = path.join(process.resourcesPath, 'server2') + const anvilFiles = fs.readdirSync(anvilDir) + if(anvilFiles.includes('config.json')) { + const configFile = path.join(anvilDir, 'config.json') + const configStr = fs.readFileSync(configFile) + const config = JSON.parse(configStr) + const response = { + has_config: true, + config: config + } + res.status(200).send(response) + } else { + const response = {has_config: false} + res.status(200).send(response) + } + }) + + app.post("/launch-anvil-from-config", (req, res) => { + const anvilTimeoutPromise = new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error("Anvil Timeout Error")) + }, 3 * 60 * 1000) + }) + if(anvilProcess !== null) { + anvilProcess.kill("SIGINT") + anvilProcess = null + console.log("killed the process") + } + const anvilDir = path.join(process.resourcesPath, 'server2') + const configPath = path.join(anvilDir, 'config.json') + const configStr = fs.readFileSync(configPath) + const config = JSON.parse(configStr) + + const context = config.KubeContext + const kubeConfig = ['config', 'use-context', context] + const kubeExec = spawn('kubectl', kubeConfig) + + kubeExec.stderr.on('data', (data) => { + console.log(`stderr: ${data}`) + res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + }) + + const anvilFiles = fs.readdirSync(anvilDir) + const anvilExec = anvilFiles.filter((file) => file.startsWith('s2-'))[0] + const runAnvil = new Promise((resolve, reject) => { + anvilProcess = spawn(path.join(anvilDir, anvilExec), { + cwd: anvilDir, + detached: true, + stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, use pipes for stdout and stderr + }); + + anvilProcess.stdout.on('data', (data) => { + console.log(`[server] stdout: ${data}`); + + if(data.toString().includes('[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.')){ + console.log("ANVIL RUN SUCCESFULLY") + resolve() + } + }); + + anvilProcess.stderr.on('data', (data) => { + console.log(`[server] stderr: ${data}`); + if( data.toString().includes("Failed to fetch kubernetes resources;") || data.toString().includes("Failed to get client config;") || data.toString().includes("Failed to install argo;")) { + console.log("I AM REJECTING NOWWWWWW") + reject(new Error(`Kubeservices not found: ${data.toString()}`)) + } + }); + + anvilProcess.on('close', (code) => {}); + + }) + console.log("CHECK RES2") + console.log(res) + + const runAnvilPromise = Promise.race([anvilTimeoutPromise, runAnvil]) + + runAnvilPromise.then((response) => { + res.sendStatus(200) + }).catch(err => { + res.status(500).send({err: "Error while launching anvil" , kubeErr: err.message}) + }) + }) + + + app.post("/launch-anvil", (req, res) => { + + + const anvilTimeoutPromise = new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error("Anvil Timeout Error")) + }, 3 * 60 * 1000) + }) + + + if(!electronApp.isPackaged) { + res.sendStatus(200) + } + if(anvilProcess !== null) { + anvilProcess.kill("SIGINT") + anvilProcess = null + console.log("killed the process") + } + console.log("CAN I REACH HERE AFTER KILL???") + + const anvilDir = path.join(process.resourcesPath, 'server2') + const body = req.body + + const config = { + IsLocal: true, + IsDev: true? process.env.VITE_ZETAFORGE_IS_DEV === 'True': false , + ServerPort: parseInt(body.anvilPort), + KanikoImage: "gcr.io/kaniko-project/executor:latest", + WorkDir: "/app", + FileDir: "/files", + ComputationFile: "computations.py", + EntrypointFile: "entrypoint.py", + ServiceAccount: "executor", + Bucket: "forge-bucket", + Database: "./zetaforge.db", + KubeContext: body.KubeContext, + SetupVersion: "1", + Local: { + BucketPort: parseInt(body.s3Port), + Driver: body.driver + } + } + const configDir = path.join(anvilDir, 'config.json') + const configStr = JSON.stringify(config) + try{ + fs.writeFileSync(configDir, configStr) + console.log("FILE WRITTEN") + } catch(err) { + console.log("ERROR HAPPEND WHILE WRITING CONFIG.JS") + console.log(err) + res.status(500).send("Error happend while writing config.js") + } + const kubeConfig = ['config', 'use-context', body.KubeContext] + const kubeExec = spawn('kubectl', kubeConfig) + kubeExec.stderr.on('data', (data) => { + console.log(`stderr: ${data}`) + res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + }) + const anvilFiles = fs.readdirSync(anvilDir) + + const anvilExec = anvilFiles.filter((file) => file.startsWith('s2-'))[0] + const runAnvil = new Promise((resolve, reject) => { + anvilProcess = spawn(path.join(anvilDir, anvilExec), { + cwd: anvilDir, + detached: true, + stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, use pipes for stdout and stderr + }); + + anvilProcess.stdout.on('data', (data) => { + console.log(`[server] stdout: ${data}`); + + if(data.toString().includes('[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.')){ + console.log("ANVIL RUN SUCCESFULLY") + resolve() + } + }); + + anvilProcess.stderr.on('data', (data) => { + console.log(`[server] stderr: ${data}`); + if( data.toString().includes("Failed to fetch kubernetes resources;") || data.toString().includes("Failed to get client config;") || data.toString().includes("Failed to install argo;")) { + console.log("I AM REJECTING NOWWWWWW") + reject(new Error(`Kubeservices not found: ${data.toString()}`)) + } + }); + + anvilProcess.on('close', (code) => {}); + + }) + + + const runAnvilPromise = Promise.race([anvilTimeoutPromise, runAnvil]) + + runAnvilPromise.then((response) => { + res.sendStatus(200) + }).catch(err => { + res.status(500).send({err: "Error while launching anvil" , kubeErr: err.message}) + }) + }) + + + app.post("/initial-anvil-launch", (req, res) => { + console.log("INITIAL LAUNCH") + if(!electronApp.isPackaged) { + res.sendStatus(200) + } + const anvilDir = path.join(process.resourcesPath, 'server2') + try{ + const anvilFiles = fs.readdirSync(anvilDir) + if(!anvilFiles.includes('config.json')) { + console.log("CONFIG NOT FOUND") + res.status(500).send({error: "CONFIG NOT FOUND"}) + } else { + console.log("CONFIG FOUND") + const configFile = path.join(anvilDir, 'config.json') + const configBuffer = fs.readFileSync(configFile) + const config = JSON.parse(configBuffer) + if(config.IsLocal !== true){ + res.status(500).send({err: "Malformed config.json", kubeErr: "Local must be true"}) + } + if(config.Local.Driver === 'minikube') { + console.log("DRIVER IS MINIKUBE#######") + const kubeConfig = ['config', 'use-context', 'zetaforge'] + const kubeExec = spawn('kubectl', kubeConfig) + kubeExec.stderr.on('data', (data) => { + console.log(`stderr: ${data}`) + res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + }) + + const anvilExec = anvilFiles.filter((file) => file.startsWith('s2-'))[0] + const runAnvil = new Promise((resolve, reject) => { + anvilProcess = spawn(path.join(anvilDir, anvilExec), { + cwd: anvilDir, + detached: true, + stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, use pipes for stdout and stderr + }); + + anvilProcess.stdout.on('data', (data) => { + console.log(`[server] stdout: ${data}`); + + if(data.toString().includes('[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.')){ + console.log("ANVIL RUN SUCCESFULLY") + resolve() + } + }); + + anvilProcess.stderr.on('data', (data) => { + console.log(`[server] stderr: ${data}`); + if( data.toString().includes("Failed to fetch kubernetes resources;") || data.toString().includes("Failed to get client config;")) { + reject(new Error(`Kubeservices not found: ${data.toString()}`)) + } + }); + + anvilProcess.on('close', (code) => {}); + + }) + console.log("CHECK RES2") + console.log(res) + + const runAnvilPromise = Promise.race([anvilTimeoutPromise, runAnvil]) + + runAnvilPromise.then((response) => { + res.sendStatus(200) + }).catch(err => { + res.status(500).send({err: "Error while launching anvil" , kubeErr: err.message}) + }) + } else { + console.log("CHECK KUBECONFIG") + console.log(config.KubeContext) + const kubeConfig = ['config', 'use-context', config.KubeContext] + const kubeExec = spawn('kubectl', kubeConfig) + kubeExec.stderr.on('data', (data) => { + console.log(`stderr: ${data}`) + res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + }) + const anvilExec = anvilFiles.filter((file) => file.startsWith('s2-'))[0] + const runAnvil = new Promise((resolve, reject) => { + anvilProcess = spawn(path.join(anvilDir, anvilExec), { + cwd: anvilDir, + detached: true, + stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, use pipes for stdout and stderr + }); + + anvilProcess.stdout.on('data', (data) => { + console.log(`[server] stdout: ${data}`); + + if(data.toString().includes('[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.')){ + console.log("ANVIL RUN SUCCESFULLY") + resolve() + } + }); + + anvilProcess.stderr.on('data', (data) => { + console.log(`[server] stderr: ${data}`); + if(data.toString().includes("Failed to fetch kubernetes resources;")|| data.toString().includes("Failed to get client config;")) { + reject(new Error(`Kubeservices not found: ${data.toString()}`)) + } + }); + + anvilProcess.on('close', (code) => {}); + + }) + console.log("CHECK RES2") + console.log(res) + + const runAnvilPromise = Promise.race([anvilTimeoutPromise, runAnvil]) + + runAnvilPromise.then((response) => { + res.sendStatus(200) + }).catch(err => { + res.status(500).send({err: "Error while launching anvil" , kubeErr: err.message}) + }) + + } + + + } + } catch(err) { + res.sendStatus(500) + } + }) + + + app.post("/create-anvil-config", (req, res) => { + console.log("CREATING ANVIL CONFIG") + const body = req.body + const config = { + IsLocal: true, + IsDev: true? process.env.VITE_ZETAFORGE_IS_DEV === 'True': false , + ServerPort: parseInt(body.anvilPort), + KanikoImage: "gcr.io/kaniko-project/executor:latest", + WorkDir: "/app", + FileDir: "/files", + ComputationFile: "computations.py", + EntrypointFile: "entrypoint.py", + ServiceAccount: "executor", + Bucket: "forge-bucket", + Database: "./zetaforge.db", + KubeContext: body.KubeContext, + SetupVersion: "1", + Local: { + BucketPort: parseInt(body.s3Port), + Driver: body.KubeContext + } + } + const anvilDir = path.join(process.resourcesPath, 'server2') + const configDir = path.join(anvilDir, 'config.json') + const configStr = JSON.stringify(config) + try{ + fs.writeFileSync(configDir, configStr) + console.log("FILE WRITTEN") + } catch(err) { + console.log("ERROR HAPPEND WHILE WRITING CONFIG.JS") + console.log(err) + } + const kubectl = ['config', 'use-context', body.KubeContext] + const kubectlCmd = spawn('kubectl', kubectl) + kubectlCmd.on('error', (data) => { + console.log(data) + return res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + }) + + res.sendStatus(200) + + + + }) + + app.get("/isPackaged", (req, res) => { + console.log("INITIAL CHECK") + console.log(electronApp.isPackaged) + console.log("CHEEEEEEEEEEEEEEEEECCCKKK") + const isPip = process.env.VITE_IS_PIP === 'True'? true : false + return res.status(200).json(electronApp.isPackaged && !isPip) + }) + // app.post("/launch-anvil", async (req,res) => { + // if(!electronApp.isPackaged) { + // res.sendStatus(200) + // } + // const anvilDir = path.join(process.resourcesPath, 'server2') + // if(anvilProcess !== null) { + // anvilProcess.kill() + // } + // const body = req.body + + + // const anvilFiles = fs.readdirSync(anvilDir) + // if(!anvilFiles.includes('config.json')) { + // console.log("CHECK DEV") + // console.log(process.env.VITE_ZETAFORGE_IS_DEV) + // const config = { + // IsLocal: true, + // IsDev: true? process.env.VITE_ZETAFORGE_IS_DEV === 'True': false, + // ServerPort: parseInt(body.anvilPort), + // KanikoImage: "gcr.io/kaniko-project/executor:latest", + // WorkDir: "/app", + // FileDir: "/files", + // ComputationFile: "computations.py", + // EntrypointFile: "entrypoint.py", + // ServiceAccount: "executor", + // Bucket: "forge-bucket", + // Database: "./zetaforge.db", + // KubeContext: body.KubeContext, + // SetupVersion: "1", + // Local: { + // BucketPort: parseInt(body.s3Port), + // Driver: body.KubeContext + // } + // } + + // const configDir = path.join(anvilDir, 'config.json') + // const configStr = JSON.stringify(config) + // try{ + // fs.writeFileSync(configDir, configStr) + // console.log("FILE WRITTEN") + // } catch(err) { + // console.log("ERROR HAPPEND WHILE WRITING CONFIG.JS") + // res.status(500).status({err: "Config error happened", kubeErr: "Error creating config error"}) + + // console.log(err) + // } + + // } else { + // console.log("EXCEPTION HAPPEN HERE") + // //this else is added for minikube case. + // const configDir = path.join(anvilDir, 'config.json') + // const configFile = fs.readFileSync(configDir) + // const config = JSON.parse(configFile) + // config.KubeContext = body.KubeContext + // if(config.Local.Driver !== 'minikube') { + // config.Local.Driver = config.KubeContext + // } else { + // config.Local.Driver = 'minikube' + // } + + // const configStr = JSON.stringify(config) + // try { + // fs.writeFileSync(configDir, configStr) + // } catch(err) { + // res.status(500).status({err: "Config error happened", kubeErr: "Error creating config error"}) + // } + + // } + + // const configDir = path.join(anvilDir, 'config.json') + // const configBuffer = fs.readFileSync(configDir) + // const config = JSON.parse(configBuffer) + // if(config.Local.Driver === 'minikube') { + // console.log("DRIVER IS MINIKUBE111") + // const kubectl = ['config', 'use-context', 'zetaforge'] + // const kubectlCmd = spawn('kubectl', kubectl) + // kubectlCmd.on('error', (data) => { + // console.log(data) + // return res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + // }) + // } else { + // console.log("CHECK HERE") + // console.log(config.KubeContext) + // const KubeContext = config.KubeContext + // const kubectl = ['config', 'use-context', KubeContext] + // const kubectlCmd = spawn('kubectl', kubectl) + // kubectlCmd.on('error', (data) => { + // console.log(data) + // res.status(500).send({err: "CAN'T SET KUBECONTEXT", kubeErr: data.toString()}) + // }) + // } + // const anvilDirContent = fs.readdirSync(anvilDir) + // const anvilExec = anvilDirContent.filter((file) => file.startsWith('s2-'))[0] + // console.log("STARTING LAUNCH ANVIL...") + // const runAnvil = new Promise((resolve, reject) => { + // anvilProcess = spawn(path.join(anvilDir, anvilExec), { + // cwd: anvilDir, + // detached: true, + // stdio: ['ignore', 'pipe', 'pipe'], // Ignore stdin, use pipes for stdout and stderr + // }); + + // anvilProcess.stdout.on('data', (data) => { + // console.log(`[server] stdout: ${data}`); + + // if(data.toString().includes('[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.')){ + // console.log("ANVIL RUN SUCCESFULLY") + // resolve() + // } + // }); + + // anvilProcess.stderr.on('data', (data) => { + // console.log(`[server] stderr: ${data}`); + // if(data.toString().includes("Failed to fetch kubernetes resources;"|| data.toString().includes("Failed to get client config;"))){ + // reject(new Error(`Kubeservices not found: ${data.toString()}`)) + // } + // }); + + // anvilProcess.on('close', (code) => {}); + + // }) + // const runAnvilPromise = Promise.race([anvilTimeoutPromise, runAnvil]) + + // runAnvilPromise.then((response) => { + // res.sendStatus(200) + // }).catch(err => { + // res.status(500).send({err: "Error while launching anvil" , kubeErr: err.message}) + // }) + +// }) const getFileSystemContent = (dirPath) => { const fileSystem = {}; @@ -280,6 +815,13 @@ function startExpressServer() { return fileSystem; }; + + app.post("/launch-anvil-locally", (req, res) => { + console.log("RECEIVED REQUEST") + const config = req.body + + console.log(config) + }) app.post("/new-block-react", (req, res) => { const data = req.body; @@ -319,6 +861,23 @@ function startExpressServer() { app.listen(port, () => { console.log(`Server running at http://localhost:${port}`); }); + + process.on('SIGINT', () => { + console.log("SIGINT ANVIL") + if(anvilProcess !== null) { + console.log("KILLING ANVIL...") + anvilProcess.kill('SIGINT') + } + }) + + process.on('SIGTERM', () => { + console.log("SIGINT ANVIL") + if(anvilProcess !== null) { + console.log("KILLING ANVIL...") + anvilProcess.kill("SIGINT") + } + + }) } -export { startExpressServer }; +export { startExpressServer, gracefullyStopAnvil }; diff --git a/frontend/server/s3.js b/frontend/server/s3.js index c3d5e740..ad5d2e2b 100644 --- a/frontend/server/s3.js +++ b/frontend/server/s3.js @@ -57,6 +57,35 @@ async function copy(newKey, copyKey, anvilConfiguration) { } } +export async function checkAndCopy(newKey, copyKey, anvilConfiguration) { + const oldExists = await fileExists(copyKey, anvilConfiguration) + if (!oldExists) { + throw new Error("Previous file did not upload successfully, please upload a new file.") + } + const exists = await fileExists(newKey, anvilConfiguration); + if (!exists) { + await copy(newKey, copyKey, anvilConfiguration); + } +} + +async function copy(newKey, copyKey, anvilConfiguration) { + const client = getClient(anvilConfiguration); + const source = encodeURI(`/${config.s3.bucket}/${copyKey}`) + try { + const res = await client.send(new CopyObjectCommand({ + Bucket: config.s3.bucket, + CopySource: source, + Key: newKey, + })); + + return res; + } catch (err) { + const message = `Could not copy file in S3 from ${source} to ${newKey}`; + console.error(message, err, err?.stack); + throw new Error(message); + } +} + export async function checkAndUpload(key, filePath, anvilConfiguration) { const exists = await fileExists(key, anvilConfiguration); diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d16a814d..c7eb8080 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -9,8 +9,97 @@ import LibrarySwitcher from "@/components/ui/library/LibrarySwitcher"; import ModalWrapper from "@/components/ui/modal/ModalWrapper"; import ToastWrapper from "./components/ui/ToastWrapper"; import "./styles/globals.scss"; +import AnvilConfigurationsModal from "./components/ui/modal/AnvilConfigurationsModal"; +import ClosableModal from "./components/ui/modal/ClosableModal"; +import { useState, useEffect } from "react"; +import axios from 'axios' +import { useAtom } from "jotai"; +import { isPackaged} from "@/atoms/kubecontextAtom"; +import { availableKubeContexts } from "@/atoms/kubecontextAtom"; +import {Loading} from "@carbon/react" export default function App() { + + + const [appIsPackaged, setIsPackaged] = useAtom(isPackaged) + const [availableKubeContextsAtom, setAvailableKubeContexts] = useAtom(availableKubeContexts) + const [configOpen, setConfigOpen] = useState(false) + const [confirmationOpen, setConfirmationIsOpen] = useState(false) + const [confirmationText, setConfirmationText] = useState([]) + const [errModalOpen, setErrModalOpen] = useState(false) + const [errText, setErrText] = useState(false) + const [loading, setIsLoading] = useState(false) + + useEffect(() => { + const serverAddress = import.meta.env.VITE_EXPRESS + const res = axios.get(`${serverAddress}/isPackaged`).then((response) => { + console.log("CHECK HERE FOR RESPONSE - APP IS PACKAGED???") + console.log(response) + console.log(response.data) + setIsPackaged(response.data) + + + + if(availableKubeContextsAtom.length === 0) { + axios.get(`${serverAddress}/get-kube-contexts`).then((res) => { + setAvailableKubeContexts(res.data) + } + ) + } + + axios.get(`${serverAddress}/get-anvil-config`).then(res => { + console.log("CHECK RES") + console.log(res) + console.log(res.data) + + + const data = res.data + if(data.has_config) { + console.log("I SHOULD BE HERE ON THE RUN") + const config = data.config + const bucketPort = config.Local.BucketPort + const driver = config.Local.Driver + const serverPort = config.ServerPort + const context = config.KubeContext + if(config.IsLocal === true){ + setConfirmationIsOpen(true) + const configText = ["Are you sure you want to run anvil with the following configurations?", "If you are using minikube driver, please make sure you've setted up your minikube cluster, and that it's running.", `HOST: 127.0.0.1`, `PORT: ${serverPort}` , `Context: ${context}`, `Driver: ${driver}`] + setConfirmationText(configText) + } + } else { + console.log("NOT HERE") + setConfigOpen(true) + setConfirmationIsOpen(false) + } + }).catch(err => { + console.log("DEFINITELY NOT HERE") + setErrText(["Your local anvil did not started as expected. Please select a config", err.response?.data?.err, err.response?.data?.kubeErr]) + setConfigOpen(true) + }) + + }) + + + + + + + }, []) + + const confirmSettings = async () => { + setIsLoading(true) + const serverAddress = import.meta.env.VITE_EXPRESS + try{ + + const res = await axios.post(`${serverAddress}/launch-anvil-from-config`) + console.log(res) + console.log("CONFIRMATION") + setConfirmationIsOpen(false) + setIsLoading(false) + } catch(err) { + setErrText([err.message]) + } + } return ( @@ -19,6 +108,34 @@ export default function App() { + setConfigOpen(false)}/> + + + {/* Confirmation */} + setConfirmationIsOpen(false)} open={confirmationOpen}> +
+ {confirmationText.map((error, i) => { + console.log(confirmationText) + return ( +

{error}

+ ) + })} +
+ +
+ + {/* Error */} + {setConfirmationIsOpen(false); setConfigOpen(true) }} open={errModalOpen}> +
+ {confirmationText.map((error, i) => { + console.log(confirmationText) + return ( +

{error}

+ ) + })} +
+
+ diff --git a/frontend/src/atoms/kubecontextAtom.js b/frontend/src/atoms/kubecontextAtom.js new file mode 100644 index 00000000..ebe79165 --- /dev/null +++ b/frontend/src/atoms/kubecontextAtom.js @@ -0,0 +1,10 @@ +import {atom} from 'jotai' + +export const availableKubeContexts = atom([]) +export const choosenKubeContexts = atom('') +export const isPackaged = atom(false) +export const runningKubeContext = atom('') +export const kubeErrorModalIsOpen = atom(false) +export const kubeErrors = atom([]) +export const drivers = atom(['docker', 'minikube']) +export const choosenDriver = atom('') diff --git a/frontend/src/components/ui/RunPipelineButton.jsx b/frontend/src/components/ui/RunPipelineButton.jsx index 1f36cff8..fbd701b4 100644 --- a/frontend/src/components/ui/RunPipelineButton.jsx +++ b/frontend/src/components/ui/RunPipelineButton.jsx @@ -156,6 +156,7 @@ export default function RunPipelineButton({ children, action }) { margin: "5px", }; + return ( <>