diff --git a/src/components/Dropdown/index.tsx b/src/components/Dropdown/index.tsx index 055fd959..da0a1885 100644 --- a/src/components/Dropdown/index.tsx +++ b/src/components/Dropdown/index.tsx @@ -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; + options: Dictionary; 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 ( diff --git a/src/components/GradientInput/index.tsx b/src/components/GradientInput/index.tsx index bfbd8fac..93a8e91a 100644 --- a/src/components/GradientInput/index.tsx +++ b/src/components/GradientInput/index.tsx @@ -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"; @@ -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, @@ -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 = {[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) => ({ diff --git a/src/components/InputSwitch/index.tsx b/src/components/InputSwitch/index.tsx index 07ceb9b1..c830cb54 100644 --- a/src/components/InputSwitch/index.tsx +++ b/src/components/InputSwitch/index.tsx @@ -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"; @@ -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 @@ -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; @@ -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) { diff --git a/src/components/JSONViewer/index.tsx b/src/components/JSONViewer/index.tsx index 2e83b403..65293b68 100644 --- a/src/components/JSONViewer/index.tsx +++ b/src/components/JSONViewer/index.tsx @@ -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 => { @@ -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' @@ -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), diff --git a/src/components/PackingInput/index.tsx b/src/components/PackingInput/index.tsx index 4bcce8ed..a68f4feb 100644 --- a/src/components/PackingInput/index.tsx +++ b/src/components/PackingInput/index.tsx @@ -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"; @@ -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 () => { @@ -54,15 +48,12 @@ const PackingInput = (props: PackingInputProps): JSX.Element => { await storeStartPacking(startPacking); }; - const handleRecipeStringChange = (newString: string) => { - if (selectedRecipeId) { - updateRecipeString(selectedRecipeId, newString); - } - }; + const loadingText = (
Loading...
) - if (isLoading) { - return
Loading...
; - } + // No recipe or dropdown options to load + if (!recipeObj && !inputOptions[selectedRecipeId]) { + return loadingText; + } return ( <> @@ -75,19 +66,19 @@ const PackingInput = (props: PackingInputProps): JSX.Element => { onChange={selectRecipe} /> - - - - - - - - + {/* Options menu loaded, but no recipe to load yet */} + {!recipeObj ? ( + loadingText + ) : ( + + + + + + + + + )} ); }; diff --git a/src/components/Viewer/index.tsx b/src/components/Viewer/index.tsx index 8a2dc79d..804376a4 100644 --- a/src/components/Viewer/index.tsx +++ b/src/components/Viewer/index.tsx @@ -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 (