Skip to content
Merged
Binary file modified bun.lockb
Binary file not shown.
48 changes: 0 additions & 48 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,51 +41,3 @@
width: 450px;
margin-top: 5%;
}

.recipeBox {
width: 45%;
float: left;
}

.recipeJSON {
max-height: 300px;
width: 450px;
overflow-y: auto;
}

.configBox {
width: 45%;
float: right;
}

.configJSON {
max-height: 300px;
width: 450px;
overflow-y: auto;
}

textarea {
width: 450px;
height: 300px;
padding: 12px 20px;
box-sizing: border-box;
border: 2px solid #ccc;
border-radius: 4px;
font-size: 13px;
resize: none;
}

.logBox {
display: flex;
justify-content: space-between;
flex-direction: row;
text-align: start;
margin-top: 10px;
padding: 10px;
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
font-size: 14px;
align-items: flex-start;
border: 1px solid #ddd;
}
178 changes: 19 additions & 159 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import { v4 as uuidv4 } from 'uuid';
import "./App.css";
import { getResultPath, getLocationDict, getDocById, getFirebaseRecipe, getJobStatus, updateRecipe } from "./firebase";
import { getResultPath, getDocById, getFirebaseRecipe, getJobStatus, updateRecipe } from "./firebase";
import {
getSubmitPackingUrl,
JobStatus,
Expand All @@ -11,27 +11,18 @@ import {
FIRESTORE_FIELDS,
} from "./constants/firebaseConstants";
import { SIMULARIUM_EMBED_URL } from "./constants/urls";
import {
FirebaseDict,
} from "./types";
import { Link } from "react-router-dom";
import { PageRoutes } from "./constants/routes";
import PackingInput from "./components/PackingInput";
import Viewer from "./components/Viewer";
import ErrorLogs from "./components/ErrorLogs";

function App() {
const [recipes, setRecipes] = useState<FirebaseDict>({});
const [configs, setConfigs] = useState<FirebaseDict>({});
const [selectedRecipe, setSelectedRecipe] = useState("");
const [selectedConfig, setSelectedConfig] = useState("");
const [jobId, setJobId] = useState("");
const [jobStatus, setJobStatus] = useState("");
const [jobLogs, setJobLogs] = useState<string>("");
const [resultUrl, setResultUrl] = useState<string>("");
const [recipeStr, setRecipeStr] = useState<string>("");
const [configStr, setConfigStr] = useState<string>("");
const [viewRecipe, setViewRecipe] = useState<boolean>(true);
const [viewConfig, setViewConfig] = useState<boolean>(true);
const [viewResults, setViewResults] = useState<boolean>(false);
const [viewLogs, setViewLogs] = useState<boolean>(true);
const [runTime, setRunTime] = useState<number>(0);

let start = 0;
Expand All @@ -40,9 +31,9 @@ function App() {
return new Promise((resolve) => setTimeout(resolve, ms));
};

const recipeHasChanged = async (): Promise<boolean> => {
const originalRecipe = await getFirebaseRecipe(selectedRecipe);
return !(originalRecipe == recipeStr);
const recipeHasChanged = async (recipeId: string, recipeString: string): Promise<boolean> => {
const originalRecipe = await getFirebaseRecipe(recipeId);
return !(originalRecipe == recipeString);
}

const recipeToFirebase = (recipe: string, path: string, id: string): object => {
Expand All @@ -56,16 +47,16 @@ function App() {
return recipeJson;
}

const submitRecipe = async () => {
const submitRecipe = async (recipeId: string, configId: string, recipeString: string) => {
setResultUrl("");
setRunTime(0);
let firebaseRecipe = "firebase:recipes/" + selectedRecipe;
const firebaseConfig = "firebase:configs/" + selectedConfig;
const recipeChanged: boolean = await recipeHasChanged();
let firebaseRecipe = "firebase:recipes/" + recipeId;
const firebaseConfig = "firebase:configs/" + configId;
const recipeChanged: boolean = await recipeHasChanged(recipeId, recipeString);
if (recipeChanged) {
const recipeId = uuidv4();
firebaseRecipe = "firebase:recipes_edited/" + recipeId;
const recipeJson = recipeToFirebase(recipeStr, firebaseRecipe, recipeId);
const recipeJson = recipeToFirebase(recipeString, firebaseRecipe, recipeId);
try {
await updateRecipe(recipeId, recipeJson);
} catch(e) {
Expand All @@ -91,32 +82,9 @@ function App() {
}
};

const getRecipes = async () => {
const recipeDict = await getLocationDict(FIRESTORE_COLLECTIONS.RECIPES);
return recipeDict;
};

useEffect(() => {
const fetchRecipes = async () => {
const recipeDict = await getRecipes();
setRecipes(recipeDict);
};
fetchRecipes();
}, []);


const getConfigs = async () => {
const configDict = await getLocationDict(FIRESTORE_COLLECTIONS.CONFIGS);
return configDict;
};

useEffect(() => {
const fetchConfigs = async () => {
const configDict = await getConfigs();
setConfigs(configDict);
};
fetchConfigs();
}, []);
const startPacking = async (recipeId: string, configId: string, recipeString: string) => {
submitRecipe(recipeId, configId, recipeString).then((jobIdFromSubmit) => checkStatus(jobIdFromSubmit));
}

const checkStatus = async (jobIdFromSubmit: string) => {
const id = jobIdFromSubmit || jobId;
Expand Down Expand Up @@ -150,138 +118,30 @@ function App() {
setJobLogs(logStr);
};

const runPackingECS = async () => {
setViewConfig(false);
setViewRecipe(false);
submitRecipe().then((jobIdFromSubmit) => checkStatus(jobIdFromSubmit));
};

const selectRecipe = async (recipe: string) => {
setSelectedRecipe(recipe);
const recStr = await getFirebaseRecipe(recipe);
setRecipeStr(recStr);
}

const selectConfig = async (config: string) => {
setSelectedConfig(config);
const confStr = await getDocById(FIRESTORE_COLLECTIONS.CONFIGS, config);
setConfigStr(confStr);
}

const toggleRecipe = () => {
setViewRecipe(!viewRecipe);
}

const toggleConfig = () => {
setViewConfig(!viewConfig);
}

const toggleResults = () => {
if (resultUrl == "") {
fetchResultUrl();
}
setViewResults(!viewResults);
}

const toggleLogs = async () => {
if (jobLogs.length == 0) {
await getLogs();
} else {
setViewLogs(!viewLogs);
}
}

const jobSucceeded = jobStatus == JobStatus.DONE;
const showLogButton = jobStatus == JobStatus.FAILED;
const showResults = resultUrl && viewResults;

return (
<div className="app">
<h1>Welcome to cellPACK</h1>
<div className="input-container">
<select
value={selectedRecipe}
onChange={(e) => selectRecipe(e.target.value)}
>
<option value="" disabled>
Select a recipe
</option>
{Object.entries(recipes).map(([key, value]) => (
<option key={key} value={value["firebaseId"]}>
{key}
</option>
))}
</select>
<select
value={selectedConfig}
onChange={(e) => selectConfig(e.target.value)}
>
<option value="" disabled>
Select a config
</option>
{Object.entries(configs).map(([key, value]) => (
<option key={key} value={value["firebaseId"]}>
{key}
</option>
))}
</select>
<button onClick={runPackingECS} disabled={!selectedRecipe}>
Pack
</button>
</div>
<div className="box">
{recipeStr.length > 0 && (
<div className="recipeBox">
<button type="button" className="collapsible" onClick={toggleRecipe}>Recipe</button>
<div className="recipeJSON">
{viewRecipe && (
<textarea value={recipeStr} onChange={e => setRecipeStr(e.target.value)}/>
)}
</div>
</div>
)}
{configStr.length > 0 && (
<div className="configBox">
<button type="button" className="collapsible" onClick={toggleConfig}>Config</button>
<div className="configJSON">
{viewConfig && (
<pre>{configStr}</pre>
)}
</div>
</div>
)}
</div>
<PackingInput startPacking={startPacking} />
<h3>Job Status: {jobStatus}</h3>
{jobSucceeded && (
<div>
{runTime > 0 && (<h4>Time to Run: {runTime} sec</h4>)}
<button onClick={toggleResults}>Results</button>
</div>
)}
{
showResults && (
<div>
<iframe
src={resultUrl}
style={{
width: "1000px",
height: "600px",
border: "1px solid black",
}}
></iframe>
</div>
)
}
{showLogButton && (
<div>
<button className="collapsible" onClick={toggleLogs}>Logs</button>
{viewLogs && jobLogs.length > 0 && (
<div className="logBox">
<pre>{jobLogs}</pre>
</div>
)}
</div>
)}
{showResults && <Viewer resultUrl={resultUrl} />}
{showLogButton && <ErrorLogs errorLogs={jobLogs} getLogs={getLogs} />}
<div>
<Link
to={PageRoutes.LANDING_PAGE}
Expand Down
32 changes: 32 additions & 0 deletions src/components/ErrorLogs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useState } from "react";
import "./style.css";

interface ErrorLogsProps {
errorLogs: string;
getLogs: () => Promise<void>;
}

const ErrorLogs = (props: ErrorLogsProps): JSX.Element => {
const { errorLogs, getLogs } = props;
const [viewErrorLogs, setViewErrorLogs] = useState<boolean>(true);

const toggleLogs = async () => {
if (errorLogs.length === 0) {
await getLogs();
} else {
setViewErrorLogs(!viewErrorLogs);
}
}
return (
<div>
<button className="collapsible" onClick={toggleLogs}>Logs</button>
{viewErrorLogs && errorLogs.length > 0 && (
<div className="log-box">
<pre>{errorLogs}</pre>
</div>
)}
</div>
);
};

export default ErrorLogs;
14 changes: 14 additions & 0 deletions src/components/ErrorLogs/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.log-box {
display: flex;
justify-content: space-between;
flex-direction: row;
text-align: start;
margin-top: 10px;
padding: 10px;
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
font-size: 14px;
align-items: flex-start;
border: 1px solid #ddd;
}
Loading