Skip to content

Commit 2d918a5

Browse files
committed
bulk select for runs & runs tab
1 parent 0e72a8e commit 2d918a5

14 files changed

+82
-118
lines changed

src/app/components/[componentId]/page.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { StackComponentsDetailHeader } from "../../../components/stack-component
33
import { StackComponentTabs } from "@/components/stack-components/component-detail/Tabs";
44
import { StackList } from "../../stacks/StackList";
55
import { RunsBody } from "../../pipelines/RunsTab/RunsBody";
6-
import { RunsSelectorProvider } from "../../pipelines/RunsTab/RunsSelectorContext";
6+
import { RunsDataTableContextProvider } from "../../pipelines/RunsTab/RunsDataTableContext";
77

88
export default function ComponentDetailPage() {
99
const { componentId } = useParams() as { componentId: string };
@@ -15,9 +15,9 @@ export default function ComponentDetailPage() {
1515
isPanel={false}
1616
stacksTabContent={<StackList fixedQueryParams={{ component_id: componentId }} />}
1717
runsTabContent={
18-
<RunsSelectorProvider>
18+
<RunsDataTableContextProvider>
1919
<RunsBody fixedQueryParams={{ stack_component: componentId }} />
20-
</RunsSelectorProvider>
20+
</RunsDataTableContextProvider>
2121
}
2222
componentId={componentId}
2323
/>

src/app/pipelines/RunsTab/ButtonGroup.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { DeleteRunAlert } from "./DeleteRunAlert";
2-
import { useRunsSelectorContext } from "./RunsSelectorContext";
2+
import { useRunsDataTableContext } from "./RunsDataTableContext";
33

44
export function RunsButtonGroup() {
5-
const { selectedRuns } = useRunsSelectorContext();
5+
const { selectedRowCount } = useRunsDataTableContext();
66
return (
77
<div className="flex items-center divide-x divide-theme-border-moderate overflow-hidden rounded-md border border-theme-border-moderate">
8-
<div className="bg-primary-25 px-2 py-1 font-semibold text-theme-text-brand">{`${selectedRuns?.length} Run${selectedRuns?.length > 1 ? "s" : ""} selected`}</div>
8+
<div className="bg-primary-25 px-2 py-1 font-semibold text-theme-text-brand">{`${selectedRowCount} Run${selectedRowCount > 1 ? "s" : ""} selected`}</div>
99
<DeleteRunAlert />
1010
</div>
1111
);

src/app/pipelines/RunsTab/DeleteRunAlert.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import Trash from "@/assets/icons/trash.svg?react";
22
import { DeleteAlertContent, DeleteAlertContentBody } from "@/components/DeleteAlertDialog";
33
import { AlertDialog, AlertDialogTrigger, Button } from "@zenml-io/react-component-library";
44
import { useState } from "react";
5-
import { useRunsSelectorContext } from "./RunsSelectorContext";
5+
import { useRunsDataTableContext } from "./RunsDataTableContext";
6+
import { useBulkDeleteRuns } from "./bulk";
67

78
export function DeleteRunAlert() {
89
const [isOpen, setIsOpen] = useState(false);
9-
const { bulkDeleteRuns, selectedRuns } = useRunsSelectorContext();
10+
const { selectedRowIDs } = useRunsDataTableContext();
11+
const { bulkDelete } = useBulkDeleteRuns();
1012

1113
async function handleDelete() {
12-
await bulkDeleteRuns(selectedRuns);
14+
await bulkDelete(selectedRowIDs);
1315
setIsOpen(false);
1416
}
1517

@@ -27,7 +29,7 @@ export function DeleteRunAlert() {
2729
</Button>
2830
</AlertDialogTrigger>
2931
<DeleteAlertContent
30-
title={`Delete Run${selectedRuns.length >= 2 ? "s" : ""}`}
32+
title={`Delete Run${selectedRowIDs.length >= 2 ? "s" : ""}`}
3133
handleDelete={handleDelete}
3234
>
3335
<DeleteAlertContentBody>

src/app/pipelines/RunsTab/RunDropdown.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
DropdownMenuTrigger
1010
} from "@zenml-io/react-component-library";
1111
import { ElementRef, useRef, useState } from "react";
12-
import { useRunsSelectorContext } from "./RunsSelectorContext";
12+
import { useBulkDeleteRuns } from "./bulk";
1313

1414
type Props = {
1515
id: string;
@@ -21,10 +21,10 @@ export function RunDropdown({ id }: Props) {
2121
const dropdownTriggerRef = useRef<ElementRef<typeof AlertDialogTrigger> | null>(null);
2222
const focusRef = useRef<HTMLElement | null>(null);
2323

24-
const { bulkDeleteRuns } = useRunsSelectorContext();
24+
const { bulkDelete } = useBulkDeleteRuns();
2525

2626
async function handleDelete() {
27-
await bulkDeleteRuns([id]);
27+
await bulkDelete([id]);
2828
handleDialogItemOpenChange(false);
2929
}
3030

src/app/pipelines/RunsTab/RunSelector.tsx

-27
This file was deleted.

src/app/pipelines/RunsTab/RunsBody.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ import { PipelineRunOvervieweParams } from "@/types/pipeline-runs";
66
import { Button, DataTable, Skeleton } from "@zenml-io/react-component-library";
77
import { RunsButtonGroup } from "./ButtonGroup";
88
import { runsColumns } from "./columns";
9-
import { useRunsSelectorContext } from "./RunsSelectorContext";
9+
import { useRunsDataTableContext } from "./RunsDataTableContext";
1010
import { useRunsOverviewSearchParams } from "./service";
1111

1212
type Props = {
1313
fixedQueryParams?: PipelineRunOvervieweParams;
1414
};
1515

1616
export function RunsBody({ fixedQueryParams = {} }: Props) {
17-
const { selectedRuns } = useRunsSelectorContext();
17+
const { selectedRowIDs } = useRunsDataTableContext();
1818
const queryParams = useRunsOverviewSearchParams();
1919
const { data, refetch } = useAllPipelineRuns({
2020
params: {
@@ -27,7 +27,7 @@ export function RunsBody({ fixedQueryParams = {} }: Props) {
2727
return (
2828
<div className="mt-5 flex flex-col gap-5">
2929
<div className="flex items-center justify-between">
30-
{selectedRuns.length ? <RunsButtonGroup /> : <SearchField searchParams={queryParams} />}
30+
{selectedRowIDs.length ? <RunsButtonGroup /> : <SearchField searchParams={queryParams} />}
3131
<div className="flex justify-between">
3232
<Button intent="primary" emphasis="subtle" size="md" onClick={() => refetch()}>
3333
<Refresh className="h-5 w-5 fill-theme-text-brand" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createDataTableConsumerContext } from "@/components/table/DataTableConsumerContext";
2+
3+
export const {
4+
Context: RunsDataTableContext,
5+
ContextProvider: RunsDataTableContextProvider,
6+
useContext: useRunsDataTableContext
7+
} = createDataTableConsumerContext();

src/app/pipelines/RunsTab/RunsSelectorContext.tsx

-53
This file was deleted.

src/app/pipelines/RunsTab/bulk.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createUseBulkDelete } from "@/lib/bulk-delete";
2+
import { useDeleteRun } from "@/data/pipeline-runs/delete-run";
3+
import { pipelineQueries } from "@/data/pipelines";
4+
import { useRunsDataTableContext } from "./RunsDataTableContext";
5+
6+
export const useBulkDeleteRuns = createUseBulkDelete({
7+
useMutation: useDeleteRun,
8+
useQueryKeys: () => pipelineQueries,
9+
useDataTableContext: useRunsDataTableContext,
10+
getParams: (runId) => ({ runId })
11+
});

src/app/pipelines/RunsTab/columns.tsx

+19-7
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,38 @@ import { Stack } from "@/types/stack";
99
import { ColumnDef } from "@tanstack/react-table";
1010
import { Tag } from "@zenml-io/react-component-library";
1111
import {
12+
Checkbox,
1213
Tooltip,
1314
TooltipContent,
1415
TooltipProvider,
1516
TooltipTrigger
16-
} from "@zenml-io/react-component-library/components/client";
17+
} from "@zenml-io/react-component-library";
1718
import { Link } from "react-router-dom";
1819
import { RunDropdown } from "./RunDropdown";
19-
import { RunSelector } from "./RunSelector";
2020

2121
export const runsColumns: ColumnDef<PipelineRun>[] = [
2222
{
2323
id: "check",
24-
header: "",
24+
header: ({ table }) => (
25+
<Checkbox
26+
id="check-all"
27+
checked={table.getIsAllRowsSelected()}
28+
onCheckedChange={(state) =>
29+
table.toggleAllRowsSelected(state === "indeterminate" ? true : state)
30+
}
31+
/>
32+
),
2533
meta: {
2634
width: "1%"
2735
},
28-
accessorFn: (row) => ({ id: row.id }),
29-
cell: ({ getValue }) => {
30-
const { id } = getValue<{ id: string }>();
31-
return <RunSelector id={id} />;
36+
cell: ({ row }) => {
37+
return (
38+
<Checkbox
39+
id={`check-${row.id}`}
40+
checked={row.getIsSelected()}
41+
onCheckedChange={row.getToggleSelectedHandler()}
42+
/>
43+
);
3244
}
3345
},
3446
{

src/app/pipelines/Tabs.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { useNavigate, useSearchParams } from "react-router-dom";
77
import { PipelinesBody } from "./PipelinesTab/PipelinesBody";
88
import { PipelineDataTableContextProvider } from "./PipelinesTab/PipelineSelectorContext";
99
import { RunsBody } from "./RunsTab/RunsBody";
10-
import { RunsSelectorProvider } from "./RunsTab/RunsSelectorContext";
1110
import { useSelectedTab } from "./service";
1211
import { TemplateBody } from "./Templates/TemplateBody";
12+
import { RunsDataTableContextProvider } from "./RunsTab/RunsDataTableContext";
1313

1414
const tabData = [
1515
{
@@ -85,9 +85,9 @@ export function PipelineTabs() {
8585
</TabsContent>
8686

8787
<TabsContent className="m-0 mt-5 border-0 bg-transparent p-0" value="runs">
88-
<RunsSelectorProvider>
88+
<RunsDataTableContextProvider>
8989
<RunsBody />
90-
</RunsSelectorProvider>
90+
</RunsDataTableContextProvider>
9191
</TabsContent>
9292
<TabsContent className="m-0 mt-5 border-0 bg-transparent p-0" value="templates">
9393
<TemplateBody />

src/app/pipelines/[namespace]/RunsTable.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import { useAllPipelineRuns } from "@/data/pipeline-runs/all-pipeline-runs-query
66
import { SearchField } from "@/components/SearchField";
77
import Pagination from "@/components/Pagination";
88
import { getPipelineDetailColumns } from "./columns";
9-
import { useRunsSelectorContext } from "../RunsTab/RunsSelectorContext";
109
import { RunsButtonGroup } from "../RunsTab/ButtonGroup";
10+
import { useRunsDataTableContext } from "../RunsTab/RunsDataTableContext";
1111

1212
export function PipelineRunsTable() {
1313
const { namespace } = useParams() as { namespace: string };
1414
const params = usePipelineRunParams();
1515
const cols = getPipelineDetailColumns();
16-
const { selectedRuns } = useRunsSelectorContext();
16+
const { selectedRowIDs } = useRunsDataTableContext();
1717

1818
const { data, refetch } = useAllPipelineRuns(
1919
{
@@ -29,7 +29,7 @@ export function PipelineRunsTable() {
2929
return (
3030
<div className="flex flex-col gap-5 p-5">
3131
<div className="flex items-center justify-between">
32-
{selectedRuns.length ? <RunsButtonGroup /> : <SearchField searchParams={params} />}
32+
{selectedRowIDs.length ? <RunsButtonGroup /> : <SearchField searchParams={params} />}
3333
<Button intent="primary" emphasis="subtle" size="md" onClick={() => refetch()}>
3434
<Refresh className="h-5 w-5 fill-theme-text-brand" />
3535
Refresh

src/app/pipelines/[namespace]/columns.tsx

+18-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Stack } from "@/types/stack";
1010
import { User } from "@/types/user";
1111
import { ColumnDef } from "@tanstack/react-table";
1212
import {
13+
Checkbox,
1314
Tag,
1415
Tooltip,
1516
TooltipContent,
@@ -18,20 +19,31 @@ import {
1819
} from "@zenml-io/react-component-library";
1920
import { Link } from "react-router-dom";
2021
import { RunDropdown } from "../RunsTab/RunDropdown";
21-
import { RunSelector } from "../RunsTab/RunSelector";
2222

2323
export function getPipelineDetailColumns(): ColumnDef<PipelineRun>[] {
2424
return [
2525
{
2626
id: "check",
27-
header: "",
27+
header: ({ table }) => (
28+
<Checkbox
29+
id="check-all"
30+
checked={table.getIsAllRowsSelected()}
31+
onCheckedChange={(state) =>
32+
table.toggleAllRowsSelected(state === "indeterminate" ? true : state)
33+
}
34+
/>
35+
),
2836
meta: {
2937
width: "1%"
3038
},
31-
accessorFn: (row) => ({ id: row.id }),
32-
cell: ({ getValue }) => {
33-
const { id } = getValue<{ id: string }>();
34-
return <RunSelector id={id} />;
39+
cell: ({ row }) => {
40+
return (
41+
<Checkbox
42+
id={`check-${row.id}`}
43+
checked={row.getIsSelected()}
44+
onCheckedChange={row.getToggleSelectedHandler()}
45+
/>
46+
);
3547
}
3648
},
3749
{

src/app/pipelines/[namespace]/page.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Header } from "./Header";
33
import { PipelineRunsTable } from "./RunsTable";
44
import { useEffect } from "react";
55
import { useBreadcrumbsContext } from "@/layouts/AuthenticatedLayout/BreadcrumbsContext";
6-
import { RunsSelectorProvider } from "../RunsTab/RunsSelectorContext";
6+
import { RunsDataTableContextProvider } from "../RunsTab/RunsDataTableContext";
77

88
export default function PipelineNamespacePage() {
99
const { namespace } = useParams() as { namespace: string };
@@ -19,10 +19,10 @@ export default function PipelineNamespacePage() {
1919

2020
return (
2121
<div>
22-
<RunsSelectorProvider>
22+
<RunsDataTableContextProvider>
2323
<Header namespace={namespace} />
2424
<PipelineRunsTable />
25-
</RunsSelectorProvider>
25+
</RunsDataTableContextProvider>
2626
</div>
2727
);
2828
}

0 commit comments

Comments
 (0)