Skip to content

Commit

Permalink
[UI v2] feat: Scaffolds concurrency-limit route (#16370)
Browse files Browse the repository at this point in the history
  • Loading branch information
devinvillarosa authored Dec 27, 2024
1 parent f1aaad2 commit cf2f269
Show file tree
Hide file tree
Showing 85 changed files with 1,142 additions and 382 deletions.
17 changes: 17 additions & 0 deletions ui-v2/src/components/concurrency/concurrency-limits-page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Typography } from "@/components/ui/typography";

import { GlobalConcurrencyLimitsView } from "@/components/concurrency/global-concurrency-limits/global-concurrency-limits-view";
import { TaskRunConcurrencyLimitsView } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-view";
import { ConcurrencyLimitsTabs } from "./concurrency-limits-tabs";

export const ConcurrencyLimitsPage = () => {
return (
<div className="flex flex-col gap-4">
<Typography variant="h2">Concurrency</Typography>
<ConcurrencyLimitsTabs
globalView={<GlobalConcurrencyLimitsView />}
taskRunView={<TaskRunConcurrencyLimitsView />}
/>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { TabOptions } from "@/routes/concurrency-limits";
import type { TabOptions } from "@/routes/concurrency-limits";
import { getRouteApi } from "@tanstack/react-router";
import type { JSX } from "react";

const routeApi = getRouteApi("/concurrency-limits");
const routeApi = getRouteApi("/concurrency-limits/");

type TabOptionValues = {
/** Value of search value in url */
Expand All @@ -18,7 +18,7 @@ const TAB_OPTIONS: Record<TabOptions, TabOptionValues> = {
tabSearchValue: "global",
displayValue: "Global",
},
["task-run"]: {
"task-run": {
tabSearchValue: "task-run",
displayValue: "Task Run",
},
Expand All @@ -31,7 +31,7 @@ type Props = {

// TODO: Move Tabs for navigation to a generic styled component

export const ConcurrencyTabs = ({
export const ConcurrencyLimitsTabs = ({
globalView,
taskRunView,
}: Props): JSX.Element => {
Expand Down
19 changes: 0 additions & 19 deletions ui-v2/src/components/concurrency/concurrency-page.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
createFakeGlobalConcurrencyLimit,
reactQueryDecorator,
} from "@/storybook/utils";
import type { Meta, StoryObj } from "@storybook/react";
import { GlobalConcurrencyLimitsCreateOrEditDialog } from "./global-concurrency-limits-create-or-edit-dialog";

const meta = {
title:
"Components/Concurrency/GlobalConcurrencyLimits/GlobalConcurrencyLimitsCreateOrEditDialog",
component: GlobalConcurrencyLimitsCreateOrEditDialog,
decorators: [reactQueryDecorator],
args: {
onOpenChange: () => {},
onSubmit: () => {},
},
} satisfies Meta<typeof GlobalConcurrencyLimitsCreateOrEditDialog>;

export default meta;

type Story = StoryObj<typeof GlobalConcurrencyLimitsCreateOrEditDialog>;

export const CreateLimit: Story = {};

export const EditLimit: Story = {
args: {
limitToUpdate: createFakeGlobalConcurrencyLimit(),
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CreateOrEditLimitDialog } from "./create-or-edit-limit-dialog";
import { GlobalConcurrencyLimitsCreateOrEditDialog } from "./global-concurrency-limits-create-or-edit-dialog";

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
Expand All @@ -16,7 +16,7 @@ const MOCK_DATA = {
slot_decay_per_second: 0,
};

describe("CreateOrEditLimitDialog", () => {
describe("GlobalConcurrencyLimitsCreateOrEditDialog", () => {
beforeAll(() => {
class ResizeObserverMock {
observe() {}
Expand All @@ -33,7 +33,7 @@ describe("CreateOrEditLimitDialog", () => {
// ------------ Setup
const mockOnSubmitFn = vi.fn();
render(
<CreateOrEditLimitDialog
<GlobalConcurrencyLimitsCreateOrEditDialog
onOpenChange={vi.fn()}
onSubmit={mockOnSubmitFn}
/>,
Expand Down Expand Up @@ -62,7 +62,7 @@ describe("CreateOrEditLimitDialog", () => {
// ------------ Setup
const mockOnSubmitFn = vi.fn();
render(
<CreateOrEditLimitDialog
<GlobalConcurrencyLimitsCreateOrEditDialog
limitToUpdate={MOCK_DATA}
onOpenChange={vi.fn()}
onSubmit={mockOnSubmitFn}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,26 @@ import {
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
import { type GlobalConcurrencyLimit } from "@/hooks/global-concurrency-limits";
import type { GlobalConcurrencyLimit } from "@/hooks/global-concurrency-limits";

import { useCreateOrEditLimitForm } from "./use-create-or-edit-limit-form";
import { useCreateOrEditGlobalConcurrencyLimitForm } from "./use-create-or-edit-global-concurrency-limit-form";

type Props = {
limitToUpdate?: GlobalConcurrencyLimit;
onOpenChange: (open: boolean) => void;
onSubmit: () => void;
};

export const CreateOrEditLimitDialog = ({
export const GlobalConcurrencyLimitsCreateOrEditDialog = ({
limitToUpdate,
onOpenChange,
onSubmit,
}: Props) => {
const { form, isLoading, saveOrUpdate } = useCreateOrEditLimitForm({
limitToUpdate,
onSubmit,
});
const { form, isLoading, saveOrUpdate } =
useCreateOrEditGlobalConcurrencyLimitForm({
limitToUpdate,
onSubmit,
});

const dialogTitle = limitToUpdate
? `Update ${limitToUpdate.name}`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { GlobalConcurrencyLimitsCreateOrEditDialog } from "./global-concurrency-limits-create-or-edit-dialog";
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
GlobalConcurrencyLimit,
type GlobalConcurrencyLimit,
useCreateGlobalConcurrencyLimit,
useUpdateGlobalConcurrencyLimit,
} from "@/hooks/global-concurrency-limits";
Expand Down Expand Up @@ -38,17 +38,17 @@ const DEFAULT_VALUES = {
active_slots: 0,
} as const;

type useCreateOrEditLimitForm = {
type UseCreateOrEditGlobalConcurrencyLimitFormOptions = {
/** Limit to edit. Pass undefined if creating a new limit */
limitToUpdate: GlobalConcurrencyLimit | undefined;
/** Callback after hitting Save or Update */
onSubmit: () => void;
};

export const useCreateOrEditLimitForm = ({
export const useCreateOrEditGlobalConcurrencyLimitForm = ({
limitToUpdate,
onSubmit,
}: useCreateOrEditLimitForm) => {
}: UseCreateOrEditGlobalConcurrencyLimitFormOptions) => {
const { toast } = useToast();

const { createGlobalConcurrencyLimit, status: createStatus } =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Icon } from "@/components/ui/icons";
import type { GlobalConcurrencyLimit } from "@/hooks/global-concurrency-limits";
import { useToast } from "@/hooks/use-toast";
import type { CellContext } from "@tanstack/react-table";

type Props = CellContext<GlobalConcurrencyLimit, unknown> & {
onEditRow: (row: GlobalConcurrencyLimit) => void;
onDeleteRow: (row: GlobalConcurrencyLimit) => void;
};

export const ActionsCell = ({ onEditRow, onDeleteRow, ...props }: Props) => {
const { toast } = useToast();

const handleCopyId = (id: string | undefined) => {
if (!id) {
throw new Error("'id' field expected in GlobalConcurrencyLimit");
}
void navigator.clipboard.writeText(id);
toast({ title: "ID copied" });
};

const row = props.row.original;

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="h-8 w-8 p-0">
<span className="sr-only">Open menu</span>
<Icon id="MoreVertical" className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem onClick={() => handleCopyId(row.id)}>
Copy ID
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onDeleteRow(row)}>
Delete
</DropdownMenuItem>
<DropdownMenuItem onClick={() => onEditRow(row)}>Edit</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const ActiveCell = (

const handleCheckedChange = (checked: boolean, id: string | undefined) => {
if (!id) {
throw new Error("Expecting 'id' of global concurrent limit");
throw new Error("Expecting 'id' of global concurrency limit");
}

updateGlobalConcurrencyLimit(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
createFakeGlobalConcurrencyLimit,
reactQueryDecorator,
} from "@/storybook/utils";
import type { Meta, StoryObj } from "@storybook/react";
import { Table as GlobalConcurrencyLimitsDataTable } from "./global-concurrency-limits-data-table";

const MOCK_DATA = [
createFakeGlobalConcurrencyLimit(),
createFakeGlobalConcurrencyLimit(),
createFakeGlobalConcurrencyLimit(),
createFakeGlobalConcurrencyLimit(),
createFakeGlobalConcurrencyLimit(),
];

const meta = {
title:
"Components/Concurrency/GlobalConcurrencyLimits/GlobalConcurrencyLimitsDataTable",
component: GlobalConcurrencyLimitsDataTable,
decorators: [reactQueryDecorator],
args: {
data: MOCK_DATA,
onDeleteRow: () => {},
onEditRow: () => {},
onSearchChange: () => {},
searchValue: "",
},
} satisfies Meta<typeof GlobalConcurrencyLimitsDataTable>;

export default meta;

export const Story: StoryObj = {
name: "GlobalConcurrencyLimitsDataTable",
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { createWrapper } from "@tests/utils";
import { describe, expect, it, vi } from "vitest";
import { Table } from "./data-table";
import { Table } from "./global-concurrency-limits-data-table";

const MOCK_ROW = {
id: "0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DataTable } from "@/components/ui/data-table";
import { type GlobalConcurrencyLimit } from "@/hooks/global-concurrency-limits";
import type { GlobalConcurrencyLimit } from "@/hooks/global-concurrency-limits";
import { getRouteApi } from "@tanstack/react-router";
import {
createColumnHelper,
Expand All @@ -13,7 +13,7 @@ import { useDeferredValue, useMemo } from "react";
import { ActionsCell } from "./actions-cell";
import { ActiveCell } from "./active-cell";

const routeApi = getRouteApi("/concurrency-limits");
const routeApi = getRouteApi("/concurrency-limits/");

const columnHelper = createColumnHelper<GlobalConcurrencyLimit>();

Expand Down Expand Up @@ -43,7 +43,13 @@ const createColumns = ({
columnHelper.display({
id: "actions",
cell: (props) => (
<ActionsCell {...props} onEditRow={onEditRow} onDeleteRow={onDeleteRow} />
<div className="flex flex-row justify-end">
<ActionsCell
{...props}
onEditRow={onEditRow}
onDeleteRow={onDeleteRow}
/>
</div>
),
}),
];
Expand All @@ -54,7 +60,7 @@ type Props = {
onDeleteRow: (row: GlobalConcurrencyLimit) => void;
};

export const GlobalConcurrencyDataTable = ({
export const GlobalConcurrencyLimitsDataTable = ({
data,
onEditRow,
onDeleteRow,
Expand Down Expand Up @@ -110,6 +116,7 @@ export function Table({
return (
<div className="flex flex-col gap-4">
<SearchInput
className="max-w-72"
placeholder="Search global concurrency limit"
value={searchValue}
onChange={(e) => onSearchChange(e.target.value)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { GlobalConcurrencyLimitsDataTable } from "./global-concurrency-limits-data-table";
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
createFakeGlobalConcurrencyLimit,
reactQueryDecorator,
} from "@/storybook/utils";
import type { Meta, StoryObj } from "@storybook/react";
import { GlobalConcurrencyLimitsDeleteDialog } from "./global-concurrency-limits-delete-dialog";

const meta = {
title:
"Components/Concurrency/GlobalConcurrencyLimits/GlobalConcurrencyLimitsDeleteDialog",
component: GlobalConcurrencyLimitsDeleteDialog,
decorators: [reactQueryDecorator],
args: {
limit: createFakeGlobalConcurrencyLimit(),
onOpenChange: () => {},
onDelete: () => {},
},
} satisfies Meta<typeof GlobalConcurrencyLimitsDeleteDialog>;

export default meta;

export const story: StoryObj = { name: "GlobalConcurrencyLimitsDeleteDialog" };
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeleteLimitDialog } from "./delete-limit-dialog";
import { GlobalConcurrencyLimitsDeleteDialog } from "./global-concurrency-limits-delete-dialog";

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
Expand All @@ -16,13 +16,13 @@ const MOCK_DATA = {
slot_decay_per_second: 0,
};

test("DeleteLimitDialog can successfully call delete", async () => {
test("GlobalConcurrencyLimitsDeleteDialog can successfully call delete", async () => {
const user = userEvent.setup();

// ------------ Setup
const mockOnDeleteFn = vi.fn();
render(
<DeleteLimitDialog
<GlobalConcurrencyLimitsDeleteDialog
limit={MOCK_DATA}
onDelete={mockOnDeleteFn}
onOpenChange={vi.fn()}
Expand Down
Loading

0 comments on commit cf2f269

Please sign in to comment.