diff --git a/ui-v2/src/components/concurrency/concurrency-limits-page.tsx b/ui-v2/src/components/concurrency/concurrency-limits-page.tsx new file mode 100644 index 000000000000..18b3c5e81987 --- /dev/null +++ b/ui-v2/src/components/concurrency/concurrency-limits-page.tsx @@ -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 ( +
+ Concurrency + } + taskRunView={} + /> +
+ ); +}; diff --git a/ui-v2/src/components/concurrency/concurrency-tabs.tsx b/ui-v2/src/components/concurrency/concurrency-limits-tabs.tsx similarity index 91% rename from ui-v2/src/components/concurrency/concurrency-tabs.tsx rename to ui-v2/src/components/concurrency/concurrency-limits-tabs.tsx index 03789c9d78de..a81120e1e6cc 100644 --- a/ui-v2/src/components/concurrency/concurrency-tabs.tsx +++ b/ui-v2/src/components/concurrency/concurrency-limits-tabs.tsx @@ -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 */ @@ -18,7 +18,7 @@ const TAB_OPTIONS: Record = { tabSearchValue: "global", displayValue: "Global", }, - ["task-run"]: { + "task-run": { tabSearchValue: "task-run", displayValue: "Task Run", }, @@ -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 => { diff --git a/ui-v2/src/components/concurrency/concurrency-page.tsx b/ui-v2/src/components/concurrency/concurrency-page.tsx deleted file mode 100644 index 85a45c4c915a..000000000000 --- a/ui-v2/src/components/concurrency/concurrency-page.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import type { JSX } from "react"; - -import { Typography } from "@/components/ui/typography"; - -import { ConcurrencyTabs } from "./concurrency-tabs"; -import { GlobalConcurrencyView } from "./global-concurrency-view"; -import { TaskRunConcurrencyView } from "./task-run-concurrenct-view"; - -export const ConcurrencyPage = (): JSX.Element => { - return ( -
- Concurrency - } - taskRunView={} - /> -
- ); -}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.stories.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.stories.tsx new file mode 100644 index 000000000000..34917f7e327f --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.stories.tsx @@ -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; + +export default meta; + +type Story = StoryObj; + +export const CreateLimit: Story = {}; + +export const EditLimit: Story = { + args: { + limitToUpdate: createFakeGlobalConcurrencyLimit(), + }, +}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/create-or-edit-limit-dialog.test.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.test.tsx similarity index 88% rename from ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/create-or-edit-limit-dialog.test.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.test.tsx index e8473af769a8..4242be417f41 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/create-or-edit-limit-dialog.test.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/global-concurrency-limits-create-or-edit-dialog.test.tsx @@ -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"; @@ -16,7 +16,7 @@ const MOCK_DATA = { slot_decay_per_second: 0, }; -describe("CreateOrEditLimitDialog", () => { +describe("GlobalConcurrencyLimitsCreateOrEditDialog", () => { beforeAll(() => { class ResizeObserverMock { observe() {} @@ -33,7 +33,7 @@ describe("CreateOrEditLimitDialog", () => { // ------------ Setup const mockOnSubmitFn = vi.fn(); render( - , @@ -62,7 +62,7 @@ describe("CreateOrEditLimitDialog", () => { // ------------ Setup const mockOnSubmitFn = vi.fn(); render( - 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}` diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/index.ts b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/index.ts new file mode 100644 index 000000000000..d7e679f4997a --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/index.ts @@ -0,0 +1 @@ +export { GlobalConcurrencyLimitsCreateOrEditDialog } from "./global-concurrency-limits-create-or-edit-dialog"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/use-create-or-edit-limit-form.ts b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/use-create-or-edit-global-concurrency-limit-form.ts similarity index 93% rename from ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/use-create-or-edit-limit-form.ts rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/use-create-or-edit-global-concurrency-limit-form.ts index a55ec64fb518..317d3d2ff74b 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/use-create-or-edit-limit-form.ts +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-create-or-edit-dialog/use-create-or-edit-global-concurrency-limit-form.ts @@ -1,5 +1,5 @@ import { - GlobalConcurrencyLimit, + type GlobalConcurrencyLimit, useCreateGlobalConcurrencyLimit, useUpdateGlobalConcurrencyLimit, } from "@/hooks/global-concurrency-limits"; @@ -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 } = diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/actions-cell.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/actions-cell.tsx new file mode 100644 index 000000000000..c7304901c23d --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/actions-cell.tsx @@ -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 & { + 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 ( + + + + + + Actions + handleCopyId(row.id)}> + Copy ID + + onDeleteRow(row)}> + Delete + + onEditRow(row)}>Edit + + + ); +}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/active-cell.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/active-cell.tsx similarity index 94% rename from ui-v2/src/components/concurrency/global-concurrency-view/data-table/active-cell.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/active-cell.tsx index ce0a452b9a4a..5df9064ce3ed 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/active-cell.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/active-cell.tsx @@ -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( diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.stories.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.stories.tsx new file mode 100644 index 000000000000..2476698dce58 --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.stories.tsx @@ -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; + +export default meta; + +export const Story: StoryObj = { + name: "GlobalConcurrencyLimitsDataTable", +}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.test.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.test.tsx similarity index 97% rename from ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.test.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.test.tsx index 16e35f843441..90cd8a76cb27 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.test.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.test.tsx @@ -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", diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.tsx similarity index 88% rename from ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.tsx index d246a82a0885..ae6fbd01eb3e 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/data-table.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/global-concurrency-limits-data-table.tsx @@ -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, @@ -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(); @@ -43,7 +43,13 @@ const createColumns = ({ columnHelper.display({ id: "actions", cell: (props) => ( - +
+ +
), }), ]; @@ -54,7 +60,7 @@ type Props = { onDeleteRow: (row: GlobalConcurrencyLimit) => void; }; -export const GlobalConcurrencyDataTable = ({ +export const GlobalConcurrencyLimitsDataTable = ({ data, onEditRow, onDeleteRow, @@ -110,6 +116,7 @@ export function Table({ return (
onSearchChange(e.target.value)} diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/index.ts b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/index.ts new file mode 100644 index 000000000000..6ad53cca2eea --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-data-table/index.ts @@ -0,0 +1 @@ +export { GlobalConcurrencyLimitsDataTable } from "./global-concurrency-limits-data-table"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.stories.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.stories.tsx new file mode 100644 index 000000000000..57ea259206be --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.stories.tsx @@ -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; + +export default meta; + +export const story: StoryObj = { name: "GlobalConcurrencyLimitsDeleteDialog" }; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/delete-limit-dialog.test.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.test.tsx similarity index 79% rename from ui-v2/src/components/concurrency/global-concurrency-view/dialog/delete-limit-dialog.test.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.test.tsx index 3f9f227f8618..3cf322bbe82b 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/delete-limit-dialog.test.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/global-concurrency-limits-delete-dialog.test.tsx @@ -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"; @@ -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( - void; }; -export const DeleteLimitDialog = ({ limit, onOpenChange, onDelete }: Props) => { +export const GlobalConcurrencyLimitsDeleteDialog = ({ + limit, + onOpenChange, + onDelete, +}: Props) => { const { toast } = useToast(); const { deleteGlobalConcurrencyLimit, isPending } = useDeleteGlobalConcurrencyLimit(); diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/index.ts b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/index.ts new file mode 100644 index 000000000000..66143d007ad2 --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-delete-dialog/index.ts @@ -0,0 +1 @@ +export { GlobalConcurrencyLimitsDeleteDialog } from "./global-concurrency-limits-delete-dialog"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.stories.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.stories.tsx new file mode 100644 index 000000000000..d5f936f859b6 --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.stories.tsx @@ -0,0 +1,13 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { GlobalConcurrencyLimitsEmptyState } from "./global-concurrency-limits-empty-state"; + +export const story: StoryObj = { name: "GlobalConcurrencyLimitsEmptyState" }; + +export default { + title: + "Components/Concurrency/GlobalConcurrencyLimits/GlobalConcurrencyLimitsEmptyState", + component: GlobalConcurrencyLimitsEmptyState, + args: { + onAdd: () => {}, + }, +} satisfies Meta; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.test.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.test.tsx similarity index 72% rename from ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.test.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.test.tsx index b2590e75f2dc..4b586da07140 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.test.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.test.tsx @@ -1,14 +1,14 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { expect, test, vi } from "vitest"; -import { GlobalConcurrencyLimitEmptyState } from "./global-concurrency-limit-empty-state"; +import { GlobalConcurrencyLimitsEmptyState } from "./global-concurrency-limits-empty-state"; test("GlobalConcurrencyLimitEmptyState", async () => { const user = userEvent.setup(); const mockFn = vi.fn(); - render(); + render(); await user.click( screen.getByRole("button", { name: /Add Concurrency Limit/i }), ); diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.tsx similarity index 92% rename from ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.tsx index 5ed33c7800c8..c7bd421bec00 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/global-concurrency-limit-empty-state.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/global-concurrency-limits-empty-state.tsx @@ -12,7 +12,7 @@ import { Icon } from "@/components/ui/icons"; type Props = { onAdd: () => void; }; -export const GlobalConcurrencyLimitEmptyState = ({ onAdd }: Props) => ( +export const GlobalConcurrencyLimitsEmptyState = ({ onAdd }: Props) => ( Add a concurrency limit diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/index.ts b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/index.ts new file mode 100644 index 000000000000..1d17920bd415 --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-empty-state/index.ts @@ -0,0 +1 @@ +export { GlobalConcurrencyLimitsEmptyState } from "./global-concurrency-limits-empty-state"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.stories.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.stories.tsx new file mode 100644 index 000000000000..7723c8d5fa57 --- /dev/null +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { GlobalConcurrencyLimitsHeader } from "./global-concurrency-limits-header"; + +const meta = { + title: + "Components/Concurrency/GlobalConcurrencyLimits/GlobalConcurrencyLimitsHeader", + component: GlobalConcurrencyLimitsHeader, + args: { + onAdd: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const Story: StoryObj = { + name: "GlobalConcurrencyLimitsHeader", +}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/header/global-concurrency-limits-header.test.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.test.tsx similarity index 100% rename from ui-v2/src/components/concurrency/global-concurrency-view/header/global-concurrency-limits-header.test.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.test.tsx diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/header/global-concurrency-limits-header.tsx b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.tsx similarity index 92% rename from ui-v2/src/components/concurrency/global-concurrency-view/header/global-concurrency-limits-header.tsx rename to ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.tsx index f5f057d3e25c..105876342600 100644 --- a/ui-v2/src/components/concurrency/global-concurrency-view/header/global-concurrency-limits-header.tsx +++ b/ui-v2/src/components/concurrency/global-concurrency-limits/global-concurrency-limits-header/global-concurrency-limits-header.tsx @@ -13,6 +13,8 @@ export const GlobalConcurrencyLimitsHeader = ({ onAdd }: Props) => { - - - Actions - handleCopyId(row.id)}> - Copy ID - - onDeleteRow(row)}> - Delete - - onEditRow(row)}> - Edit - - - -
- ); -}; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/index.ts b/ui-v2/src/components/concurrency/global-concurrency-view/data-table/index.ts deleted file mode 100644 index efe2adf76286..000000000000 --- a/ui-v2/src/components/concurrency/global-concurrency-view/data-table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { GlobalConcurrencyDataTable } from "./data-table"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/index.ts b/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/index.ts deleted file mode 100644 index 3d271c515e53..000000000000 --- a/ui-v2/src/components/concurrency/global-concurrency-view/dialog/create-or-edit-limit-dialog/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CreateOrEditLimitDialog } from "./create-or-edit-limit-dialog"; diff --git a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/index.ts b/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/index.ts deleted file mode 100644 index 48db61994bde..000000000000 --- a/ui-v2/src/components/concurrency/global-concurrency-view/empty-state/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { GlobalConcurrencyLimitEmptyState } from "./global-concurrency-limit-empty-state"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/actions-cell.tsx b/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/actions-cell.tsx deleted file mode 100644 index 5e5b07daee7e..000000000000 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/actions-cell.tsx +++ /dev/null @@ -1,56 +0,0 @@ -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 TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; -import { useToast } from "@/hooks/use-toast"; -import { CellContext } from "@tanstack/react-table"; - -type Props = CellContext & { - onDeleteRow: (row: TaskRunConcurrencyLimit) => void; - onResetRow: (row: TaskRunConcurrencyLimit) => void; -}; - -export const ActionsCell = ({ onDeleteRow, onResetRow, ...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: "Name copied" }); - }; - - const row = props.row.original; - - return ( -
- - - - - - Actions - handleCopyId(row.id)}> - Copy ID - - onDeleteRow(row)}> - Delete - - onResetRow(row)}> - Reset - - - -
- ); -}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.test.tsx b/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.test.tsx deleted file mode 100644 index 85961acb10e5..000000000000 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.test.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { describe, expect, it, vi } from "vitest"; -import { Table } from "./data-table"; - -const MOCK_ROW = { - id: "0", - created: "2021-01-01T00:00:00Z", - updated: "2021-01-01T00:00:00Z", - tag: "my tag 0", - concurrency_limit: 1, - active_slots: [] as Array, -}; - -describe("TaskRunDataTable -- table", () => { - it("renders row data", () => { - render( - , - ); - expect(screen.getByRole("cell", { name: /my tag 0/i })).toBeVisible(); - expect(screen.getByRole("cell", { name: /1/i })).toBeVisible(); - }); - it("calls onDelete upon clicking delete action menu item", async () => { - const user = userEvent.setup(); - - const mockFn = vi.fn(); - - render( -
, - ); - await user.click( - screen.getByRole("button", { name: /open menu/i, hidden: true }), - ); - await user.click(screen.getByRole("menuitem", { name: /delete/i })); - expect(mockFn).toHaveBeenCalledWith(MOCK_ROW); - }); - it("calls onReset upon clicking rest action menu item", async () => { - const user = userEvent.setup(); - const mockFn = vi.fn(); - - render( -
, - ); - await user.click( - screen.getByRole("button", { name: /open menu/i, hidden: true }), - ); - await user.click(screen.getByRole("menuitem", { name: /reset/i })); - expect(mockFn).toHaveBeenCalledWith(MOCK_ROW); - }); -}); diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/index.ts b/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/index.ts deleted file mode 100644 index be5bcc6d4a6b..000000000000 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { TaskRunConcurrencyDataTable } from "./data-table"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/index.ts b/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/index.ts deleted file mode 100644 index 75c9c520c471..000000000000 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { TaskRunConcurrencyLimitEmptyState } from "./task-run-concurrency-limit-empty-state"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-active-task-runs/index.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-active-task-runs/index.tsx new file mode 100644 index 000000000000..20337917f960 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-active-task-runs/index.tsx @@ -0,0 +1,3 @@ +export const TaskRunConcurrencyLimitActiveTaskRuns = () => { + return
TODO: Active Task Runs View
; +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/index.ts new file mode 100644 index 000000000000..49fde8f8e31a --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitDetails } from "./task-run-concurrency-limit-details"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.stories.tsx new file mode 100644 index 000000000000..50ffa97467d8 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.stories.tsx @@ -0,0 +1,13 @@ +import { createFakeTaskRunConcurrencyLimit } from "@/storybook/utils"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { TaskRunConcurrencyLimitDetails } from "./task-run-concurrency-limit-details"; + +export default { + component: TaskRunConcurrencyLimitDetails, + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitDetails", + args: { data: createFakeTaskRunConcurrencyLimit() }, +} satisfies Meta; + +export const story: StoryObj = { name: "TaskRunConcurrencyLimitDetails" }; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.tsx new file mode 100644 index 000000000000..65072b8aea53 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details/task-run-concurrency-limit-details.tsx @@ -0,0 +1,67 @@ +import { cn } from "@/lib/utils"; + +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import { format, parseISO } from "date-fns"; +import React from "react"; + +type Props = { + data: TaskRunConcurrencyLimit; +}; + +export const TaskRunConcurrencyLimitDetails = ({ data }: Props) => { + return ( +
+
Tag
+
{data.tag}
+
+
+ {getKeyValueList(data).map((d) => ( + +
{d.label}
+
+ {d.value} +
+
+ ))} +
+
+ ); +}; + +const getKeyValueList = (data: TaskRunConcurrencyLimit) => + [ + { + label: "Concurrency Limit Count", + value: data.concurrency_limit, + formatType: "number", + }, + { + label: "Concurrency Limit Active Task Run", + value: data.active_slots?.length ?? "Unknown", + formatType: "number", + }, + { + label: "Concurrency Limit ID", + value: data.id ?? "Unknown", + formatType: "number", + }, + { + label: "Created", + value: data.created + ? format(parseISO(data.created), "yyyy/MM/dd pp") + : "N/A", + formatType: "date", + }, + { + label: "Updated", + value: data.updated + ? format(parseISO(data.updated), "yyyy/MM/dd pp") + : "N/A", + formatType: "date", + }, + ] as const; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/index.ts new file mode 100644 index 000000000000..22debd80a103 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitHeader } from "./task-run-concurrency-limit-header"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/nav-header.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/nav-header.tsx new file mode 100644 index 000000000000..123aba77cf52 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/nav-header.tsx @@ -0,0 +1,31 @@ +import { + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbPage, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { Link } from "@tanstack/react-router"; + +type Props = { + tag: string; +}; + +export const NavHeader = ({ tag }: Props) => { + return ( +
+ + + + Concurrency Limits + + + + {tag} + + + +
+ ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.stories.tsx new file mode 100644 index 000000000000..7e4e34dbd86d --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.stories.tsx @@ -0,0 +1,25 @@ +import { + createFakeTaskRunConcurrencyLimit, + routerDecorator, +} from "@/storybook/utils"; +import type { Meta, StoryObj } from "@storybook/react"; + +import { TaskRunConcurrencyLimitHeader } from "./task-run-concurrency-limit-header"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitHeader", + component: TaskRunConcurrencyLimitHeader, + decorators: [routerDecorator], + args: { + data: createFakeTaskRunConcurrencyLimit(), + onDelete: () => {}, + onReset: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const Story: StoryObj = { + name: "TaskRunConcurrencyLimitHeader", +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.tsx new file mode 100644 index 000000000000..77dfd69bdc7d --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header/task-run-concurrency-limit-header.tsx @@ -0,0 +1,27 @@ +import { TaskRunConcurrencyLimitsActionsMenu } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu"; +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; + +import { NavHeader } from "./nav-header"; + +type Props = { + data: TaskRunConcurrencyLimit; + onDelete: () => void; + onReset: () => void; +}; + +export const TaskRunConcurrencyLimitHeader = ({ + data, + onDelete, + onReset, +}: Props) => { + return ( +
+ + +
+ ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/index.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/index.tsx new file mode 100644 index 000000000000..66c475f0450c --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/index.tsx @@ -0,0 +1,55 @@ +import { TaskRunConcurrencyLimitHeader } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-header"; +import { useGetTaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import { useState } from "react"; + +import { TaskRunConcurrencyLimitActiveTaskRuns } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-active-task-runs"; +import { TaskRunConcurrencyLimitDetails } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-details"; +import { + type Dialogs, + TaskRunConcurrencyLimitDialog, +} from "./task-run-concurrency-limit-dialog"; +import { TaskRunConcurrencyLimitTabNavigation } from "./task-run-concurrency-limit-tab-navigation"; + +type Props = { + id: string; +}; + +export const TaskRunConcurrencyLimitPage = ({ id }: Props) => { + const [openDialog, setOpenDialog] = useState(null); + const { data } = useGetTaskRunConcurrencyLimit(id); + + const handleOpenDeleteDialog = () => setOpenDialog("delete"); + const handleOpenResetDialog = () => setOpenDialog("reset"); + const handleCloseDialog = () => setOpenDialog(null); + + // Because all modals will be rendered, only control the closing logic + const handleOpenChange = (open: boolean) => { + if (!open) { + handleCloseDialog(); + } + }; + + return ( + <> +
+ +
+ } + /> + +
+
+ + + ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-dialog.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-dialog.tsx new file mode 100644 index 000000000000..f64f9d98788b --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-dialog.tsx @@ -0,0 +1,50 @@ +import { TaskRunConcurrencyLimitsDeleteDialog } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog"; +import { TaskRunConcurrencyLimitsResetDialog } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-reset-dialog"; +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import { getRouteApi } from "@tanstack/react-router"; + +export type Dialogs = null | "delete" | "reset"; + +const routeApi = getRouteApi("/concurrency-limits/"); + +type Props = { + data: TaskRunConcurrencyLimit; + openDialog: Dialogs; + onOpenChange: (open: boolean) => void; + onCloseDialog: () => void; +}; + +export const TaskRunConcurrencyLimitDialog = ({ + data, + openDialog, + onCloseDialog, + onOpenChange, +}: Props) => { + const navigate = routeApi.useNavigate(); + + const handleDelete = () => { + onCloseDialog(); + void navigate({ to: "/concurrency-limits", search: { tab: "task-run" } }); + }; + + switch (openDialog) { + case "reset": + return ( + + ); + case "delete": + return ( + + ); + default: + return null; + } +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-tab-navigation.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-tab-navigation.tsx new file mode 100644 index 000000000000..35d5b2ec45f9 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limit-page/task-run-concurrency-limit-tab-navigation.tsx @@ -0,0 +1,55 @@ +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import type { TabOptions } from "@/routes/concurrency-limits/concurrency-limit.$id"; +import { getRouteApi } from "@tanstack/react-router"; + +const routeApi = getRouteApi("/concurrency-limits/concurrency-limit/$id"); + +type TabOptionValues = { + /** Value of search value in url */ + tabSearchValue: TabOptions; + /** Display value for the UI */ + displayValue: string; +}; + +/** Maps url tab option to visual name */ +const TAB_OPTIONS: Record = { + "active-task-runs": { + tabSearchValue: "active-task-runs", + displayValue: "Active Task Runs", + }, +} as const; + +type Props = { + activetaskRunsView: React.ReactNode; +}; + +// TODO: Move Tabs for navigation to a generic styled component +export const TaskRunConcurrencyLimitTabNavigation = ({ + activetaskRunsView, +}: Props) => { + const { tab } = routeApi.useSearch(); + const navigate = routeApi.useNavigate(); + + return ( + + + { + void navigate({ + to: "/concurrency-limits/concurrency-limit/$id", + search: { + tab: TAB_OPTIONS["active-task-runs"].tabSearchValue, + }, + }); + }} + > + {TAB_OPTIONS["active-task-runs"].displayValue} + + + + {activetaskRunsView} + + + ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/index.ts new file mode 100644 index 000000000000..421ea0222e39 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitsActionsMenu } from "./task-run-concurrency-limits-actions-menu"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.stories.tsx new file mode 100644 index 000000000000..4ab5d6d18a2a --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { TaskRunConcurrencyLimitsActionsMenu } from "./task-run-concurrency-limits-actions-menu"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsActionsMenu", + component: TaskRunConcurrencyLimitsActionsMenu, + args: { + id: "0", + onDelete: () => {}, + onReset: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const story: StoryObj = { name: "TaskRunConcurrencyLimitsActionsMenu" }; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.test.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.test.tsx new file mode 100644 index 000000000000..99177c91ad79 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.test.tsx @@ -0,0 +1,80 @@ +import { Toaster } from "@/components/ui/toaster"; + +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; + +import { TaskRunConcurrencyLimitsActionsMenu } from "./task-run-concurrency-limits-actions-menu"; + +describe("TaskRunConcurrencyLimitsActionsMenu", () => { + it("copies the id", async () => { + // ------------ Setup + const user = userEvent.setup(); + render( + <> + + + , + ); + + // ------------ Act + await user.click( + screen.getByRole("button", { name: /open menu/i, hidden: true }), + ); + await user.click(screen.getByRole("menuitem", { name: "Copy ID" })); + + // ------------ Assert + expect(screen.getByText("ID copied")).toBeVisible(); + }); + + it("calls delete option ", async () => { + // ------------ Setup + const user = userEvent.setup(); + const mockOnDeleteFn = vi.fn(); + + render( + , + ); + + // ------------ Act + + await user.click( + screen.getByRole("button", { name: /open menu/i, hidden: true }), + ); + await user.click(screen.getByRole("menuitem", { name: /delete/i })); + + // ------------ Assert + expect(mockOnDeleteFn).toHaveBeenCalledOnce(); + }); + + it("calls reset option ", async () => { + // ------------ Setup + const user = userEvent.setup(); + const mockOnResetFn = vi.fn(); + + render( + , + ); + + // ------------ Act + await user.click( + screen.getByRole("button", { name: /open menu/i, hidden: true }), + ); + await user.click(screen.getByRole("menuitem", { name: /reset/i })); + + // ------------ Assert + expect(mockOnResetFn).toHaveBeenCalledOnce(); + }); +}); diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.tsx new file mode 100644 index 000000000000..b28703254ce6 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu/task-run-concurrency-limits-actions-menu.tsx @@ -0,0 +1,51 @@ +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Icon } from "@/components/ui/icons"; +import { useToast } from "@/hooks/use-toast"; + +type Props = { + id: string | undefined; + onDelete: () => void; + onReset: () => void; +}; + +export const TaskRunConcurrencyLimitsActionsMenu = ({ + id, + onDelete, + onReset, +}: 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" }); + }; + + return ( + + + + + + Actions + handleCopyId(id)}> + Copy ID + + Delete + Reset + + + ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/index.ts new file mode 100644 index 000000000000..7dcd7625e88a --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitsCreateDialog } from "./task-run-concurrency-limits-create-dialog"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.stories.tsx new file mode 100644 index 000000000000..0aabc19a66b2 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.stories.tsx @@ -0,0 +1,20 @@ +import { reactQueryDecorator } from "@/storybook/utils"; +import type { Meta, StoryObj } from "@storybook/react"; +import { TaskRunConcurrencyLimitsCreateDialog } from "./task-run-concurrency-limits-create-dialog"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsCreateDialog", + component: TaskRunConcurrencyLimitsCreateDialog, + decorators: [reactQueryDecorator], + args: { + onOpenChange: () => {}, + onSubmit: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const Story: StoryObj = { + name: "TaskRunConcurrencyLimitsCreateDialog", +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.test.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.test.tsx similarity index 80% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.test.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.test.tsx index 65c17dc3ac09..561e6ba953c5 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.test.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.test.tsx @@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event"; import { createWrapper } from "@tests/utils"; import { beforeAll, describe, expect, it, vi } from "vitest"; -import { CreateLimitDialog } from "./create-dialog"; +import { TaskRunConcurrencyLimitsCreateDialog } from "./task-run-concurrency-limits-create-dialog"; const MOCK_DATA = { id: "0", @@ -14,7 +14,7 @@ const MOCK_DATA = { active_slots: [] as Array, }; -describe("CreateLimitDialog", () => { +describe("TaskRunConcurrencyLimitsCreateDialog", () => { beforeAll(() => { class ResizeObserverMock { observe() {} @@ -29,7 +29,10 @@ describe("CreateLimitDialog", () => { // ------------ Setup const mockOnSubmitFn = vi.fn(); render( - , + , { wrapper: createWrapper() }, ); diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.tsx similarity index 96% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.tsx index 939eefe09d66..602a90ccc018 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/create-dialog.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-create-dialog/task-run-concurrency-limits-create-dialog.tsx @@ -42,7 +42,10 @@ type Props = { onSubmit: () => void; }; -export const CreateLimitDialog = ({ onOpenChange, onSubmit }: Props) => { +export const TaskRunConcurrencyLimitsCreateDialog = ({ + onOpenChange, + onSubmit, +}: Props) => { const { toast } = useToast(); const { createTaskRunConcurrencyLimit, isPending } = diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/active-task-runs-cell.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/active-task-runs-cell.tsx similarity index 72% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/active-task-runs-cell.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/active-task-runs-cell.tsx index ac84b50c854a..a3c625a3605a 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/active-task-runs-cell.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/active-task-runs-cell.tsx @@ -1,5 +1,5 @@ -import { type TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; -import { CellContext } from "@tanstack/react-table"; +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import type { CellContext } from "@tanstack/react-table"; type Props = CellContext>; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/index.ts new file mode 100644 index 000000000000..8bda75061cda --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitsDataTable } from "./task-run-concurrency-limits-data-table"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/tag-cell.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/tag-cell.tsx new file mode 100644 index 000000000000..728799c7d987 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/tag-cell.tsx @@ -0,0 +1,18 @@ +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import { Link } from "@tanstack/react-router"; +import type { CellContext } from "@tanstack/react-table"; + +type Props = CellContext; + +export const TagCell = (props: Props) => { + const tag = props.getValue(); + const id = props.row.original.id; + if (!id) { + throw new Error("Expecting 'id' field"); + } + return ( + + {tag} + + ); +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.stories.tsx new file mode 100644 index 000000000000..af8093f273f7 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.stories.tsx @@ -0,0 +1,33 @@ +import { + createFakeTaskRunConcurrencyLimit, + routerDecorator, +} from "@/storybook/utils"; +import type { Meta, StoryObj } from "@storybook/react"; +import { Table as TaskRunConcurrencyLimitsDataTable } from "./task-run-concurrency-limits-data-table"; + +const MOCK_DATA = [ + createFakeTaskRunConcurrencyLimit(), + createFakeTaskRunConcurrencyLimit(), + createFakeTaskRunConcurrencyLimit(), + createFakeTaskRunConcurrencyLimit(), + createFakeTaskRunConcurrencyLimit(), +]; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsDataTable", + decorators: [routerDecorator], + component: TaskRunConcurrencyLimitsDataTable, + args: { + data: MOCK_DATA, + onDeleteRow: () => {}, + onResetRow: () => {}, + onSearchChange: () => {}, + searchValue: () => {}, + }, +} satisfies Meta; +export default meta; + +export const story: StoryObj = { + name: "TaskRunConcurrencyLimitsDataTable", +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.tsx similarity index 78% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.tsx index 2069baa90ad5..417f42c98e9a 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/data-table/data-table.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-data-table/task-run-concurrency-limits-data-table.tsx @@ -1,5 +1,7 @@ +import { TaskRunConcurrencyLimitsActionsMenu } from "@/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-actions-menu"; import { DataTable } from "@/components/ui/data-table"; -import { type TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; +import { SearchInput } from "@/components/ui/input"; +import type { TaskRunConcurrencyLimit } from "@/hooks/task-run-concurrency-limits"; import { getRouteApi } from "@tanstack/react-router"; import { createColumnHelper, @@ -7,14 +9,12 @@ import { getPaginationRowModel, useReactTable, } from "@tanstack/react-table"; - -import { SearchInput } from "@/components/ui/input"; import { useDeferredValue, useMemo } from "react"; -import { ActionsCell } from "./actions-cell"; -import { ActiveTaskRunCells } from "./active-task-runs-cell"; -const routeApi = getRouteApi("/concurrency-limits"); +import { ActiveTaskRunCells } from "./active-task-runs-cell"; +import { TagCell } from "./tag-cell"; +const routeApi = getRouteApi("/concurrency-limits/"); const columnHelper = createColumnHelper(); const createColumns = ({ @@ -25,7 +25,8 @@ const createColumns = ({ onResetRow: (row: TaskRunConcurrencyLimit) => void; }) => [ columnHelper.accessor("tag", { - header: "Tag", // TODO: Make this a link when starting the tak run concurrency page + header: "Tag", + cell: TagCell, }), columnHelper.accessor("concurrency_limit", { header: "Slots", @@ -36,13 +37,18 @@ const createColumns = ({ }), columnHelper.display({ id: "actions", - cell: (props) => ( - - ), + cell: (props) => { + const row = props.row.original; + return ( +
+ onDeleteRow(row)} + onReset={() => onResetRow(row)} + /> +
+ ); + }, }), ]; @@ -52,7 +58,7 @@ type Props = { onResetRow: (row: TaskRunConcurrencyLimit) => void; }; -export const TaskRunConcurrencyDataTable = ({ +export const TaskRunConcurrencyLimitsDataTable = ({ data, onDeleteRow, onResetRow, @@ -108,6 +114,7 @@ export function Table({ return (
onSearchChange(e.target.value)} diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/index.ts new file mode 100644 index 000000000000..7c8fd19a76c7 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitsDeleteDialog } from "./task-run-concurrency-limits-delete-dialog"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.stories.tsx new file mode 100644 index 000000000000..2fc856b85237 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.stories.tsx @@ -0,0 +1,22 @@ +import { + createFakeTaskRunConcurrencyLimit, + reactQueryDecorator, +} from "@/storybook/utils"; +import type { Meta, StoryObj } from "@storybook/react"; +import { TaskRunConcurrencyLimitsDeleteDialog } from "./task-run-concurrency-limits-delete-dialog"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsDeleteDialog", + component: TaskRunConcurrencyLimitsDeleteDialog, + decorators: [reactQueryDecorator], + args: { + data: createFakeTaskRunConcurrencyLimit(), + onOpenChange: () => {}, + onDelete: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const story: StoryObj = { name: "TaskRunConcurrencyLimitsDeleteDialog" }; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/delete-dialog.test.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.test.tsx similarity index 78% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/delete-dialog.test.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.test.tsx index 2eae080d669e..db0fad431cef 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/dialogs/delete-dialog.test.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-delete-dialog/task-run-concurrency-limits-delete-dialog.test.tsx @@ -1,4 +1,4 @@ -import { DeleteLimitDialog } from "./delete-dialog"; +import { TaskRunConcurrencyLimitsDeleteDialog } from "./task-run-concurrency-limits-delete-dialog"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; @@ -14,13 +14,13 @@ const MOCK_DATA = { active_slots: [] as Array, }; -test("DeleteLimitDialog can successfully call delete", async () => { +test("TaskRunConcurrencyLimitsDeleteDialog can successfully call delete", async () => { const user = userEvent.setup(); // ------------ Setup const mockOnDeleteFn = vi.fn(); render( - void; }; -export const DeleteLimitDialog = ({ data, onOpenChange, onDelete }: Props) => { +export const TaskRunConcurrencyLimitsDeleteDialog = ({ + data, + onOpenChange, + onDelete, +}: Props) => { const { toast } = useToast(); const { deleteTaskRunConcurrencyLimit, isPending } = useDeleteTaskRunConcurrencyLimit(); diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/index.ts new file mode 100644 index 000000000000..973817e69e15 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/index.ts @@ -0,0 +1 @@ +export { TaskRunConcurrencyLimitsEmptyState } from "./task-run-concurrency-limits-empty-state"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.stories.tsx new file mode 100644 index 000000000000..159b4648a963 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { TaskRunConcurrencyLimitsEmptyState } from "./task-run-concurrency-limits-empty-state"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsEmptyState", + component: TaskRunConcurrencyLimitsEmptyState, + args: { + onAdd: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const Story: StoryObj = { + name: "TaskRunConcurrencyLimitsEmptyState", +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.test.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.test.tsx similarity index 67% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.test.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.test.tsx index d3bbdf8127aa..8dd08e0d3fd3 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.test.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.test.tsx @@ -1,15 +1,15 @@ import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi } from "vitest"; -import { TaskRunConcurrencyLimitEmptyState } from "./task-run-concurrency-limit-empty-state"; +import { TaskRunConcurrencyLimitsEmptyState } from "./task-run-concurrency-limits-empty-state"; -describe("TaskRunConcurrencyLimitEmptyState", () => { +describe("TaskRunConcurrencyLimitsEmptyState", () => { it("when adding task run concurrency limit, callback gets fired", async () => { const user = userEvent.setup(); const mockFn = vi.fn(); - render(); + render(); await user.click( screen.getByRole("button", { name: /Add Concurrency Limit/i }), ); diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.tsx similarity index 92% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.tsx index f89e28bdd934..d73b16d27237 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/empty-state/task-run-concurrency-limit-empty-state.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-empty-state/task-run-concurrency-limits-empty-state.tsx @@ -12,7 +12,7 @@ import { Icon } from "@/components/ui/icons"; type Props = { onAdd: () => void; }; -export const TaskRunConcurrencyLimitEmptyState = ({ onAdd }: Props) => ( +export const TaskRunConcurrencyLimitsEmptyState = ({ onAdd }: Props) => ( diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/header/index.ts b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/index.ts similarity index 73% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/header/index.ts rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/index.ts index 5c98b17a6b83..1fc7d88eacb6 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/header/index.ts +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/index.ts @@ -1 +1 @@ -export { TaskRunConcurrencyLimitsHeader } from "./task-run-concurrency-limit-header"; +export { TaskRunConcurrencyLimitsHeader } from "./task-run-concurrency-limits-header"; diff --git a/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.stories.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.stories.tsx new file mode 100644 index 000000000000..8c561837e8e0 --- /dev/null +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { TaskRunConcurrencyLimitsHeader } from "./task-run-concurrency-limits-header"; + +const meta = { + title: + "Components/Concurrency/TaskRunConcurrencyLimits/TaskRunConcurrencyLimitsHeader", + component: TaskRunConcurrencyLimitsHeader, + args: { + onAdd: () => {}, + }, +} satisfies Meta; + +export default meta; + +export const Story: StoryObj = { + name: "TaskRunConcurrencyLimitsHeader", +}; diff --git a/ui-v2/src/components/concurrency/task-run-concurrenct-view/header/task-run-concurrency-limit-header.tsx b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.tsx similarity index 92% rename from ui-v2/src/components/concurrency/task-run-concurrenct-view/header/task-run-concurrency-limit-header.tsx rename to ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.tsx index ba5c1d9f64ce..c04f4173074d 100644 --- a/ui-v2/src/components/concurrency/task-run-concurrenct-view/header/task-run-concurrency-limit-header.tsx +++ b/ui-v2/src/components/concurrency/task-run-concurrency-limits/task-run-concurrency-limits-header/task-run-concurrency-limits-header.tsx @@ -13,6 +13,8 @@ export const TaskRunConcurrencyLimitsHeader = ({ onAdd }: Props) => {