Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
8 changes: 4 additions & 4 deletions src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Select } from "antd";
import { map } from "lodash-es";
import { Dictionary, RecipeManifest } from "../../types";
import { Dictionary, RecipeMetadata } from "../../types";

interface DropdownProps {
placeholder: string;
defaultValue?: string;
options: Dictionary<RecipeManifest>;
options: Dictionary<RecipeMetadata>;
onChange: (value: string) => void;
}

const Dropdown = (props: DropdownProps): JSX.Element => {
const { placeholder, options, onChange, defaultValue } = props;
const selectOptions = map(options, (opt, key) => ({
label: opt.name || key,
value: opt.recipe,
label: opt.displayName || key,
value: opt.recipeId,
}));

return (
Expand Down
16 changes: 5 additions & 11 deletions src/components/GradientInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import { Select, Slider, InputNumber } from "antd";
import { GradientOption } from "../../types";
import {
useSelectedRecipeId,
useUpdateRecipeObj,
useGetCurrentValue,
useCurrentRecipeString,
useEditRecipe,
} from "../../state/store";
import { getSelectedGradient, deriveGradientStrength, round2, toStore } from "../../utils/gradient";
import "./style.css";
Expand All @@ -19,10 +18,8 @@ interface GradientInputProps {
const GradientInput = (props: GradientInputProps): JSX.Element => {
const { displayName, description, gradientOptions, defaultValue } = props;
const selectedRecipeId = useSelectedRecipeId();
const updateRecipeObj = useUpdateRecipeObj();
const editRecipe = useEditRecipe();
const getCurrentValue = useGetCurrentValue();
// Force re-render after restore/navigation
useCurrentRecipeString();

const { currentGradient, selectedOption } = getSelectedGradient(
gradientOptions,
Expand All @@ -36,20 +33,17 @@ const GradientInput = (props: GradientInputProps): JSX.Element => {
if (!selectedRecipeId) return;
const selectedOption = gradientOptions.find(option => option.value === value);
if (!selectedOption || !selectedOption.path) return;

// Make changes to JSON recipe
const changes: Record<string, string | number> = {[selectedOption.path]: value};
if (selectedOption.packing_mode && selectedOption.packing_mode_path) {
changes[selectedOption.packing_mode_path] = selectedOption.packing_mode;
editRecipe(selectedRecipeId, selectedOption.packing_mode_path, selectedOption.packing_mode);
}
updateRecipeObj(selectedRecipeId, changes);
editRecipe(selectedRecipeId, selectedOption.path, value);
};

const handleStrengthChange = (val: number | null) => {
if (val == null || !selectedRecipeId || !gradientStrengthData) return;
const uiVal = round2(val);
const storeVal = toStore(uiVal);
updateRecipeObj(selectedRecipeId, { [gradientStrengthData.path]: storeVal });
editRecipe(selectedRecipeId, gradientStrengthData.path, storeVal);
};

const selectOptions = gradientOptions.map((option) => ({
Expand Down
12 changes: 6 additions & 6 deletions src/components/InputSwitch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Input, InputNumber, Select, Slider } from "antd";
import { GradientOption } from "../../types";
import {
useSelectedRecipeId,
useUpdateRecipeObj,
useGetCurrentValue,
useCurrentRecipeString,
useEditRecipe,
useRecipes,
} from "../../state/store";
import GradientInput from "../GradientInput";
import "./style.css";
Expand All @@ -28,9 +28,9 @@ const InputSwitch = (props: InputSwitchProps): JSX.Element => {
const { displayName, inputType, dataType, description, min, max, options, id, gradientOptions, conversionFactor, unit } = props;

const selectedRecipeId = useSelectedRecipeId();
const updateRecipeObj = useUpdateRecipeObj();
const editRecipe = useEditRecipe();
const getCurrentValue = useGetCurrentValue();
const recipeVersion = useCurrentRecipeString();
const recipes = useRecipes();

// Conversion factor for numeric inputs where we want to display a
// different unit in the UI than is stored in the recipe
Expand Down Expand Up @@ -59,7 +59,7 @@ const InputSwitch = (props: InputSwitchProps): JSX.Element => {
// Reset local state when store value (or recipe) changes
useEffect(() => {
setValue(getCurrentValueMemo());
}, [getCurrentValueMemo, recipeVersion]);
}, [getCurrentValueMemo, recipes]);

const handleInputChange = (value: string | number | null) => {
if (value == null || !selectedRecipeId) return;
Expand All @@ -68,7 +68,7 @@ const InputSwitch = (props: InputSwitchProps): JSX.Element => {
// Convert back to original units for updating recipe object
value = value / conversion;
}
updateRecipeObj(selectedRecipeId, { [id]: value });
editRecipe(selectedRecipeId, id, value);
};

switch (inputType) {
Expand Down
9 changes: 3 additions & 6 deletions src/components/JSONViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import {
returnOneElement,
} from "./formattingUtils";
import "./style.css";
import { ViewableRecipe } from "../../types";

interface JSONViewerProps {
title: string;
content: string;
isEditable: boolean;
onChange: (value: string) => void;
content?: ViewableRecipe;
}

const JSONViewer = (props: JSONViewerProps): JSX.Element | null => {
Expand All @@ -22,8 +21,6 @@ const JSONViewer = (props: JSONViewerProps): JSX.Element | null => {
return null;
}

const contentAsObj = JSON.parse(content);

// descriptions for top level key-value pairs
const descriptions: DescriptionsItemProps[] = [];
// trees for nested objects like 'objects', 'composition', 'gradients'
Expand All @@ -44,7 +41,7 @@ const JSONViewer = (props: JSONViewerProps): JSX.Element | null => {
};

// top level objects, like name, bounding_box, etc.
Object.entries(contentAsObj).forEach(([key, value]) => {
Object.entries(content).forEach(([key, value]) => {
if (typeof value === "string") {
descriptions.push({
label: convertUnderscoreToSpace(key),
Expand Down
53 changes: 22 additions & 31 deletions src/components/PackingInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ import { Tabs } from "antd";

import {
useSelectedRecipeId,
useCurrentRecipeString,
useFieldsToDisplay,
useInputOptions,
useIsLoading,
useLoadInputOptions,
useSelectRecipe,
useUpdateRecipeString,
useStartPacking,
useLoadAllRecipes,
useCurrentRecipeObject,
useInputOptions,
useLoadInputOptions,
} from "../../state/store";
import Dropdown from "../Dropdown";
import JSONViewer from "../JSONViewer";
Expand All @@ -29,15 +26,12 @@ interface PackingInputProps {
const PackingInput = (props: PackingInputProps): JSX.Element => {
const { startPacking } = props;
const selectedRecipeId = useSelectedRecipeId();
const recipeString = useCurrentRecipeString();
const fieldsToDisplay = useFieldsToDisplay();
const recipeObj = useCurrentRecipeObject();
const inputOptions = useInputOptions();
const isLoading = useIsLoading();

const loadInputOptions = useLoadInputOptions();
const loadAllRecipes = useLoadAllRecipes();
const selectRecipe = useSelectRecipe();
const updateRecipeString = useUpdateRecipeString();
const storeStartPacking = useStartPacking();

const preFetchInputsAndRecipes = useCallback(async () => {
Expand All @@ -54,15 +48,12 @@ const PackingInput = (props: PackingInputProps): JSX.Element => {
await storeStartPacking(startPacking);
};

const handleRecipeStringChange = (newString: string) => {
if (selectedRecipeId) {
updateRecipeString(selectedRecipeId, newString);
}
};
const loadingText = (<div>Loading...</div>)

if (isLoading) {
return <div>Loading...</div>;
}
// No recipe or dropdown options to load
if (!recipeObj && !inputOptions[selectedRecipeId]) {
return loadingText;
}

return (
<>
Expand All @@ -75,19 +66,19 @@ const PackingInput = (props: PackingInputProps): JSX.Element => {
onChange={selectRecipe}
/>
</div>
<Tabs defaultActiveKey="1" className="recipe-content">
<Tabs.TabPane tab="Edit" key="1">
<RecipeForm onStartPacking={handleStartPacking} />
</Tabs.TabPane>
<Tabs.TabPane tab="Full Recipe" key="2">
<JSONViewer
title="Recipe"
content={recipeString}
isEditable={fieldsToDisplay === undefined}
onChange={handleRecipeStringChange}
/>
</Tabs.TabPane>
</Tabs>
{/* Options menu loaded, but no recipe to load yet */}
{!recipeObj ? (
loadingText
) : (
<Tabs defaultActiveKey="1" className="recipe-content">
<Tabs.TabPane tab="Edit" key="1">
<RecipeForm onStartPacking={handleStartPacking} />
</Tabs.TabPane>
<Tabs.TabPane tab="Full Recipe" key="2">
<JSONViewer title="Recipe" content={recipeObj} />
</Tabs.TabPane>
</Tabs>
)}
</>
);
};
Expand Down
28 changes: 27 additions & 1 deletion src/components/Viewer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,41 @@
import { LoadingOutlined } from "@ant-design/icons";
import { SIMULARIUM_EMBED_URL } from "../../constants/urls";
import { useResultUrl } from "../../state/store";
import { useCurrentRecipeObject, useIsModified, useIsPacking, useResultUrl } from "../../state/store";
import "./style.css";

const Viewer = (): JSX.Element => {
const resultUrl = useResultUrl();
const recipeObject = useCurrentRecipeObject();
const isLoading = !recipeObject;
const isPacking = useIsPacking();
const isModified = useIsModified();

let overlayText = "";
if (isLoading) {
overlayText = "Loading...";
} else if (isPacking) {
overlayText = "Running...";
} else if (isModified) {
overlayText = "Re-run packing to view result";
}

const showOverlay = isLoading || isPacking || isModified;
const showSpinner = isLoading || isPacking;

return (
<div className="viewer-container">
<iframe
className="simularium-embed"
src={`${SIMULARIUM_EMBED_URL}${resultUrl}`}
/>
{showOverlay && (
<div className="viewer-overlay">
<div className="overlay-content">
{showSpinner && <LoadingOutlined />}
<p>{overlayText}</p>
</div>
</div>
)}
</div>
);
};
Expand Down
28 changes: 28 additions & 0 deletions src/components/Viewer/style.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
.viewer-container {
width: 100%;
height: 100%;
position: relative;
}

.simularium-embed {
width: 100%;
height: 100%;
border: 1px solid black;
}

.viewer-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #DCDDE5;
color: #468ADE;
display: flex;
align-items: center;
justify-content: center;
}

.overlay-content {
color: #468ADE;
font-size: 32px;
text-align: center;
}

.dark-theme .viewer-overlay {
background-color: #2C2F38;
}

.dark-theme .overlay-content {
color: #8b91ff;
}
Loading