Skip to content

Commit

Permalink
[UI v2] feat: Adds Runs list to deployment runs tab
Browse files Browse the repository at this point in the history
  • Loading branch information
devinvillarosa committed Feb 22, 2025
1 parent 1881252 commit 5167332
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 23 deletions.
231 changes: 229 additions & 2 deletions ui-v2/src/components/deployments/deployment-details-runs-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { Deployment } from "@/api/deployments";
import { useFilterFlowRunswithFlows } from "@/api/flow-runs/use-filter-flow-runs-with-flows";
import { usePaginateFlowRunswithFlows } from "@/api/flow-runs/use-paginate-flow-runs-with-flows";
import { FlowRunCard } from "@/components/flow-runs/flow-run-card";
import {
FlowRunState,
FlowRunsFilters,
FlowRunsList,
FlowRunsPagination,
FlowRunsRowCount,
PaginationState,
SortFilters,
useFlowRunsSelectedRows,
} from "@/components/flow-runs/flow-runs-list";
import { Typography } from "@/components/ui/typography";
import { useMemo } from "react";
import { getRouteApi } from "@tanstack/react-router";
import { useCallback, useMemo } from "react";
import { FLOW_RUN_STATES_NO_SCHEDULED } from "../flow-runs/flow-runs-list/flow-runs-filters/state-filters.constants";

const routeApi = getRouteApi("/deployments/deployment/$id");

type DeploymentDetailsRunsTabProps = {
deployment: Deployment;
Expand All @@ -11,16 +26,92 @@ type DeploymentDetailsRunsTabProps = {
export const DeploymentDetailsRunsTab = ({
deployment,
}: DeploymentDetailsRunsTabProps) => {
const [selectedRows, setSelectedRows, { clearSet, onSelectRow }] =
useFlowRunsSelectedRows();
const [pagination, onChangePagination] = usePagination();
const [search, setSearch] = useSearch();
const [sort, setSort] = useSort();
const [filter, setFilter] = useFilter();
const resetFilters = useResetFilters();

const { data } = usePaginateFlowRunswithFlows({
deployments: {
operator: "and_",
id: { any_: [deployment.id] },
},
flow_runs: {
name: { like_: search || undefined },
state: {
name: { any_: filter.length === 0 ? undefined : filter },
operator: "or_",
},
operator: "and_",
},
limit: pagination.limit,
page: pagination.page,
sort,
});

const dataWithDeployment = useMemo(() => {
if (!data) {
return undefined;
}
return {
...data,
results: data.results.map((flowRun) => ({ ...flowRun, deployment })),
};
}, [data, deployment]);

const handleResetFilters = !resetFilters
? undefined
: () => {
resetFilters();
clearSet();
};

const nextRun = useGetNextRun(deployment);

return (
<div className="flex flex-col">
<div className="flex flex-col gap-2">
{nextRun && (
<div className="flex flex-col gap-2 border-b py-2">
<Typography variant="bodyLarge">Next Run</Typography>
<FlowRunCard flowRun={nextRun} />
</div>
)}
<div className="flex flex-col gap-2">
<div className="flex items-center justify-between">
<FlowRunsRowCount
count={dataWithDeployment?.count}
results={dataWithDeployment?.results}
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
/>
<FlowRunsFilters
search={{ value: search, onChange: setSearch }}
sort={{ value: sort, onSelect: setSort }}
stateFilter={{
value: new Set(filter),
onSelect: setFilter,
}}
/>
</div>
<FlowRunsList
flowRuns={dataWithDeployment?.results}
selectedRows={selectedRows}
onSelect={onSelectRow}
onClearFilters={handleResetFilters}
/>

{dataWithDeployment && dataWithDeployment.results.length > 0 && (
<FlowRunsPagination
count={dataWithDeployment.count}
pagination={pagination}
onChangePagination={onChangePagination}
pages={dataWithDeployment.pages}
/>
)}
</div>
</div>
);
};
Expand All @@ -47,3 +138,139 @@ function useGetNextRun(deployment: Deployment) {
};
}, [data, deployment]);
}

function useResetFilters() {
const { runs } = routeApi.useSearch();
const navigate = routeApi.useNavigate();
const resetFilters = useCallback(() => {
void navigate({
to: ".",
search: (prev) => ({
...prev,
runs: undefined,
}),
replace: true,
});
}, [navigate]);
const hasFiltersApplied = useMemo(() => Boolean(runs), [runs]);

return hasFiltersApplied ? resetFilters : undefined;
}

function usePagination() {
const { runs } = routeApi.useSearch();
const navigate = routeApi.useNavigate();

const onChangePagination = useCallback(
(pagination?: PaginationState) => {
void navigate({
to: ".",
search: (prev) => ({
...prev,
runs: {
...runs,
...pagination,
},
}),
replace: true,
});
},
[navigate, runs],
);

const pagination = useMemo(() => {
return {
page: runs?.page ?? 1,
limit: runs?.limit ?? 10,
};
}, [runs?.limit, runs?.page]);

return [pagination, onChangePagination] as const;
}

function useSearch() {
const { runs } = routeApi.useSearch();
const navigate = routeApi.useNavigate();

const onSearch = useCallback(
(value?: string) => {
void navigate({
to: ".",
search: (prev) => ({
...prev,
runs: {
...runs,
flowRuns: {
...runs?.flowRuns,
name: value,
},
},
}),
replace: true,
});
},
[navigate, runs],
);
const search = useMemo(
() => runs?.flowRuns?.name ?? "",
[runs?.flowRuns?.name],
);
return [search, onSearch] as const;
}

