Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
devinvillarosa committed Feb 12, 2025
1 parent e6aa657 commit 4515660
Show file tree
Hide file tree
Showing 12 changed files with 554 additions and 10 deletions.
52 changes: 50 additions & 2 deletions ui-v2/src/components/deployments/deployment-details-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,59 @@ import { buildDeploymentDetailsQuery } from "@/api/deployments";
import { DeleteConfirmationDialog } from "@/components/ui/delete-confirmation-dialog";
import { Skeleton } from "@/components/ui/skeleton";
import { useSuspenseQuery } from "@tanstack/react-query";
import { Suspense } from "react";
import { Suspense, useMemo, useState } from "react";

import { DeploymentActionMenu } from "./deployment-action-menu";
import { DeploymentDetailsHeader } from "./deployment-details-header";
import { DeploymentDetailsTabs } from "./deployment-details-tabs";
import { DeploymentFlowLink } from "./deployment-flow-link";
import { DeploymentMetadata } from "./deployment-metadata";
import { DeploymentScheduleDialog } from "./deployment-schedules/deployment-schedule-dialog";
import { DeploymentSchedules } from "./deployment-schedules/deployment-schedules";
import { DeploymentTriggers } from "./deployment-triggers";
import { RunFlowButton } from "./run-flow-button";
import { useDeleteDeploymentConfirmationDialog } from "./use-delete-deployment-confirmation-dialog";

type Dialogs = "create" | "edit";

type DeploymentDetailsPageProps = {
id: string;
};

