Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI v2] feat: Adds global concurrency limit query definitions #16220

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions ui-v2/src/hooks/global-concurrency-limits.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { renderHook, waitFor } from "@testing-library/react";
import { http, HttpResponse } from "msw";
import { describe, expect, it } from "vitest";

import {
type GlobalConcurrencyLimit,
useGetGlobalConcurrencyLimit,
useListGlobalConcurrencyLimits,
} from "./global-concurrency-limits";

import { server } from "../../tests/mocks/node";

describe("global concurrency limits hooks", () => {
const seedGlobalConcurrencyLimits = () => [
{
id: "0",
created: "2021-01-01T00:00:00Z",
updated: "2021-01-01T00:00:00Z",
active: false,
name: "global concurrency limit 0",
limit: 0,
active_slots: 0,
slot_decay_per_second: 0,
},
];

const seedGlobalConcurrencyLimitDetails = () => ({
id: "0",
created: "2021-01-01T00:00:00Z",
updated: "2021-01-01T00:00:00Z",
active: false,
name: "global concurrency limit 0",
limit: 0,
active_slots: 0,
slot_decay_per_second: 0,
});

const mockFetchGlobalConcurrencyLimitsAPI = (
globalConcurrencyLimits: Array<GlobalConcurrencyLimit>,
) => {
server.use(
http.post(
"http://localhost:4200/api/v2/concurrency_limits/filter",
() => {
return HttpResponse.json(globalConcurrencyLimits);
},
),
);
};

const mockFetchGlobalConcurrencyLimitDetailsAPI = (
globalConcurrencyLimit: GlobalConcurrencyLimit,
) => {
server.use(
http.get(
"http://localhost:4200/api/v2/concurrency_limits/:id_or_name",
() => {
return HttpResponse.json(globalConcurrencyLimit);
},
),
);
};

const createQueryWrapper = ({ queryClient = new QueryClient() }) => {
const QueryWrapper = ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
return QueryWrapper;
};

const filter = {
offset: 0,
};

/**
* Data Management:
* - Asserts global concurrency limit list data is fetched based on the APIs invoked for the hook
*/
it("is stores list data into the appropriate list query when using useQuery()", async () => {
// ------------ Mock API requests when cache is empty
const mockList = seedGlobalConcurrencyLimits();
mockFetchGlobalConcurrencyLimitsAPI(mockList);

// ------------ Initialize hooks to test
const { result } = renderHook(
() => useListGlobalConcurrencyLimits(filter),
{ wrapper: createQueryWrapper({}) },
);

// ------------ Assert
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockList);
});

/**
* Data Management:
* - Asserts global concurrency limit details data is fetched based on the APIs invoked for the hook
*/
it("is stores details data into the appropriate details query when using useQuery()", async () => {
// ------------ Mock API requests when cache is empty
const mockDetails = seedGlobalConcurrencyLimitDetails();
mockFetchGlobalConcurrencyLimitDetailsAPI(mockDetails);

// ------------ Initialize hooks to test
const { result } = renderHook(
() => useGetGlobalConcurrencyLimit(mockDetails.id),
{ wrapper: createQueryWrapper({}) },
);

// ------------ Assert
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockDetails);
});
});
80 changes: 80 additions & 0 deletions ui-v2/src/hooks/global-concurrency-limits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type { components } from "@/api/prefect";
import { getQueryService } from "@/api/service";
import { queryOptions, useQuery } from "@tanstack/react-query";

export type GlobalConcurrencyLimit =
components["schemas"]["GlobalConcurrencyLimitResponse"];
export type GlobalConcurrencyLimitsFilter =
components["schemas"]["Body_read_all_concurrency_limits_v2_v2_concurrency_limits_filter_post"];

/**
* ```
* 🏗️ Variable queries construction 👷
* all => ['global-concurrency-limits'] // key to match ['global-concurrency-limits', ...
* list => ['global-concurrency-limits', 'list'] // key to match ['global-concurrency-limits', 'list', ...
* ['global-concurrency-limits', 'list', { ...filter1 }]
* ['global-concurrency-limits', 'list', { ...filter2 }]
* details => ['global-concurrency-limits', 'details'] // key to match ['global-concurrency-limits', 'details', ...]
* ['global-concurrency-limits', 'details', { ...globalConcurrencyLimit1 }]
* ['global-concurrency-limits', 'details', { ...globalConcurrencyLimit2 }]
* ```
* */
const queryKeyFactory = {
all: () => ["global-concurrency-limits"] as const,
lists: () => [...queryKeyFactory.all(), "list"] as const,
list: (filter: GlobalConcurrencyLimitsFilter) =>
[...queryKeyFactory.lists(), filter] as const,
details: () => [...queryKeyFactory.all(), "details"] as const,
detail: (id_or_name: string) =>
[...queryKeyFactory.details(), id_or_name] as const,
};

// ----- 🔑 Queries 🗄️
// ----------------------------
export const buildListGlobalConcurrencyLimitsQuery = (
filter: GlobalConcurrencyLimitsFilter,
) =>
queryOptions({
queryKey: queryKeyFactory.list(filter),
queryFn: async () => {
const res = await getQueryService().POST(
"/v2/concurrency_limits/filter",
{ body: filter },
);
return res.data ?? [];
},
});

export const buildGetGlobalConcurrencyLimitQuery = (id_or_name: string) =>
queryOptions({
queryKey: queryKeyFactory.detail(id_or_name),
queryFn: async () => {
const res = await getQueryService().GET(
"/v2/concurrency_limits/{id_or_name}",
{ params: { path: { id_or_name } } },
);
return res.data ?? null;
},
});

/**
*
* @param filter
* @returns list of global concurrency limits as a QueryResult object
*/
export const useListGlobalConcurrencyLimits = (
filter: GlobalConcurrencyLimitsFilter,
) => useQuery(buildListGlobalConcurrencyLimitsQuery(filter));

/**
*
* @param id_or_name
* @returns details about the specified global concurrency limit as a QueryResult object
*/
export const useGetGlobalConcurrencyLimit = (id_or_name: string) =>
useQuery(buildGetGlobalConcurrencyLimitQuery(id_or_name));

// ----- ✍🏼 Mutations 🗄️
// ----------------------------

// TODO:
Loading