Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add edit environment info features #20

Merged
merged 1 commit into from
Sep 16, 2023
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
49 changes: 45 additions & 4 deletions frontend/src/components/environment_card.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,54 @@
import { Environment } from "@/types/environment";
import { Environment, VectorSpec } from "@/types/environment";
import VariableSpec from "@/components/variable_spec";
import { useState, useEffect } from "react";

export default function EnvironmentCard({ env }: { env: Environment }) {
const [envSpecs, setEnvSpecs] = useState<Environment>(env);
const [obsSpecs, setObsSpecs] = useState<VectorSpec[]>(
env.observation_spec ?? []
);
const [actSpecs, setActSpecs] = useState<VectorSpec[]>(env.action_spec ?? []);
useEffect(() => {
setEnvSpecs((prevState) => {
const newState = { ...prevState };
newState.observation_spec = obsSpecs;
newState.action_spec = actSpecs;
return newState;
});
}, [obsSpecs, actSpecs]);
const onSave = () => {
fetch(`/api/env/${env.id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(envSpecs),
})
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
console.log("Environment saved successfully!");
})
.catch((error) => {
console.error("There was a problem saving the environment:", error);
});
};

return (
<div className="card m-5">
<div className="card-body">
<h2 className="card-title">{env.name}</h2>
<VariableSpec title="Observation Space" specs={env.observation_spec} />
<VariableSpec title="Action Space" specs={env.action_spec} />
<h2 className="card-title">{envSpecs.name}</h2>
<VariableSpec
title="Observation Space"
specs={obsSpecs}
setSpecs={setObsSpecs}
onSave={onSave}
/>
<VariableSpec
title="Action Space"
specs={actSpecs}
setSpecs={setActSpecs}
onSave={onSave}
/>
<div className="card bg-base-100 max-w m-3">
<div className="card-body">
<h2 className="card-title">Detailed Env Specs</h2>
Expand Down
120 changes: 91 additions & 29 deletions frontend/src/components/variable_spec.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,112 @@
import React from "react";
import { VectorSpec } from "@/types/environment";

interface Props {
const VAR_DISP_LIMIT = 50;

export default function VariableSpec({
title,
specs,
setSpecs,
onSave,
}: {
title: string;
specs?: VectorSpec[];
}
specs: VectorSpec[];
setSpecs: React.Dispatch<React.SetStateAction<VectorSpec[]>>;
onSave: () => void;
}) {
const [isEditing, setIsEditing] = React.useState<boolean[]>(
specs.map(() => false) ?? []
);
const handleEditSubmitClick = (i: number) => {
setIsEditing((prevIsEditing) => {
const newIsEditing = [...prevIsEditing];
newIsEditing[i] = !prevIsEditing[i];
if (!newIsEditing[i]) {
onSave();
}
return newIsEditing;
});
};

export default function VariableSpec(props: Props) {
return (
<div className="card flex-shrink-0 max-w bg-base-100 m-3">
<div className="card-body">
<h2 className="card-title">{props.title}</h2>
{props.specs?.map((spec, i) => (
<h2 className="card-title">{title}</h2>
{specs.map((spec, i) => (
<div key={i}>
<p>{spec.space}</p>
<div className="card flex-shrink-0 shadow m-10">
<code className="bg-base-200">{spec.space}</code>
<div className="card flex-shrink-0 m-10">
<table className="table table-zebra">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Description</th>
<th></th>
</tr>
</thead>
<tbody>
{spec.var_info?.slice(0, 50).map((var_info, i) => (
<tr key={i}>
<th>{i + 1}</th>
<td>
<input
type="text"
className="input input-bordered w-full max-w-xs"
placeholder="Add Varible Name"
defaultValue={var_info.name ?? ""}
/>
</td>
<td>
<input
type="text"
className="input input-bordered w-full max-w-xs"
placeholder="Add Variable Description"
defaultValue={var_info.description ?? ""}
/>
</td>
</tr>
))}
{spec.var_info
?.slice(0, VAR_DISP_LIMIT)
.map((var_info, j) => (
<tr key={j}>
<th>{j + 1}</th>
<td>
{isEditing[j] ? (
<input
type="text"
className="input w-full max-w-xs bg-transparent input-bordered"
placeholder="Add Variable Name"
defaultValue={var_info.name ?? ""}
onBlur={(event) => {
setSpecs((prevState) => {
const newState = JSON.parse(
JSON.stringify(prevState)
);

newState[i].var_info[j].name =
event.target.value;
return newState;
});
}}
/>
) : (
<p>{var_info.name}</p>
)}
</td>
<td>
{isEditing[j] ? (
<textarea
className="input w-full max-w-xs bg-transparent input-bordered"
placeholder="Add Variable Description"
defaultValue={var_info.description ?? ""}
readOnly={!isEditing[j]}
onBlur={(event) => {
setSpecs((prevState) => {
const newState = JSON.parse(
JSON.stringify(prevState)
);

newState[i].var_info[j].description =
event.target.value;
return newState;
});
}}
/>
) : (
<p>{var_info.description}</p>
)}
</td>
<td>
<button
className="btn btn-sm btn-ghost normal-case"
onClick={() => handleEditSubmitClick(j)}
>
{isEditing[j] ? "Save" : "Edit"}
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
Expand Down
Loading