Skip to content

Commit

Permalink
[UI v2] feat: Adds deployment schedule cron tab (#17132)
Browse files Browse the repository at this point in the history
  • Loading branch information
devinvillarosa authored Feb 13, 2025
1 parent 016fb00 commit cd03e6f
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 38 deletions.
1 change: 1 addition & 0 deletions ui-v2/src/api/deployments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export type Deployment = components["schemas"]["DeploymentResponse"];
export type DeploymentWithFlow = Deployment & {
flow?: components["schemas"]["Flow"];
};
export type DeploymentSchedule = components["schemas"]["DeploymentSchedule"];
export type DeploymentsFilter =
components["schemas"]["Body_read_deployments_deployments_filter_post"];
export type DeploymentsPaginationFilter =
Expand Down
41 changes: 18 additions & 23 deletions ui-v2/src/components/deployments/deployment-details-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ 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 [showScheduleDialog, setShowScheduleDialog] = useState({
open: false,
scheduleIdToEdit: "",
});

const { data: deployment } = useSuspenseQuery(
buildDeploymentDetailsQuery(id),
Expand All @@ -35,20 +33,20 @@ export const DeploymentDetailsPage = ({ id }: DeploymentDetailsPageProps) => {
useDeleteDeploymentConfirmationDialog();

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

const handleAddSchedule = () => setShowScheduleDialog("create");
const handleEditSchedule = (scheduleId: string) => {
setScheduleIdToEdit(scheduleId);
setShowScheduleDialog("edit");
};
const closeDialog = () => setShowScheduleDialog(null);
const handleAddSchedule = () =>
setShowScheduleDialog({ open: true, scheduleIdToEdit: "" });
const handleEditSchedule = (scheduleId: string) =>
setShowScheduleDialog({ open: true, scheduleIdToEdit: scheduleId });
const closeDialog = () =>
setShowScheduleDialog({ open: false, scheduleIdToEdit: "" });
const handleOpenChange = (open: boolean) => {
// nb: Only need to handle when closing the dialog
if (!open) {
Expand Down Expand Up @@ -97,16 +95,13 @@ export const DeploymentDetailsPage = ({ id }: DeploymentDetailsPageProps) => {
</div>
</div>
<DeploymentScheduleDialog
open={showScheduleDialog === "create"}
deploymentId={id}
open={showScheduleDialog.open}
onOpenChange={handleOpenChange}
scheduleToEdit={scheduleToEdit}
onSubmit={closeDialog}
/>
{scheduleToEdit && (
<DeploymentScheduleDialog
open={showScheduleDialog === "edit"}
onOpenChange={handleOpenChange}
scheduleToEdit={scheduleToEdit}
/>
)}

<DeleteConfirmationDialog {...deleteConfirmationDialogState} />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeAll, describe, expect, it, vi } from "vitest";

import { Dialog } from "@/components/ui/dialog";
import { Toaster } from "@/components/ui/toaster";
import { createWrapper } from "@tests/utils";
import { mockPointerEvents } from "@tests/utils/browser";
import {
CronScheduleForm,
type CronScheduleFormProps,
} from "./cron-schedule-form";

const CronScheduleFormTest = (props: CronScheduleFormProps) => (
<>
<Toaster />
<Dialog>
<CronScheduleForm {...props} />
</Dialog>
</>
);

describe("CronScheduleForm", () => {
beforeAll(mockPointerEvents);

it("is able to create a new cron schedule", async () => {
// Setup
const user = userEvent.setup();
render(<CronScheduleFormTest deployment_id="0" onSubmit={vi.fn()} />, {
wrapper: createWrapper(),
});

// Test
await user.click(screen.getByLabelText(/active/i));
await user.clear(screen.getByLabelText(/value/i));
await user.type(screen.getByLabelText(/value/i), "* * * * 1/2");
await user.click(screen.getByLabelText(/day or/i));
await user.click(
screen.getByRole("combobox", { name: /select timezone/i }),
);
await user.click(screen.getByRole("option", { name: /africa \/ asmera/i }));
await user.click(screen.getByRole("button", { name: /save/i }));

screen.logTestingPlaygroundURL();

// ------------ Assert

expect(screen.getByLabelText(/active/i)).not.toBeChecked();
expect(screen.getByLabelText(/value/i)).toHaveValue("* * * * 1/2");
expect(screen.getByLabelText(/day or/i)).not.toBeChecked();
});

it("is able to edit a new cron schedule", () => {
// Setup
const MOCK_SCHEDULE = {
active: true,
created: "0",
deployment_id: "0",
id: "123",
updated: "0",
schedule: {
cron: "* * * * 1/2",
day_or: true,
timezone: '"Etc/UTC"',
},
};

render(
<CronScheduleFormTest
deployment_id="0"
onSubmit={vi.fn()}
scheduleToEdit={MOCK_SCHEDULE}
/>,
{ wrapper: createWrapper() },
);

// ------------ Assert

expect(screen.getByLabelText(/active/i)).toBeChecked();
expect(screen.getByLabelText(/value/i)).toHaveValue("* * * * 1/2");
expect(screen.getByLabelText(/day or/i)).toBeChecked();
});
});
Loading

0 comments on commit cd03e6f

Please sign in to comment.