Skip to content

Commit

Permalink
[UI v2] feat: Loads data and url state to concurrency limit route for…
Browse files Browse the repository at this point in the history
… UX to consume
  • Loading branch information
devinvillarosa committed Dec 6, 2024
1 parent 9ff7d0b commit 35d8240
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 40 deletions.
5 changes: 0 additions & 5 deletions ui-v2/src/components/concurrency/concurrency-constants.ts

This file was deleted.

10 changes: 1 addition & 9 deletions ui-v2/src/components/concurrency/concurrency-page.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { useState } from "react";
import { Typography } from "@/components/ui/typography";

import { Typography } from "@/components//ui/typography";

import { TAB_OPTIONS, TabOptions } from "./concurrency-constants";
import { ConcurrencyTabs } from "./concurrency-tabs";
import { GlobalConcurrencyView } from "./global-concurrency-view";
import { TaskRunConcurrencyView } from "./task-run-concurrenct-view";

export const ConcurrencyPage = (): JSX.Element => {
// TODO: Use URL query instead
const [tab, setTab] = useState<TabOptions>(TAB_OPTIONS.Global);

return (
<div className="flex flex-col gap-4">
<Typography variant="h2">Concurrency</Typography>
<div className="flex flex-col gap-6">
<ConcurrencyTabs
value={tab}
onValueChange={setTab}
globalView={<GlobalConcurrencyView />}
taskRunView={<TaskRunConcurrencyView />}
/>
Expand Down
77 changes: 62 additions & 15 deletions ui-v2/src/components/concurrency/concurrency-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,81 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { TAB_OPTIONS, TabOptions } from "./concurrency-constants";
import { TabOptions } from "@/routes/concurrency-limits";
import { getRouteApi } from "@tanstack/react-router";

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

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<TabOptions, TabOptionValues> = {
global: {
tabSearchValue: "global",
displayValue: "Global",
},
["task-run"]: {
tabSearchValue: "task-run",
displayValue: "Task Run",
},
} as const;

type Props = {
globalView: React.ReactNode;
onValueChange: (value: TabOptions) => void;
taskRunView: React.ReactNode;
value: TabOptions;
};

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

export const ConcurrencyTabs = ({
globalView,
onValueChange,
taskRunView,
value,
}: Props): JSX.Element => {
const { tab } = routeApi.useSearch();
const navigate = routeApi.useNavigate();

return (
<Tabs
defaultValue="Global"
className="w-[400px]"
value={value}
onValueChange={(value) => onValueChange(value as TabOptions)}
>
<Tabs defaultValue="Global" value={tab}>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="Global">{TAB_OPTIONS.Global}</TabsTrigger>
<TabsTrigger value="Task Run">{TAB_OPTIONS["Task Run"]}</TabsTrigger>
<TabsTrigger
value={TAB_OPTIONS.global.tabSearchValue}
onClick={() => {
void navigate({
to: "/concurrency-limits",
search: (prev) => ({
...prev,
tab: TAB_OPTIONS.global.tabSearchValue,
}),
});
}}
>
{TAB_OPTIONS.global.displayValue}
</TabsTrigger>

<TabsTrigger
value={TAB_OPTIONS["task-run"].tabSearchValue}
onClick={() => {
void navigate({
to: "/concurrency-limits",
search: (prev) => ({
...prev,
tab: TAB_OPTIONS["task-run"].tabSearchValue,
}),
});
}}
>
{TAB_OPTIONS["task-run"].displayValue}
</TabsTrigger>
</TabsList>
<TabsContent value={TAB_OPTIONS.Global}>{globalView}</TabsContent>
<TabsContent value={TAB_OPTIONS["Task Run"]}>{taskRunView}</TabsContent>
<TabsContent value={TAB_OPTIONS.global.tabSearchValue}>
{globalView}
</TabsContent>
<TabsContent value={TAB_OPTIONS["task-run"].tabSearchValue}>
{taskRunView}
</TabsContent>
</Tabs>
);
};
10 changes: 10 additions & 0 deletions ui-v2/src/components/concurrency/global-concurrency-view/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useListGlobalConcurrencyLimits } from "@/hooks/global-concurrency-limits";
import { useState } from "react";

import { GlobalConcurrencyLimitsHeader } from "./global-concurrency-limits-header";

export const GlobalConcurrencyView = () => {
const [showAddDialog, setShowAddDialog] = useState(false);

const { data } = useListGlobalConcurrencyLimits();

const openAddDialog = () => setShowAddDialog(true);
const closeAddDialog = () => setShowAddDialog(false);

Expand All @@ -12,6 +16,12 @@ export const GlobalConcurrencyView = () => {
<div className="flex flex-col gap-2">
<GlobalConcurrencyLimitsHeader onAdd={openAddDialog} />
</div>
<div>TODO</div>
<ul>
{data.map((limit) => (
<li key={limit.id}>{JSON.stringify(limit)}</li>
))}
</ul>
{showAddDialog && <div onClick={closeAddDialog}>TODO: DIALOG</div>}
</>
);
Expand Down
19 changes: 14 additions & 5 deletions ui-v2/src/hooks/global-concurrency-limits.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { components } from "@/api/prefect";
import { getQueryService } from "@/api/service";
import {
QueryClient,
queryOptions,
useMutation,
useQuery,
useQueryClient,
useSuspenseQuery,
} from "@tanstack/react-query";

export type GlobalConcurrencyLimit =
Expand All @@ -31,7 +32,7 @@ export const queryKeyFactory = {
// ----- 🔑 Queries 🗄️
// ----------------------------
export const buildListGlobalConcurrencyLimitsQuery = (
filter: GlobalConcurrencyLimitsFilter,
filter: GlobalConcurrencyLimitsFilter = { offset: 0 },
) =>
queryOptions({
queryKey: queryKeyFactory.list(filter),
Expand All @@ -47,11 +48,19 @@ export const buildListGlobalConcurrencyLimitsQuery = (
/**
*
* @param filter
* @returns list of global concurrency limits as a QueryResult object
* @returns list of global concurrency limits as a SuspenseQueryResult object
*/

export const useListGlobalConcurrencyLimits = (
filter: GlobalConcurrencyLimitsFilter,
) => useQuery(buildListGlobalConcurrencyLimitsQuery(filter));
filter: GlobalConcurrencyLimitsFilter = { offset: 0 },
) => useSuspenseQuery(buildListGlobalConcurrencyLimitsQuery(filter));

useListGlobalConcurrencyLimits.loader = ({
context,
}: {
context: { queryClient: QueryClient };
}) =>
context.queryClient.ensureQueryData(buildListGlobalConcurrencyLimitsQuery());

// ----- ✍🏼 Mutations 🗄️
// ----------------------------
Expand Down
25 changes: 19 additions & 6 deletions ui-v2/src/routes/concurrency-limits.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { ConcurrencyPage } from "@/components/concurrency/concurrency-page";
import { useListGlobalConcurrencyLimits } from "@/hooks/global-concurrency-limits";
import { createFileRoute } from "@tanstack/react-router";
import { zodSearchValidator } from "@tanstack/router-zod-adapter";
import { z } from "zod";

import { ConcurrencyPage } from "@/components/concurrency/concurrency-page";
/**
* Schema for validating URL search parameters for the Concurrency Limits page.
* @property {'Global' | 'Task_Run'} tab used designate which tab view to display
*/
const searchParams = z
.object({
tab: z.enum(["global", "task-run"]).default("global"),
})
.strict();

export type TabOptions = z.infer<typeof searchParams>["tab"];

export const Route = createFileRoute("/concurrency-limits")({
component: RouteComponent,
validateSearch: zodSearchValidator(searchParams),
component: ConcurrencyPage,
wrapInSuspense: true,
loader: useListGlobalConcurrencyLimits.loader,
});

function RouteComponent() {
return <ConcurrencyPage />;
}

0 comments on commit 35d8240

Please sign in to comment.