From b3b69fd026c8bb40a5ec191702c2a8f7a3ee95d1 Mon Sep 17 00:00:00 2001 From: brecht-horn <119518056+brecht-horn@users.noreply.github.com> Date: Fri, 7 Jul 2023 18:26:09 -0700 Subject: [PATCH 1/9] Update README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 753ff5a..42e31ab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ ![Untitled (1000 × 300 px)](https://github.com/oslabs-beta/kaptn/assets/119518056/41f21e71-7ffc-4337-8c22-5364a17b87e0) -
+ +
+ ## Built With + ![JavaScript](https://img.shields.io/badge/-javascript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=white) ![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white) ![React](https://img.shields.io/badge/-react-61DAFB?style=for-the-badge&logo=react&logoColor=white) @@ -17,10 +20,15 @@ ![HTML](https://img.shields.io/badge/HTML5-E34F26?style=for-the-badge&logo=html5&logoColor=white) ![CSS](https://img.shields.io/badge/CSS3-1572B6?style=for-the-badge&logo=css3&logoColor=white) ![Jest](https://img.shields.io/badge/-jest-C21325?style=for-the-badge&logo=jest&logoColor=white) +
+ # kaptn + Kaptn is a fully downloadable desktop application that provides a user-friendly terminal interface for developers to interact with Kubernetes. With pre-selected kubectl options and the ability to free-type commands, Kaptn provides the training wheels you need to gain familiarity and proficiency in K8s. + ## Features + - User-friendly terminal interface - Take command of the command line interface with pre-selected kubectl options, or free-type - Clearly visualize the commands within our interactive terminal @@ -32,63 +40,97 @@ Kaptn is a fully downloadable desktop application that provides a user-friendly - Connect with Grafana and Prometheus to monitor cluster health - Troubleshoot any confusion with the Instant Help Desk - Follow tutorials and master K8s with our Learning Center + ## Getting Started + 1. Download the latest release [here](https://github.com/oslabs-beta/kaptn/releases). 2. Run the installer. -If you get a warning that the app is from an unidentified developer, go to System Preferences > Security & Privacy > General and click “Open Anyway”. + +If you get a warning that the app is from an unidentified developer, go to System Preferences > Security & Privacy > General and click "Open Anyway". + \*Please note, login functionality is currently disabled. Instead, please continue as guest to access all features of Kaptn. + ## Usage Guidelines + ### Overview + Our application defaults to our dashboard page, where you will be able to select a folder from your local system as the current working directory. From there, you can choose from the pre-suggested commands—including kubectl—to manage your kubernetes clusters or free-type in the command line interface. You can click on the ‘run’ button to run your command, or the ‘clear’ button to wipe the command line. + ![dashboardnew](https://github.com/oslabs-beta/kaptn/assets/119518056/fc791173-c81b-4e82-a68e-3a2731933c52) + ### Easy Setup + 1. Open up docker 2. Open up a terminal 3. Choose Image + - Before you begin to configure your docker and kubernetes, you will need a docker image. You may create your own docker image by defining that image in a dockerfile. For the purposes of this tutorial, however, select an existing image from an online registry, such as dockerhub - Navigate to (https://hub.docker.com) on your browser and create an account / sign in - Upon entering the dockerhub dashboard, use the search bar or the explore page to look up an image - - After selecting an image, click on ‘Tags’ to view all tag labels attached + - After selecting an image, click on 'Tags' to view all tag labels attached - In the terminal you opened up in step 2, run docker pull - Type out the full image name with the tag into the Image Input Field and press the Enter key - You may move onto step 4 once you see the image name render on the screen + ![chooseimage (1)](https://user-images.githubusercontent.com/63977843/236069404-e474bd34-4fa5-4503-84b7-bc4956335eda.gif) ![enterimg (1)](https://user-images.githubusercontent.com/63977843/236068711-3bacf6d2-a42a-49a3-9621-e0135e1a0357.gif) + 4. Choose Working Directory + - Select the working directory from which the virtual command line interface will be launched + ![cwd](https://user-images.githubusercontent.com/63977843/236047939-11ebcf22-5e44-422b-9f94-fafd4d22c6d9.gif) + 5. Create .YAML File + - Click on the CREATE .YAML FILE button, which will open up a page for you to set up your yaml file - Using the interactive .yaml generator, configure your file accordingly (e.g. deployment, deployment strategy, volume, DNS). You will be able to preview your code on the right side of the page as you make changes - Once complete, copy the yaml file by clicking the Copy to Clipboard button in the top right corner - Paste your code into the Name input field in the following format and press enter or click run: echo ‘YOUR CODE’ > FILENAME.yaml - Use your OS finder / files to locate the yaml file you created and confirm that it is configured as you expect + ![configyaml (2)](https://user-images.githubusercontent.com/63977843/236071323-57b395df-0128-40e4-b6e0-a060adcea78b.gif) ![touchyaml](https://user-images.githubusercontent.com/63977843/236071893-708850e9-d03c-47d0-a5a5-9a1f8efa55a0.gif) + 6. Congratulations! You have successfully setup your Kubernetes cluster! + ### Metrics + The metrics section is made up of various grafana dashboards to monitor different aspects of your Kubernetes clusters, including: + - Kubernetes API server: API server request rates/latencies, workqueue latencies, and etcd cache hit rate ![Screen Shot 2023-04-19 at 8 30 55 PM](https://user-images.githubusercontent.com/121407046/233463294-1ac4b9f4-12a6-467c-b4ff-5af227d7c6f6.png) + ## Contributing + ### How to contribute + Contributions are an incredibly important part of the open source community. Any contributions you make are greatly appreciated! + - Fork the project - Create your feature branch (git checkout -b feature/AmazingFeature) -- Commit your changes (git commit -m ‘Add some AmazingFeature’) +- Commit your changes (git commit -m 'Add some AmazingFeature') - Push to the branch (git push origin feature/AmazingFeature) - Open a pull request (from feature/AmazingFeature to dev) - Create a new issue on GitHub + ## Publications + Check out our Medium article [here](https://medium.com/@kaptnapp/introducing-kaptn-8c4348c6dcf6). + ## Contributors + - Brecht Horn [GitHub](https://github.com/brecht-horn) | [LinkedIn](https://www.linkedin.com/in/brecht-horn-a9b839213/) - John Choi [GitHub](https://github.com/jhwiwonc) | [LinkedIn](https://www.linkedin.com/in/hwi-won-choi-057081191/) - Natalie Cordoves [GitHub](https://github.com/ncordoves) | [LinkedIn](https://www.linkedin.com/in/natalie-cordoves) - Olivia Hodel [GitHub](https://github.com/ohodel) | [LinkedIn](https://www.linkedin.com/in/olivia-hodel/) - Yining Wang [GitHub](https://github.com/yiningcw) | [LinkedIn](https://www.linkedin.com/in/yining-wang-83b896108/) + ## License + Distributed under the MIT License. See LICENSE for more information. -Give this project a :star:️ if it helped you! -![Untitled (1000 × 300 px) (1)](https://user-images.githubusercontent.com/106838422/235518916-ddc0d40b-fe19-41c9-b43b-ac34894d52b1.png) \ No newline at end of file + +Give this project a ⭐️ if it helped you! + +![Untitled (1000 × 300 px) (1)](https://user-images.githubusercontent.com/106838422/235518916-ddc0d40b-fe19-41c9-b43b-ac34894d52b1.png) From a8ee75b1da10cf3f4d285fe6ad62153f3b5fc445 Mon Sep 17 00:00:00 2001 From: Brecht Horn Date: Mon, 21 Aug 2023 18:50:54 -0700 Subject: [PATCH 2/9] allows no working dir on kubectl commands --- main.js | 174 ++++++----- src/Pages/Dashboard.tsx | 629 ++++++++++++++++++++-------------------- src/Pages/Setup.tsx | 5 +- 3 files changed, 412 insertions(+), 396 deletions(-) diff --git a/main.js b/main.js index cf63234..7ff1c58 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,4 @@ -const path = require('path'); +const path = require("path"); const { app, BrowserWindow, @@ -6,18 +6,18 @@ const { Menu, MenuItem, globalShortcut, -} = require('electron'); -const { exec, spawnSync, spawn } = require('child_process'); -const { dialog } = require('electron'); -const { clipboard } = require('electron'); -const fixPath = require('fix-path'); +} = require("electron"); +const { exec, spawnSync, spawn } = require("child_process"); +const { dialog } = require("electron"); +const { clipboard } = require("electron"); +const fixPath = require("fix-path"); -const isDev = process.env.NODE_ENV === 'development'; +const isDev = process.env.NODE_ENV === "development"; function createMainWindow() { const mainWindow = new BrowserWindow({ - title: 'Kaptn', - titleBarStyle: 'hidden', + title: "Kaptn", + titleBarStyle: "hidden", trafficLightPosition: { x: 11.5, y: 8 }, width: 1100, height: 800, @@ -30,7 +30,7 @@ function createMainWindow() { }); if (isDev) { - mainWindow.loadURL('http://localhost:4444/'); + mainWindow.loadURL("http://localhost:4444/"); mainWindow.webContents.openDevTools(); } else { //in production, fix env.PATH for correct CLI use @@ -43,51 +43,75 @@ function createMainWindow() { /******** EVENT LISTENERS ********/ // Listen to post_command event -ipcMain.on('post_command', (event, arg) => { +ipcMain.on("post_command", (event, arg) => { const { command, currDir } = arg; - exec(` ${command}`, { cwd: currDir }, (err, stdout, stderr) => { - // Handle failed command execution - if (err) { - let output = err; - // dialog.showErrorBox('', `${err}`); - // return event.sender.send('post_command', output); - } - // Handle successful command execution but returned error (stderr) - if (stderr) { - // dialog.showErrorBox('Success execute, still error:', `${stderr}`); - return event.sender.send('post_command', stderr); + if (currDir === "NONE SELECTED") { + let kubDir = ""; + for (let i = 0; i < process.env.NVM_DIR.length - 4; i++) { + kubDir += process.env.NVM_DIR[i]; } - // Handle successful command execution with no errors - return event.sender.send('post_command', stdout); - }); + console.log("kubdir is", kubDir); + // currDir = process.env.path; + exec(` ${command}`, { cwd: kubDir }, (err, stdout, stderr) => { + // Handle failed command execution + if (err) { + let output = err; + // dialog.showErrorBox('', `${err}`); + // return event.sender.send('post_command', output); + } + // Handle successful command execution but returned error (stderr) + if (stderr) { + // dialog.showErrorBox('Success execute, still error:', `${stderr}`); + return event.sender.send("post_command", stderr); + } + // Handle successful command execution with no errors + return event.sender.send("post_command", stdout); + }); + } else { + exec(` ${command}`, { cwd: currDir }, (err, stdout, stderr) => { + // Handle failed command execution + if (err) { + let output = err; + // dialog.showErrorBox('', `${err}`); + // return event.sender.send('post_command', output); + } + // Handle successful command execution but returned error (stderr) + if (stderr) { + // dialog.showErrorBox('Success execute, still error:', `${stderr}`); + return event.sender.send("post_command", stderr); + } + // Handle successful command execution with no errors + return event.sender.send("post_command", stdout); + }); + } }); // Listen to prom_setup event -ipcMain.on('prom_setup', (event, arg) => { +ipcMain.on("prom_setup", (event, arg) => { // This command adds chart repository to helm spawnSync( - 'helm repo add prometheus-community https://prometheus-community.github.io/helm-charts', - { stdio: 'inherit', shell: true } + "helm repo add prometheus-community https://prometheus-community.github.io/helm-charts", + { stdio: "inherit", shell: true } ); // Update helm - spawnSync('helm repo update', { stdio: 'inherit', shell: true }); + spawnSync("helm repo update", { stdio: "inherit", shell: true }); // Install helm chart spawnSync( - 'helm install prometheus666 prometheus-community/kube-prometheus-stack', - { stdio: 'inherit', shell: true } + "helm install prometheus666 prometheus-community/kube-prometheus-stack", + { stdio: "inherit", shell: true } ); - return event.sender.send('prom_setup', 'Prom setup complete'); + return event.sender.send("prom_setup", "Prom setup complete"); }); // Listen to graf_setup event -ipcMain.on('graf_setup', (event, arg) => { +ipcMain.on("graf_setup", (event, arg) => { let returnValue; let podName; - const getFunc = exec('kubectl get pods', (err, stdout, stderr) => { + const getFunc = exec("kubectl get pods", (err, stdout, stderr) => { if (err) { returnValue = `exec error: ${err}`; } @@ -95,33 +119,33 @@ ipcMain.on('graf_setup', (event, arg) => { returnValue = `stderr: ${stderr}`; } - const output = stdout.split('\n'); + const output = stdout.split("\n"); output.forEach((pod) => { - if (pod.includes('prometheus666-grafana')) { - [podName] = pod.split(' '); + if (pod.includes("prometheus666-grafana")) { + [podName] = pod.split(" "); } }); }); - getFunc.once('close', () => { - spawnSync('kubectl apply -f prometheus666-grafana.yaml', { - studio: 'inherit', + getFunc.once("close", () => { + spawnSync("kubectl apply -f prometheus666-grafana.yaml", { + studio: "inherit", shell: true, }); spawnSync(`kubectl delete pod ${podName}`, { - stdio: 'inherit', + stdio: "inherit", shell: true, }); }); return event.sender.send( - 'graf_setup', + "graf_setup", `Grafana setup complete: ${returnValue}` ); }); // Listen to forward_ports event -ipcMain.on('forward_ports', (event, arg) => { - let returnData = ''; +ipcMain.on("forward_ports", (event, arg) => { + let returnData = ""; const ports = spawn( `kubectl port-forward deployment/prometheus666-grafana 3000`, { @@ -129,47 +153,43 @@ ipcMain.on('forward_ports', (event, arg) => { } ); - ports.stderr.on('data', (data) => { + ports.stderr.on("data", (data) => { returnData = `port forwarding error: ${data}`; - return event.sender.send('forward_ports', returnData); + return event.sender.send("forward_ports", returnData); }); - ports.stdout.on('data', (data) => { + ports.stdout.on("data", (data) => { returnData = `stdout: ${data}`; - return event.sender.send('forward_ports', returnData); + return event.sender.send("forward_ports", returnData); }); }); - // Listen to forward_ports event - ipcMain.on('kill_port', (event, arg) => { - const ports = spawn( - `kill -9 $(lsof -ti:3000)`, - { - shell: true, - } - ); - }) - +// Listen to forward_ports event +ipcMain.on("kill_port", (event, arg) => { + const ports = spawn(`kill -9 $(lsof -ti:3000)`, { + shell: true, + }); +}); -ipcMain.on('retrieve_key', (event, arg) => { - const cacheKey = 'api_key'; +ipcMain.on("retrieve_key", (event, arg) => { + const cacheKey = "api_key"; // Helper function to retrieve the API key and then UID const getAPIKey = async () => { try { // If the API key is not in the cache, fetch it from the API - const response = await fetch('http://localhost:3000/api/auth/keys', { - method: 'POST', - mode: 'no-cors', + const response = await fetch("http://localhost:3000/api/auth/keys", { + method: "POST", + mode: "no-cors", headers: { Authorization: - 'Basic ' + Buffer.from('admin:prom-operator').toString('base64'), - Accept: '*/*', - 'Content-Type': 'application/json', + "Basic " + Buffer.from("admin:prom-operator").toString("base64"), + Accept: "*/*", + "Content-Type": "application/json", }, body: JSON.stringify({ name: Math.random().toString(36).substring(7), - role: 'Admin', + role: "Admin", secondsToLive: 86400, }), }); @@ -179,7 +199,7 @@ ipcMain.on('retrieve_key', (event, arg) => { let key = data.key; const arg = { - dashboard: 'Kubernetes / API server', + dashboard: "Kubernetes / API server", }; const { dashboard } = arg; @@ -188,10 +208,10 @@ ipcMain.on('retrieve_key', (event, arg) => { let response2 = await fetch( `http://localhost:3000/api/search?query=${encodedDash}`, { - method: 'GET', + method: "GET", headers: { Authorization: `Bearer ${key}`, - 'Content-Type': 'application/json', + "Content-Type": "application/json", }, } ); @@ -203,27 +223,25 @@ ipcMain.on('retrieve_key', (event, arg) => { const now = new Date().getTime(); const from = new Date(now - 60 * 60 * 1000).getTime(); let url = `http://localhost:3000/d/${uid}/kubernetes-api-server?orgId=1&refresh=10s&from=${from}&to=${now}&kiosk=true?username=admin&password=prom-operator`; - require('electron').shell.openExternal(url); - return event.sender.send('retrieve_key', `true`); + require("electron").shell.openExternal(url); + return event.sender.send("retrieve_key", `true`); } catch (error) { - return event.sender.send('retrieve_key', `Error: ${error}`); + return event.sender.send("retrieve_key", `Error: ${error}`); } }; getAPIKey(); }); - -ipcMain.on('openbrowser', (event, arg) => { - event.returnValue = 'Message received!'; +ipcMain.on("openbrowser", (event, arg) => { + event.returnValue = "Message received!"; const now = new Date().getTime(); const from = new Date(now - 60 * 60 * 1000).getTime(); url = `http://localhost:3000/d/${uid}/kubernetes-api-server?orgId=1&refresh=10s&from=${from}&to=${now}&kiosk=true`; - require('electron').shell.openExternal(url); + require("electron").shell.openExternal(url); }); // Load the main window app.whenReady().then(() => { createMainWindow(); - }); diff --git a/src/Pages/Dashboard.tsx b/src/Pages/Dashboard.tsx index bb6f7ef..56311b0 100644 --- a/src/Pages/Dashboard.tsx +++ b/src/Pages/Dashboard.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect } from "react"; import { Button, InputLabel, @@ -13,63 +13,63 @@ import { useTheme, Modal, Typography, -} from '@mui/material'; -import Grid from '@mui/system/Unstable_Grid'; -import SideNav from '../components/Sidebar.jsx'; -import CommandLine from '../components/CommandLine.jsx'; -import Terminal from '../components/Terminal.jsx'; -const { ipcRenderer } = require('electron'); -import commands from '../components/commands.js'; -import { Box, lighten, darken } from '@mui/system'; -import BoltIcon from '@mui/icons-material/Bolt'; -import helpDesk from '../components/HelpDesk.jsx'; -import React from 'react'; -import Switch from '@mui/material/Switch'; -import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip'; -import { styled } from '@mui/material/styles'; +} from "@mui/material"; +import Grid from "@mui/system/Unstable_Grid"; +import SideNav from "../components/Sidebar.jsx"; +import CommandLine from "../components/CommandLine.jsx"; +import Terminal from "../components/Terminal.jsx"; +const { ipcRenderer } = require("electron"); +import commands from "../components/commands.js"; +import { Box, lighten, darken } from "@mui/system"; +import BoltIcon from "@mui/icons-material/Bolt"; +import helpDesk from "../components/HelpDesk.jsx"; +import React from "react"; +import Switch from "@mui/material/Switch"; +import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip"; +import { styled } from "@mui/material/styles"; const LightTooltip = styled(({ className, ...props }: TooltipProps) => ( ))(({ theme }) => ({ [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: theme.palette.mode === 'dark' ? '#5c4d9a' : '#8383de', - color: 'white', + backgroundColor: theme.palette.mode === "dark" ? "#5c4d9a" : "#8383de", + color: "white", fontSize: 11, }, })); //section header (e.g. beginner, intermediate, etc) rules for grouped "command" option -const BeginnerHeader = styled('div')(({ theme }) => ({ - position: 'sticky', - top: '-8px', - padding: '4px 10px', - margin: '0px', - color: '#ffffff', - backgroundColor: '#352a68', - webkitScrollbarColor: 'red yellow', +const BeginnerHeader = styled("div")(({ theme }) => ({ + position: "sticky", + top: "-8px", + padding: "4px 10px", + margin: "0px", + color: "#ffffff", + backgroundColor: "#352a68", + webkitScrollbarColor: "red yellow", })); //style for grouped commands -const GroupItems = styled('ul')({ +const GroupItems = styled("ul")({ padding: 0, - color: '#ffffff', - backgroundColor: '#5c4d9a', + color: "#ffffff", + backgroundColor: "#5c4d9a", }); function Dashboard(): JSX.Element { - const [verb, setVerb] = useState(''); - const [type, setType] = useState(''); - const [name, setName] = useState(''); - const [currDir, setCurrDir] = useState('NONE SELECTED'); - const [shortDir, setShortDir] = React.useState('NONE SELECTED'); - const [userInput, setUserInput] = useState(''); - const [command, setCommand] = useState(''); - const [tool, setTool] = useState('kubectl'); + const [verb, setVerb] = useState(""); + const [type, setType] = useState(""); + const [name, setName] = useState(""); + const [currDir, setCurrDir] = useState("NONE SELECTED"); + const [shortDir, setShortDir] = React.useState("NONE SELECTED"); + const [userInput, setUserInput] = useState(""); + const [command, setCommand] = useState(""); + const [tool, setTool] = useState("kubectl"); const [response, setResponse] = useState< Array<{ command: string; response: { [key: string]: string } }> >([]); const [flags, setFlags] = useState>([]); - const [helpList, setHelpList] = useState>(['']); + const [helpList, setHelpList] = useState>([""]); const [openCommand, setCommandOpen] = React.useState(false); const handleCommandOpen = () => setCommandOpen(true); @@ -86,18 +86,18 @@ function Dashboard(): JSX.Element { const theme = useTheme(); const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: '90%', - height: '90%', - bgcolor: theme.palette.mode === 'dark' ? '#2c1b63' : '#e9e5fa', - color: theme.palette.mode === 'dark' ? 'white' : '#47456e', + position: "absolute", + top: "50%", + left: "50%", + transform: "translate(-50%, -50%)", + width: "90%", + height: "90%", + bgcolor: theme.palette.mode === "dark" ? "#2c1b63" : "#e9e5fa", + color: theme.palette.mode === "dark" ? "white" : "#47456e", boxShadow: 24, p: 4, - padding: '10px', - borderRadius: '5px', + padding: "10px", + borderRadius: "5px", }; //maps grouped command options alphabetically including if numbered @@ -105,7 +105,7 @@ function Dashboard(): JSX.Element { const firstLetter = commands[0].category; return { firstLetter: /[{commands[0].category}]/.test(firstLetter) - ? '0-9' + ? "0-9" : firstLetter, ...option, }; @@ -118,7 +118,7 @@ function Dashboard(): JSX.Element { } = event; setFlags( // On autofill we get a stringified value. - typeof value === 'string' ? value.split(',') : value + typeof value === "string" ? value.split(",") : value ); }; @@ -132,40 +132,40 @@ function Dashboard(): JSX.Element { // Set current directory state const handleUploadDirectory = (event) => { - let path = event.target.files[0].path.split(''); - while (path[path.length - 1] !== '/') { + let path = event.target.files[0].path.split(""); + while (path[path.length - 1] !== "/") { path.pop(); } - let absPath = path.join(''); + let absPath = path.join(""); setCurrDir(absPath); - let absArr = absPath.split(''); + let absArr = absPath.split(""); let shortArr = []; - for (let i = absArr.length - 2; absArr[i] !== '/'; i--) { + for (let i = absArr.length - 2; absArr[i] !== "/"; i--) { shortArr.unshift(absArr[i]); } - shortArr.unshift('/'); - let shortPath = shortArr.join('') + '/'; - setShortDir('...' + shortPath); + shortArr.unshift("/"); + let shortPath = shortArr.join("") + "/"; + setShortDir("..." + shortPath); }; // Clear the input box const handleClear = (e) => { e.preventDefault(); - setVerb(''); - setUserInput(''); + setVerb(""); + setUserInput(""); }; // handle kubectl on off switch const handleK8ToolChange = (event) => { setChecked(event.target.checked); - if (!checked) setTool('kubectl'); - else setTool(''); + if (!checked) setTool("kubectl"); + else setTool(""); }; - let k8tool = ''; + let k8tool = ""; if (checked === true) { - k8tool = 'ON'; - } else k8tool = 'OFF'; + k8tool = "ON"; + } else k8tool = "OFF"; const toggleK8ToolHover = () => { let toolHoverStatus = !k8toolHover; @@ -173,40 +173,40 @@ function Dashboard(): JSX.Element { }; let k8toolStyle = { - display: 'flex', - justifyContent: 'flex-start', + display: "flex", + justifyContent: "flex-start", border: - theme.palette.mode === 'dark' - ? '.1px solid #ffffff50' - : '.1px solid #00000090', - borderRadius: '3px', - padding: '13px 0px 13px 8px', - width: '135px', + theme.palette.mode === "dark" + ? ".1px solid #ffffff50" + : ".1px solid #00000090", + borderRadius: "3px", + padding: "13px 0px 13px 8px", + width: "135px", }; - if (k8toolHover && theme.palette.mode === 'dark') { + if (k8toolHover && theme.palette.mode === "dark") { k8toolStyle = { - display: 'flex', - justifyContent: 'flex-start', - border: '1px solid #ffffff', - borderRadius: '3px', - padding: '13px 0px 13px 7.5px', - width: '135px', + display: "flex", + justifyContent: "flex-start", + border: "1px solid #ffffff", + borderRadius: "3px", + padding: "13px 0px 13px 7.5px", + width: "135px", }; - } else if (k8toolHover && theme.palette.mode === 'light') { + } else if (k8toolHover && theme.palette.mode === "light") { k8toolStyle = { - display: 'flex', - justifyContent: 'flex-start', - border: '1px solid #000000', - borderRadius: '3px', - padding: '13px 0px 13px 7.5px', - width: '135px', + display: "flex", + justifyContent: "flex-start", + border: "1px solid #000000", + borderRadius: "3px", + padding: "13px 0px 13px 7.5px", + width: "135px", }; } // Set the command state based on current inputs useEffect(() => { // Listen to post_command response - ipcRenderer.on('post_command', (event, arg) => { + ipcRenderer.on("post_command", (event, arg) => { const newResponseState = [ ...response, { command: command, response: arg }, @@ -214,146 +214,145 @@ function Dashboard(): JSX.Element { setResponse(newResponseState); }); - let newCommand = ''; - if (tool !== '') newCommand += tool; - if (verb !== '') newCommand += ' ' + verb; - if (type !== '') newCommand += ' ' + type; - if (name !== '') newCommand += ' ' + name; + let newCommand = ""; + if (tool !== "") newCommand += tool; + if (verb !== "") newCommand += " " + verb; + if (type !== "") newCommand += " " + type; + if (name !== "") newCommand += " " + name; if (flags.length) flags.forEach((flag) => { - newCommand += ' ' + flag; + newCommand += " " + flag; }); - if (userInput !== '') newCommand += ' ' + userInput; + if (userInput !== "") newCommand += " " + userInput; setCommand(newCommand); }); // Handle the command input submit event const handleSubmit = (e) => { e.preventDefault(); - if (currDir === 'NONE SELECTED') - return alert('Please choose working directory'); - - ipcRenderer.send('post_command', { command, currDir }); + if (tool === "" && currDir === "NONE SELECTED") { + return alert("Please choose working directory"); + } else ipcRenderer.send("post_command", { command, currDir }); }; // Command list options const commandList: { label: string }[] = [ - { label: 'get' }, - { label: 'apply' }, - { label: 'create' }, - { label: 'patch' }, - { label: 'logs' }, + { label: "get" }, + { label: "apply" }, + { label: "create" }, + { label: "patch" }, + { label: "logs" }, ]; // Type options const types: { label: string }[] = [ - { label: 'node' }, - { label: 'nodes' }, - { label: 'pod' }, - { label: 'pods' }, - { label: 'configmap' }, - { label: 'deployment' }, - { label: 'events' }, - { label: 'secret' }, - { label: 'service' }, - { label: 'services' }, + { label: "node" }, + { label: "nodes" }, + { label: "pod" }, + { label: "pods" }, + { label: "configmap" }, + { label: "deployment" }, + { label: "events" }, + { label: "secret" }, + { label: "service" }, + { label: "services" }, ]; // Flag list options - const flagList: string[] = ['-o wide', '--force', '-f', '-o default', '-v']; + const flagList: string[] = ["-o wide", "--force", "-f", "-o default", "-v"]; return ( <> {/* ----------------SIDE BAR---------------- */} {/* ----------------MAIN CONTENT---------------- */} {/* ----------------TERMINAL---------------- */} {/* ----------------BELOW TERMINAL---------------- */} {/* ----------------CHOOSE DIRECTORY---------------- */} - +

WORKING DIRECTORY:

- +

{shortDir}

- +