function useSort() {
const { runs } = routeApi.useSearch();
const navigate = routeApi.useNavigate();

const onSort = useCallback(
(value?: SortFilters) => {
void navigate({
to: ".",
search: (prev) => ({
...prev,
runs: {
...runs,
sort: value,
},
}),
replace: true,
});
},
[navigate, runs],
);
const sort = useMemo(() => runs?.sort ?? "START_TIME_DESC", [runs?.sort]);
return [sort, onSort] as const;
}

function useFilter() {
const { runs } = routeApi.useSearch();
const navigate = routeApi.useNavigate();

const onFilter = useCallback(
(value?: Set<FlowRunState>) => {
void navigate({
to: ".",
search: (prev) => ({
...prev,
runs: {
...runs,
flowRuns: {
...runs?.flowRuns,
state: value ? Array.from(value) : undefined,
},
},
}),
replace: true,
});
},
[navigate, runs],
);

const filter = useMemo(
() =>
runs?.flowRuns?.state ??
(FLOW_RUN_STATES_NO_SCHEDULED satisfies Array<FlowRunState>),
[runs?.flowRuns?.state],
);
return [filter, onFilter] as const;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {
FlowRunsRowCount,
type PaginationState,
SortFilters,
useFlowRunsSelectedRows,
} from "@/components/flow-runs/flow-runs-list";
import { useCallback, useMemo, useState } from "react";
import { useCallback, useMemo } from "react";

const routeApi = getRouteApi("/deployments/deployment/$id");

Expand All @@ -22,7 +23,8 @@ type DeploymentDetailsUpcomingTabProps = {
export const DeploymentDetailsUpcomingTab = ({
deployment,
}: DeploymentDetailsUpcomingTabProps) => {
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());
const [selectedRows, setSelectedRows, { clearSet, onSelectRow }] =
useFlowRunsSelectedRows();
const [pagination, onChangePagination] = usePagination();
const [search, setSearch] = useSearch();
const [sort, setSort] = useSort();
Expand Down Expand Up @@ -57,28 +59,11 @@ export const DeploymentDetailsUpcomingTab = ({
};
}, [data, deployment]);

const addRow = (id: string) =>
setSelectedRows((curr) => new Set(curr).add(id));
const removeRow = (id: string) =>
setSelectedRows((curr) => {
const newValue = new Set(curr);
newValue.delete(id);
return newValue;
});

const handleSelectRow = (id: string, checked: boolean) => {
if (checked) {
addRow(id);
} else {
removeRow(id);
}
};

const handleResetFilters = !resetFilters
? undefined
: () => {
resetFilters();
setSelectedRows(new Set());
clearSet();
};

return (
Expand All @@ -103,7 +88,7 @@ export const DeploymentDetailsUpcomingTab = ({
<FlowRunsList
flowRuns={dataWithDeployment?.results}
selectedRows={selectedRows}
onSelect={handleSelectRow}
onSelect={onSelectRow}
onClearFilters={handleResetFilters}
/>

Expand Down
1 change: 1 addition & 0 deletions ui-v2/src/components/flow-runs/flow-runs-list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export {
SORT_FILTERS,
type SortFilters,
} from "./flow-runs-filters/sort-filter.constants";
export { useFlowRunsSelectedRows } from "./use-flow-runs-selected-rows";
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useState } from "react";

export const useFlowRunsSelectedRows = () => {
const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());

const addRow = (id: string) =>
setSelectedRows((curr) => new Set(curr).add(id));

const removeRow = (id: string) =>
setSelectedRows((curr) => {
const newValue = new Set(curr);
newValue.delete(id);
return newValue;
});

const onSelectRow = (id: string, checked: boolean) => {
if (checked) {
addRow(id);
} else {
removeRow(id);
}
};

const clearSet = () => setSelectedRows(new Set());

const utils = {
addRow,
removeRow,
onSelectRow,
clearSet,
};

return [selectedRows, setSelectedRows, utils] as const;
};
22 changes: 22 additions & 0 deletions ui-v2/src/routes/deployments/deployment.$id.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
FLOW_RUN_STATES,
SORT_FILTERS,
} from "@/components/flow-runs/flow-runs-list";
import { FLOW_RUN_STATES_NO_SCHEDULED } from "@/components/flow-runs/flow-runs-list/flow-runs-filters/state-filters.constants";
import { createFileRoute } from "@tanstack/react-router";
import { zodValidator } from "@tanstack/zod-adapter";
import { z } from "zod";
Expand All @@ -18,6 +19,27 @@ const searchParams = z.object({
tab: z
.enum(["Runs", "Upcoming", "Parameters", "Configuration", "Description"])
.default("Runs"),
runs: z
.object({
flowRuns: z
.object({
name: z.string().optional(),
state: z
.array(z.enum(FLOW_RUN_STATES))
.optional()
.default(FLOW_RUN_STATES_NO_SCHEDULED)
.catch(FLOW_RUN_STATES_NO_SCHEDULED),
})
.optional(),
page: z.number().int().positive().optional().default(1).catch(1),
limit: z.number().int().positive().optional().default(10).catch(10),
sort: z
.enum(SORT_FILTERS)
.optional()
.default("START_TIME_DESC")
.catch("START_TIME_DESC"),
})
.optional(),
upcoming: z
.object({
flowRuns: z
Expand Down

0 comments on commit 5167332

Please sign in to comment.