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

Feat: Allow users to rebuild the app #17

Merged
merged 2 commits into from
Aug 5, 2024
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
5 changes: 5 additions & 0 deletions web/app/components/gpu-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ const packageNamesRegex = new RegExp(
const packageNamesErrorMsg =
"Please provide values in comma separated format as suggested in examples";
export interface GpuFormProps {
machineName?: string;
customNodesJson: OutputCustomNodesJson;
modelsJson: OutputModel[];
onBackStep: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}

export default function GpuForm({
machineName,
onBackStep,
customNodesJson,
modelsJson,
Expand All @@ -69,6 +71,9 @@ export default function GpuForm({
id="machine-name"
name="machine_name"
placeholder="Machine name"
defaultValue={machineName}
disabled={!!machineName}
readOnly={!!machineName}
onChange={(e) => {
if (machineNameRegex.test(e.target.value)) {
setMachineNameError(null);
Expand Down
92 changes: 47 additions & 45 deletions web/app/routes/apps/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ interface AppsLayoutProps {
}

function AppsLayout({ apps }: AppsLayoutProps) {
const deleteFetcher = useDeleteFetcherAction();
const [appStateFilter, setAppStateFilter] = useState<string>("deployed");

const displayApps = apps.filter((app) => appStateFilter === app.state);
Expand Down Expand Up @@ -291,50 +290,7 @@ function AppsLayout({ apps }: AppsLayoutProps) {

<td className="py-2 pl-0 pr-4 text-right sm:table-cell sm:pr-6 lg:pr-8">
{app.state === "deployed" ? (
<Dialog>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DialogTrigger asChild>
<DropdownMenuItem>Delete</DropdownMenuItem>
</DialogTrigger>
</DropdownMenuContent>
</DropdownMenu>
<DialogContent>
<DialogHeader>
<DialogTitle>
Are you sure you want to delete the app?
</DialogTitle>
<DialogDescription>
This action cannot be undone. Are you sure you
want to permanently delete this app?
</DialogDescription>
</DialogHeader>
<DialogFooter>
<deleteFetcher.Form method="post">
<input
type="hidden"
name="actionType"
value="delete"
/>
<input
type="hidden"
name="appId"
value={app.app_id}
/>
<DialogClose asChild>
<Button type="submit">Delete</Button>
</DialogClose>
</deleteFetcher.Form>
</DialogFooter>
</DialogContent>
</Dialog>
<DropdownActionMenu app={app} />
) : null}
</td>
</tr>
Expand All @@ -352,6 +308,52 @@ function AppsLayout({ apps }: AppsLayoutProps) {
);
}

interface DropdownActionMenuProps {
app: App;
}
function DropdownActionMenu({ app }: DropdownActionMenuProps) {
const deleteFetcher = useDeleteFetcherAction();
return (
<Dialog>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DialogTrigger asChild>
<DropdownMenuItem>Delete</DropdownMenuItem>
</DialogTrigger>
<DropdownMenuItem>
<Link to={`/create-app?rebuild=${app.description}`}>Rebuild</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure you want to delete the app?</DialogTitle>
<DialogDescription>
This action cannot be undone. Are you sure you want to permanently
delete this app?
</DialogDescription>
</DialogHeader>
<DialogFooter>
<deleteFetcher.Form method="post">
<input type="hidden" name="actionType" value="delete" />
<input type="hidden" name="appId" value={app.app_id} />
<DialogClose asChild>
<Button type="submit">Delete</Button>
</DialogClose>
</deleteFetcher.Form>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

function ErrorLayout() {
const revalidator = useRevalidator();
return (
Expand Down
10 changes: 9 additions & 1 deletion web/app/routes/create-app/route.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { json, redirect, useFetcher, useLoaderData } from "@remix-run/react";
import {
json,
redirect,
useFetcher,
useLoaderData,
useSearchParams,
} from "@remix-run/react";

import {
CreateAppErrorResponseBody,
Expand Down Expand Up @@ -79,6 +85,7 @@ export const loader = async (args: LoaderFunctionArgs) => {
};

export default function CreateAppPage() {
const [searchParams, _] = useSearchParams();
const createAppFetcher = useFetcher<typeof action>({
key: CREATE_APP_FETCHER_KEY,
});
Expand Down Expand Up @@ -188,6 +195,7 @@ export default function CreateAppPage() {
{currentStep?.name == "GPU" ? (
<>
<GpuForm
machineName={searchParams.get("rebuild") ?? ""}
customNodesJson={convertCustomNodesJson(
selectedCustomNodes.concat(selectedCustomNodesFromWFFile)
)}
Expand Down