export const DeploymentDetailsPage = ({ id }: DeploymentDetailsPageProps) => {
const [showScheduleDialog, setShowScheduleDialog] = useState<Dialogs | null>(
null,
);
const [scheduleIdToEdit, setScheduleIdToEdit] = useState("");

const { data: deployment } = useSuspenseQuery(
buildDeploymentDetailsQuery(id),
);

const [deleteConfirmationDialogState, confirmDelete] =
useDeleteDeploymentConfirmationDialog();

const scheduleToEdit = useMemo(() => {
if (!deployment.schedules) {
return undefined;
}
return deployment.schedules.find(
(schedule) => schedule.id === scheduleIdToEdit,
);
}, [deployment.schedules, scheduleIdToEdit]);

const handleAddSchedule = () => setShowScheduleDialog("create");
const handleEditSchedule = (scheduleId: string) => {
setScheduleIdToEdit(scheduleId);
setShowScheduleDialog("edit");
};
const closeDialog = () => setShowScheduleDialog(null);
const handleOpenChange = (open: boolean) => {
if (!open) {
closeDialog();
}
};

return (
<>
<div className="flex flex-col gap-4">
Expand All @@ -51,7 +80,11 @@ export const DeploymentDetailsPage = ({ id }: DeploymentDetailsPageProps) => {
<DeploymentDetailsTabs deployment={deployment} />
</div>
<div className="flex flex-col gap-3">
<DeploymentSchedules deployment={deployment} />
<DeploymentSchedules
deployment={deployment}
onAddSchedule={handleAddSchedule}
onEditSchedule={handleEditSchedule}
/>

<Suspense fallback={<LoadingSkeleton numSkeletons={2} />}>
<DeploymentTriggers deployment={deployment} />
Expand All @@ -62,6 +95,21 @@ export const DeploymentDetailsPage = ({ id }: DeploymentDetailsPageProps) => {
</div>
</div>
</div>
<DeploymentScheduleDialog
deployment_id={id}
onSubmit={closeDialog}
open={showScheduleDialog === "create"}
onOpenChange={handleOpenChange}
/>
{scheduleToEdit && (
<DeploymentScheduleDialog
deployment_id={id}
onSubmit={closeDialog}
open={showScheduleDialog === "edit"}
onOpenChange={handleOpenChange}
scheduleToEdit={scheduleToEdit}
/>
)}
<DeleteConfirmationDialog {...deleteConfirmationDialogState} />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { CronInput } from "@/components/ui/cron-input";
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Switch } from "@/components/ui/switch";
import { TimezoneSelect } from "@/components/ui/timezone-select";
import { UseFormReturn } from "react-hook-form";
import type { FormSchema } from "./use-create-or-edit-schedule-form";

type CronScheduleFormProps = {
form: UseFormReturn<FormSchema>;
};

export const CronScheduleForm = ({ form }: CronScheduleFormProps) => (
<div className="flex flex-col gap-4">
<FormField
control={form.control}
name="active"
render={({ field }) => (
<FormItem>
<FormLabel>Active</FormLabel>
<FormControl>
<Switch
className="block"
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex gap-2">
<div className="w-3/4">
<FormField
control={form.control}
name="schedule.cron"
render={({ field }) => (
<FormItem>
<FormLabel>Value</FormLabel>
<FormControl>
<CronInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="schedule.day_or"
render={({ field }) => (
<FormItem>
<FormLabel>Day Or</FormLabel>
<FormControl>
<Switch
className="block"
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="schedule.timezone"
render={({ field }) => (
<FormItem>
<FormLabel>Timezone</FormLabel>
<FormControl>
<TimezoneSelect
selectedValue={field.value}
onSelect={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import type { DeploymentSchedule } from "@/components/deployments/deployment-schedules/types";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Form, FormMessage } from "@/components/ui/form";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

import { CronScheduleForm } from "./cron-schedule-form";
import { IntervalScheduleForm } from "./interval-schedule-form";
import { RRuleScheduleForm } from "./rrule-schedule-form";
import { useCreateOrEditScheduleForm } from "./use-create-or-edit-schedule-form";

type DeploymentScheduleDialogProps = {
deployment_id: string;
onOpenChange: (open: boolean) => void;
onSubmit: () => void;
open: boolean;
scheduleToEdit?: DeploymentSchedule;
};

export const DeploymentScheduleDialog = ({
deployment_id,
onOpenChange,
onSubmit,
open,
scheduleToEdit,
}: DeploymentScheduleDialogProps) => {
const { form, saveOrUpdate, isLoading } = useCreateOrEditScheduleForm({
deployment_id,
onSubmit,
scheduleToEdit,
});

const SCHEDULE_TAB_OPTIONS = [
{
value: "interval",
label: "Interval",
Component: () => <IntervalScheduleForm form={form} />,
},
{
value: "cron",
label: "Cron",
Component: () => <CronScheduleForm form={form} />,
},
{ value: "rrule", label: "RRule", Component: () => <RRuleScheduleForm /> },
] as const;

const scheduleTab = form.watch("tab");

return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent aria-describedby={undefined}>
<DialogHeader>
<DialogTitle>{scheduleToEdit ? "Edit" : "Add"} Schedule</DialogTitle>
</DialogHeader>

<Form {...form}>
<form
onSubmit={(e) => void form.handleSubmit(saveOrUpdate)(e)}
className="space-y-4"
>
<FormMessage>{form.formState.errors.root?.message}</FormMessage>
<Tabs
defaultValue={SCHEDULE_TAB_OPTIONS[0].value}
value={scheduleTab}
>
<TabsList>
{SCHEDULE_TAB_OPTIONS.map(({ value, label }) => (
<TabsTrigger
key={value}
value={value}
onClick={() => form.setValue("tab", value)}
>
{label}
</TabsTrigger>
))}
</TabsList>
{SCHEDULE_TAB_OPTIONS.map(({ value, Component }) => (
<TabsContent key={value} value={value}>
<Component />
</TabsContent>
))}
</Tabs>
<DialogFooter>
<DialogTrigger asChild>
<Button variant="outline">Close</Button>
</DialogTrigger>
<Button type="submit" loading={isLoading}>
Save
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DeploymentScheduleDialog } from "./deployment-schedule-dialog";
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Calendar } from "@/components/ui/calendar";
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Switch } from "@/components/ui/switch";
import { TimezoneSelect } from "@/components/ui/timezone-select";
import { UseFormReturn } from "react-hook-form";
import type { FormSchema } from "./use-create-or-edit-schedule-form";

type IntervalScheduleFormProps = {
form: UseFormReturn<FormSchema>;
};

export const IntervalScheduleForm = ({ form }: IntervalScheduleFormProps) => (
<div className="flex flex-col gap-4">
<FormField
control={form.control}
name="active"
render={({ field }) => (
<FormItem>
<FormLabel>Active</FormLabel>
<FormControl>
<Switch
className="block"
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex gap-2"></div>
<FormField
control={form.control}
name="schedule.anchor_date"
render={({ field }) => (
<FormItem>
<FormLabel>Anchor date</FormLabel>
<FormControl>
<Calendar
mode="single"
selected={new Date(field.value)}
onSelect={(value) => String(field.onChange(value))}
required
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="schedule.timezone"
render={({ field }) => (
<FormItem>
<FormLabel>Timezone</FormLabel>
<FormControl>
<TimezoneSelect
selectedValue={field.value}
onSelect={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Typography } from "@/components/ui/typography";

export const RRuleScheduleForm = () => (
<Typography>
Sorry, modifying RRule schedules via the UI is currently unsupported; select
a different schedule type above or modify your schedule in code.
</Typography>
);
Loading

0 comments on commit 4515660

Please sign in to comment.