Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 45 additions & 24 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,59 @@
text-align: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;

/* Temporary styling */
.logs-container {
margin-top: 10px;
padding: 10px;
/* background-color: #f9f9f9;
border: 1px solid #ddd; */
border-radius: 5px;
max-height: 300px;
overflow-y: auto;
/* font-family: monospace; */
font-size: 14px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);

.log-entry {
margin-bottom: 5px;
padding: 8px;
border-bottom: 1px solid #eee;
word-wrap: break-word;
/* Prevent long messages from breaking layout */
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);

.box {
display: flex;
justify-content: space-between;
flex-direction: row;
text-align: start;
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
.collapsible {
width: 450px;
margin-top: 5%;
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
.recipeBox {
width: 45%;
float: left;
}

.card {
padding: 2em;
.recipeJSON {
max-height: 300px;
overflow-y: auto;
}

.read-the-docs {
color: #888;
.configBox {
width: 45%;
float: right;
}

.configJSON {
max-height: 300px;
overflow-y: auto;
}
116 changes: 98 additions & 18 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from "react";
import "./App.css";
import { queryFirebase, getLocationDict } from "./firebase";
import { queryFirebase, getLocationDict, getDocById } from "./firebase";
import {
getSubmitPackingUrl,
packingStatusUrl,
Expand All @@ -14,12 +14,12 @@ import { SIMULARIUM_EMBED_URL } from "./constants/urls";
import {
AWSBatchJobsResponse,
CloudWatchLogsResponse,
StringDict,
FirebaseDict,
} from "./types";

function App() {
const [recipes, setRecipes] = useState<StringDict>({});
const [configs, setConfigs] = useState<StringDict>({});
const [recipes, setRecipes] = useState<FirebaseDict>({});
const [configs, setConfigs] = useState<FirebaseDict>({});
const [selectedRecipe, setSelectedRecipe] = useState("");
const [selectedConfig, setSelectedConfig] = useState("");
const [jobId, setJobId] = useState("");
Expand All @@ -29,6 +29,11 @@ function App() {
);
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 [viewLogs, setViewLogs] = useState<Boolean>(true);

const submitRecipe = async () => {
const url = getSubmitPackingUrl(selectedRecipe, selectedConfig);
Expand Down Expand Up @@ -110,8 +115,55 @@ function App() {

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

const selectRecipe = async (recipe: string) => {
setSelectedRecipe(recipe);
// Determine the firebaseId for this recipe
let firebaseId = "unknown"
for (let name in recipes) {
let path = recipes[name]["path"];
if (path == recipe) {
firebaseId = recipes[name]["firebaseId"]
}
}
const recStr = await getDocById(FIRESTORE_COLLECTIONS.EXAMPLE_RECIPES, firebaseId);
setRecipeStr(recStr);
}

const selectConfig = async (config: string) => {
setSelectedConfig(config);
// Determine the firebaseId for this config
let firebaseId = "unknown"
for (let name in configs) {
let path = configs[name]["path"];
if (path == config) {
firebaseId = configs[name]["firebaseId"]
}
}
const confStr = await getDocById(FIRESTORE_COLLECTIONS.CONFIGS, firebaseId);
console.log(confStr);
setConfigStr(confStr);
}

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

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

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

const jobSucceeded = jobStatus == JobStatus.SUCCEEDED;
const showLogButton = jobSucceeded || jobStatus == JobStatus.FAILED;

Expand All @@ -121,26 +173,26 @@ function App() {
<div className="input-container">
<select
value={selectedRecipe}
onChange={(e) => setSelectedRecipe(e.target.value)}
onChange={(e) => selectRecipe(e.target.value)}
>
<option value="" disabled>
Select a recipe
</option>
{Object.entries(recipes).map(([key, value]) => (
<option key={key} value={value}>
<option key={key} value={value["path"]}>
{key}
</option>
))}
</select>
<select
value={selectedConfig}
onChange={(e) => setSelectedConfig(e.target.value)}
onChange={(e) => selectConfig(e.target.value)}
>
<option value="" disabled>
Select a config
</option>
{Object.entries(configs).map(([key, value]) => (
<option key={key} value={value}>
<option key={key} value={value["path"]}>
{key}
</option>
))}
Expand All @@ -149,18 +201,34 @@ function App() {
Pack
</button>
</div>
<div>Job Status: {jobStatus}</div>
<div className="box">
{recipeStr.length > 0 && (
<div className="recipeBox">
<button type="button" className="collapsible" onClick={toggleRecipe}>Recipe</button>
<div className="recipeJSON">
{viewRecipe && (
<pre>{recipeStr}</pre>
)}
</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>
<h3>Job Status: {jobStatus}</h3>
{jobSucceeded && (
<div>
<button onClick={fetchResultUrl}>View result</button>
</div>
)}
{showLogButton && (
<div>
<button onClick={getLogs}>Logs</button>
{jobLogs}
</div>
)}
{
resultUrl && (
<div>
Expand All @@ -175,10 +243,22 @@ function App() {
</div>
)
}
{showLogButton && (
<div>
<button className="collapsible" onClick={toggleLogs}>Logs</button>
{viewLogs && jobLogs.length > 0 && (
<div className="logs-container">
{jobLogs.map((log, index) => (
<div key={index} className="log-entry">
<span>{log}</span>
</div>
))}
</div>
)}
</div>
)}
</div>
);
}

export default App;


export default App;
20 changes: 15 additions & 5 deletions src/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
FIRESTORE_COLLECTIONS,
FIRESTORE_FIELDS,
} from "./constants/firebaseConstants";
import { StringDict, FirestoreDoc } from "./types";
import { FirestoreDoc, FirebaseDict } from "./types";


const firebaseConfig = {
Expand Down Expand Up @@ -57,15 +57,25 @@ const getLocationDict = async (collectionName: string) => {
// docs is an array of objects, each with an id, a name, and other fields
// we want to create a dictionary with the name as the key and the original_location as the value
// `reduce` is a method that takes an array and reduces it to a single value
const locationDict = docs.reduce((locationDict: StringDict, doc: FirestoreDoc) => {
const locationDict = docs.reduce((locationDict: FirebaseDict, doc: FirestoreDoc) => {
const name = doc[FIRESTORE_FIELDS.NAME];
const originalLocation = doc[FIRESTORE_FIELDS.ORIGINAL_LOCATION];
const id = doc.id;
if (name && originalLocation) {
locationDict[name] = originalLocation;
locationDict[name] = {
"path": originalLocation,
"firebaseId": id,
};
}
return locationDict;
}, {} as StringDict);
}, {} as FirebaseDict);
return locationDict;
}

export { db, queryFirebase, getLocationDict };
const getDocById = async (coll: string, id: string) => {
const docs = await getAllDocsFromCollection(coll);
const doc = docs.find(d => d.id === id);
return JSON.stringify(doc, null, 2);
}

export { db, queryFirebase, getLocationDict, getDocById };
6 changes: 5 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ export interface CloudWatchLogsResponse {

export type StringDict = {
[key: string]: string;
};
};

export type FirebaseDict = {
[key: string]: StringDict;
};