chore: update all import paths to go through client instance

This commit is contained in:
Parkreiner 2024-05-01 21:45:12 +00:00
parent 84b7406113
commit f60627eb3f
94 changed files with 668 additions and 2077 deletions

View File

@ -1,7 +1,7 @@
import type { Page } from "@playwright/test";
import { expect } from "@playwright/test";
import { formatDuration, intervalToDuration } from "date-fns";
import * as API from "api/api";
import { type DeploymentConfig, client } from "api/api";
import type { SerpentOption } from "api/typesGenerated";
import { coderPort } from "./constants";
import { findSessionToken, randomName } from "./helpers";
@ -11,25 +11,26 @@ let currentOrgId: string;
export const setupApiCalls = async (page: Page) => {
try {
const token = await findSessionToken(page);
API.setSessionToken(token);
client.setSessionToken(token);
} catch {
// If this fails, we have an unauthenticated client.
}
API.setHost(`http://127.0.0.1:${coderPort}`);
client.setHost(`http://127.0.0.1:${coderPort}`);
};
export const getCurrentOrgId = async (): Promise<string> => {
if (currentOrgId) {
return currentOrgId;
}
const currentUser = await API.getAuthenticatedUser();
const currentUser = await client.api.getAuthenticatedUser();
currentOrgId = currentUser.organization_ids[0];
return currentOrgId;
};
export const createUser = async (orgId: string) => {
const name = randomName();
const user = await API.createUser({
const user = await client.api.createUser({
email: `${name}@coder.com`,
username: name,
password: "s3cure&password!",
@ -42,7 +43,7 @@ export const createUser = async (orgId: string) => {
export const createGroup = async (orgId: string) => {
const name = randomName();
const group = await API.createGroup(orgId, {
const group = await client.api.createGroup(orgId, {
name,
display_name: `Display ${name}`,
avatar_url: "/emojis/1f60d.png",
@ -53,7 +54,7 @@ export const createGroup = async (orgId: string) => {
export async function verifyConfigFlagBoolean(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -68,7 +69,7 @@ export async function verifyConfigFlagBoolean(
export async function verifyConfigFlagNumber(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -80,7 +81,7 @@ export async function verifyConfigFlagNumber(
export async function verifyConfigFlagString(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -100,7 +101,7 @@ export async function verifyConfigFlagEmpty(page: Page, flag: string) {
export async function verifyConfigFlagArray(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -116,7 +117,7 @@ export async function verifyConfigFlagArray(
export async function verifyConfigFlagEntries(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -138,7 +139,7 @@ export async function verifyConfigFlagEntries(
export async function verifyConfigFlagDuration(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
) {
const opt = findConfigOption(config, flag);
@ -157,7 +158,7 @@ export async function verifyConfigFlagDuration(
}
export function findConfigOption(
config: API.DeploymentConfig,
config: DeploymentConfig,
flag: string,
): SerpentOption {
const opt = config.options.find((option) => option.flag === flag);

View File

@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import { hasFirstUser } from "api/api";
import { client } from "api/api";
import { Language } from "pages/CreateUserPage/CreateUserForm";
import { setupApiCalls } from "./api";
import * as constants from "./constants";
@ -9,7 +9,7 @@ import { storageState } from "./playwright.config";
test("setup deployment", async ({ page }) => {
await page.goto("/", { waitUntil: "domcontentloaded" });
await setupApiCalls(page);
const exists = await hasFirstUser();
const exists = await client.api.hasFirstUser();
// First user already exists, abort early. All tests execute this as a dependency,
// if you run multiple tests in the UI, this will fail unless we check this.
if (exists) {

View File

@ -6,7 +6,7 @@ import capitalize from "lodash/capitalize";
import path from "path";
import * as ssh from "ssh2";
import { Duplex } from "stream";
import { axiosInstance } from "api/api";
import { client } from "api/api";
import type {
WorkspaceBuildParameter,
UpdateTemplateMeta,
@ -396,6 +396,7 @@ export const waitUntilUrlIsNotResponding = async (url: string) => {
const retryIntervalMs = 1000;
let retries = 0;
const axiosInstance = client.getAxiosInstance();
while (retries < maxRetries) {
try {
await axiosInstance.get(url);

View File

@ -10,7 +10,7 @@ import type {
} from "@playwright/test/reporter";
import * as fs from "fs/promises";
import type { Writable } from "stream";
import { axiosInstance } from "api/api";
import { client } from "api/api";
import { coderdPProfPort, enterpriseLicense } from "./constants";
class CoderReporter implements Reporter {
@ -136,6 +136,7 @@ class CoderReporter implements Reporter {
const logLines = (chunk: string): string[] => chunk.trimEnd().split("\n");
const exportDebugPprof = async (outputFile: string) => {
const axiosInstance = client.getAxiosInstance();
const response = await axiosInstance.get(
`http://127.0.0.1:${coderdPProfPort}/debug/pprof/goroutine?debug=1`,
);

View File

@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import * as API from "api/api";
import { client } from "api/api";
import { setupApiCalls } from "../../api";
import { e2eFakeExperiment1, e2eFakeExperiment2 } from "../../constants";
@ -7,7 +7,7 @@ test("experiments", async ({ page }) => {
await setupApiCalls(page);
// Load experiments from backend API
const availableExperiments = await API.getAvailableExperiments();
const availableExperiments = await client.api.getAvailableExperiments();
// Verify if the site lists the same experiments
await page.goto("/deployment/general", { waitUntil: "networkidle" });

View File

@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { client } from "api/api";
import {
setupApiCalls,
verifyConfigFlagArray,
@ -11,7 +11,7 @@ import {
test("enabled network settings", async ({ page }) => {
await setupApiCalls(page);
const config = await getDeploymentConfig();
const config = await client.api.getDeploymentConfig();
await page.goto("/deployment/network", { waitUntil: "domcontentloaded" });

View File

@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { client } from "api/api";
import {
setupApiCalls,
verifyConfigFlagArray,
@ -11,7 +11,7 @@ import {
test("enabled observability settings", async ({ page }) => {
await setupApiCalls(page);
const config = await getDeploymentConfig();
const config = await client.api.getDeploymentConfig();
await page.goto("/deployment/observability", {
waitUntil: "domcontentloaded",

View File

@ -1,7 +1,7 @@
import type { Page } from "@playwright/test";
import { expect, test } from "@playwright/test";
import type * as API from "api/api";
import { getDeploymentConfig } from "api/api";
import { client } from "api/api";
import {
findConfigOption,
setupApiCalls,
@ -12,7 +12,7 @@ import {
test("enabled security settings", async ({ page }) => {
await setupApiCalls(page);
const config = await getDeploymentConfig();
const config = await client.api.getDeploymentConfig();
await page.goto("/deployment/security", { waitUntil: "domcontentloaded" });

View File

@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { client } from "api/api";
import {
setupApiCalls,
verifyConfigFlagArray,
@ -10,7 +10,7 @@ import {
test("login with OIDC", async ({ page }) => {
await setupApiCalls(page);
const config = await getDeploymentConfig();
const config = await client.api.getDeploymentConfig();
await page.goto("/deployment/userauth", { waitUntil: "domcontentloaded" });

View File

@ -1,5 +1,5 @@
import { test, expect, type Page } from "@playwright/test";
import { createWorkspaceProxy } from "api/api";
import { client } from "api/api";
import { setupApiCalls } from "../../api";
import { coderPort, workspaceProxyPort } from "../../constants";
import { randomName, requiresEnterpriseLicense } from "../../helpers";
@ -34,7 +34,7 @@ test("custom proxy is online", async ({ page }) => {
const proxyName = randomName();
// Register workspace proxy
const proxyResponse = await createWorkspaceProxy({
const proxyResponse = await client.api.createWorkspaceProxy({
name: proxyName,
display_name: "",
icon: "/emojis/1f1e7-1f1f7.png",

View File

@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test";
import * as API from "api/api";
import { client } from "api/api";
import {
createGroup,
createUser,
@ -19,7 +19,7 @@ test("remove member", async ({ page, baseURL }) => {
createGroup(orgId),
createUser(orgId),
]);
await API.addMember(group.id, member.id);
await client.api.addMember(group.id, member.id);
await page.goto(`${baseURL}/groups/${group.id}`, {
waitUntil: "domcontentloaded",

View File

@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import { createTemplate, createTemplateVersion, getTemplate } from "api/api";
import { client } from "api/api";
import { getCurrentOrgId, setupApiCalls } from "../../api";
import { beforeCoderTest } from "../../hooks";
@ -11,14 +11,14 @@ test("update template schedule settings without override other settings", async
}) => {
await setupApiCalls(page);
const orgId = await getCurrentOrgId();
const templateVersion = await createTemplateVersion(orgId, {
const templateVersion = await client.api.createTemplateVersion(orgId, {
storage_method: "file" as const,
provisioner: "echo",
user_variable_values: [],
example_id: "docker",
tags: {},
});
const template = await createTemplate(orgId, {
const template = await client.api.createTemplate(orgId, {
name: "test-template",
display_name: "Test Template",
template_version_id: templateVersion.id,
@ -33,7 +33,7 @@ test("update template schedule settings without override other settings", async
await page.getByRole("button", { name: "Submit" }).click();
await expect(page.getByText("Template updated successfully")).toBeVisible();
const updatedTemplate = await getTemplate(template.id);
const updatedTemplate = await client.api.getTemplate(template.id);
// Validate that the template data remains consistent, with the exception of
// the 'default_ttl_ms' field (updated during the test) and the 'updated at'
// field (automatically updated by the backend).

View File

@ -6,10 +6,11 @@ import {
MockWorkspaceBuild,
MockWorkspaceBuildParameter1,
} from "testHelpers/entities";
import * as api from "./api";
import { axiosInstance } from "./api";
import { client, getURLWithSearchParams, MissingBuildParameters } from "./api";
import type * as TypesGen from "./typesGenerated";
const axiosInstance = client.getAxiosInstance();
describe("api.ts", () => {
describe("login", () => {
it("should return LoginResponse", async () => {
@ -23,7 +24,7 @@ describe("api.ts", () => {
.mockResolvedValueOnce({ data: loginResponse });
// when
const result = await api.login("test", "123");
const result = await client.api.login("test", "123");
// then
expect(axiosInstance.post).toHaveBeenCalled();
@ -44,7 +45,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
try {
await api.login("test", "123");
await client.api.login("test", "123");
} catch (error) {
expect(error).toStrictEqual(expectedError);
}
@ -60,7 +61,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
// when
await api.logout();
await client.api.logout();
// then
expect(axiosMockPost).toHaveBeenCalled();
@ -80,7 +81,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
try {
await api.logout();
await client.api.logout();
} catch (error) {
expect(error).toStrictEqual(expectedError);
}
@ -100,7 +101,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
// when
const result = await api.getApiKey();
const result = await client.api.getApiKey();
// then
expect(axiosMockPost).toHaveBeenCalled();
@ -121,7 +122,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
try {
await api.getApiKey();
await client.api.getApiKey();
} catch (error) {
expect(error).toStrictEqual(expectedError);
}
@ -147,7 +148,7 @@ describe("api.ts", () => {
])(
`Workspaces - getURLWithSearchParams(%p, %p) returns %p`,
(basePath, filter, expected) => {
expect(api.getURLWithSearchParams(basePath, filter)).toBe(expected);
expect(getURLWithSearchParams(basePath, filter)).toBe(expected);
},
);
});
@ -164,7 +165,7 @@ describe("api.ts", () => {
])(
`Users - getURLWithSearchParams(%p, %p) returns %p`,
(basePath, filter, expected) => {
expect(api.getURLWithSearchParams(basePath, filter)).toBe(expected);
expect(getURLWithSearchParams(basePath, filter)).toBe(expected);
},
);
});
@ -172,25 +173,30 @@ describe("api.ts", () => {
describe("update", () => {
it("creates a build with start and the latest template", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(client.api, "postWorkspaceBuild")
.mockResolvedValueOnce(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate);
await api.updateWorkspace(MockWorkspace);
expect(api.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id, {
transition: "start",
template_version_id: MockTemplate.active_version_id,
rich_parameter_values: [],
});
jest.spyOn(client.api, "getTemplate").mockResolvedValueOnce(MockTemplate);
await client.api.updateWorkspace(MockWorkspace);
expect(client.api.postWorkspaceBuild).toHaveBeenCalledWith(
MockWorkspace.id,
{
transition: "start",
template_version_id: MockTemplate.active_version_id,
rich_parameter_values: [],
},
);
});
it("fails when having missing parameters", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(client.api, "postWorkspaceBuild")
.mockResolvedValue(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValue(MockTemplate);
jest.spyOn(api, "getWorkspaceBuildParameters").mockResolvedValue([]);
jest.spyOn(client.api, "getTemplate").mockResolvedValue(MockTemplate);
jest
.spyOn(api, "getTemplateVersionRichParameters")
.spyOn(client.api, "getWorkspaceBuildParameters")
.mockResolvedValue([]);
jest
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValue([
MockTemplateVersionParameter1,
{ ...MockTemplateVersionParameter2, mutable: false },
@ -198,14 +204,14 @@ describe("api.ts", () => {
let error = new Error();
try {
await api.updateWorkspace(MockWorkspace);
await client.api.updateWorkspace(MockWorkspace);
} catch (e) {
error = e as Error;
}
expect(error).toBeInstanceOf(api.MissingBuildParameters);
expect(error).toBeInstanceOf(MissingBuildParameters);
// Verify if the correct missing parameters are being passed
expect((error as api.MissingBuildParameters).parameters).toEqual([
expect((error as MissingBuildParameters).parameters).toEqual([
MockTemplateVersionParameter1,
{ ...MockTemplateVersionParameter2, mutable: false },
]);
@ -213,23 +219,26 @@ describe("api.ts", () => {
it("creates a build with the no parameters if it is already filled", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(client.api, "postWorkspaceBuild")
.mockResolvedValueOnce(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest.spyOn(client.api, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest
.spyOn(api, "getWorkspaceBuildParameters")
.spyOn(client.api, "getWorkspaceBuildParameters")
.mockResolvedValue([MockWorkspaceBuildParameter1]);
jest
.spyOn(api, "getTemplateVersionRichParameters")
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValue([
{ ...MockTemplateVersionParameter1, required: true, mutable: false },
]);
await api.updateWorkspace(MockWorkspace);
expect(api.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id, {
transition: "start",
template_version_id: MockTemplate.active_version_id,
rich_parameter_values: [],
});
await client.api.updateWorkspace(MockWorkspace);
expect(client.api.postWorkspaceBuild).toHaveBeenCalledWith(
MockWorkspace.id,
{
transition: "start",
template_version_id: MockTemplate.active_version_id,
rich_parameter_values: [],
},
);
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
import type { QueryClient, UseQueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { AppearanceConfig } from "api/typesGenerated";
import { getMetadataAsJSON } from "utils/metadata";
import { cachedQuery } from "./util";
@ -12,13 +12,13 @@ export const appearance = (): UseQueryOptions<AppearanceConfig> => {
return cachedQuery({
initialData: initialAppearanceData,
queryKey: ["appearance"],
queryFn: () => API.getAppearance(),
queryFn: () => client.api.getAppearance(),
});
};
export const updateAppearance = (queryClient: QueryClient) => {
return {
mutationFn: API.updateAppearance,
mutationFn: client.api.updateAppearance,
onSuccess: (newConfig: AppearanceConfig) => {
queryClient.setQueryData(appearanceConfigKey, newConfig);
},

View File

@ -1,4 +1,4 @@
import { getAuditLogs } from "api/api";
import { client } from "api/api";
import type { AuditLogResponse } from "api/typesGenerated";
import { useFilterParamsKey } from "components/Filter/filter";
import type { UsePaginatedQueryOptions } from "hooks/usePaginatedQuery";
@ -13,7 +13,7 @@ export function paginatedAudits(
return ["auditLogs", payload, pageNumber] as const;
},
queryFn: ({ payload, limit, offset }) => {
return getAuditLogs({
return client.api.getAuditLogs({
offset,
limit,
q: payload,

View File

@ -1,4 +1,4 @@
import * as API from "api/api";
import { client } from "api/api";
import type { AuthorizationRequest } from "api/typesGenerated";
export const AUTHORIZATION_KEY = "authorization";
@ -9,6 +9,6 @@ export const getAuthorizationKey = (req: AuthorizationRequest) =>
export const checkAuthorization = (req: AuthorizationRequest) => {
return {
queryKey: getAuthorizationKey(req),
queryFn: () => API.checkAuthorization(req),
queryFn: () => client.api.checkAuthorization(req),
};
};

View File

@ -1,5 +1,5 @@
import type { UseQueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { BuildInfoResponse } from "api/typesGenerated";
import { getMetadataAsJSON } from "utils/metadata";
import { cachedQuery } from "./util";
@ -12,6 +12,6 @@ export const buildInfo = (): UseQueryOptions<BuildInfoResponse> => {
return cachedQuery({
initialData: initialBuildInfoData,
queryKey: buildInfoKey,
queryFn: () => API.getBuildInfo(),
queryFn: () => client.api.getBuildInfo(),
});
};

View File

@ -1,5 +1,5 @@
import type { QueryClient, UseMutationOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { HealthSettings, UpdateHealthSettings } from "api/typesGenerated";
export const HEALTH_QUERY_KEY = ["health"];
@ -7,14 +7,14 @@ export const HEALTH_QUERY_SETTINGS_KEY = ["health", "settings"];
export const health = () => ({
queryKey: HEALTH_QUERY_KEY,
queryFn: async () => API.getHealth(),
queryFn: async () => client.api.getHealth(),
});
export const refreshHealth = (queryClient: QueryClient) => {
return {
mutationFn: async () => {
await queryClient.cancelQueries(HEALTH_QUERY_KEY);
const newHealthData = await API.getHealth(true);
const newHealthData = await client.api.getHealth(true);
queryClient.setQueryData(HEALTH_QUERY_KEY, newHealthData);
},
};
@ -23,7 +23,7 @@ export const refreshHealth = (queryClient: QueryClient) => {
export const healthSettings = () => {
return {
queryKey: HEALTH_QUERY_SETTINGS_KEY,
queryFn: API.getHealthSettings,
queryFn: client.api.getHealthSettings,
};
};
@ -36,7 +36,7 @@ export const updateHealthSettings = (
unknown
> => {
return {
mutationFn: API.updateHealthSettings,
mutationFn: client.api.updateHealthSettings,
onSuccess: async (_, newSettings) => {
await queryClient.invalidateQueries(HEALTH_QUERY_KEY);
queryClient.setQueryData(HEALTH_QUERY_SETTINGS_KEY, newSettings);

View File

@ -1,29 +1,29 @@
import * as API from "api/api";
import { client } from "api/api";
export const deploymentConfig = () => {
return {
queryKey: ["deployment", "config"],
queryFn: API.getDeploymentConfig,
queryFn: client.api.getDeploymentConfig,
};
};
export const deploymentDAUs = () => {
return {
queryKey: ["deployment", "daus"],
queryFn: () => API.getDeploymentDAUs(),
queryFn: () => client.api.getDeploymentDAUs(),
};
};
export const deploymentStats = () => {
return {
queryKey: ["deployment", "stats"],
queryFn: API.getDeploymentStats,
queryFn: client.api.getDeploymentStats,
};
};
export const deploymentSSHConfig = () => {
return {
queryKey: ["deployment", "sshConfig"],
queryFn: API.getDeploymentSSHConfig,
queryFn: client.api.getDeploymentSSHConfig,
};
};

View File

@ -1,5 +1,5 @@
import type { QueryClient, UseQueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { Entitlements } from "api/typesGenerated";
import { getMetadataAsJSON } from "utils/metadata";
import { cachedQuery } from "./util";
@ -11,13 +11,13 @@ export const entitlements = (): UseQueryOptions<Entitlements> => {
return cachedQuery({
initialData: initialEntitlementsData,
queryKey: entitlementsQueryKey,
queryFn: () => API.getEntitlements(),
queryFn: () => client.api.getEntitlements(),
});
};
export const refreshEntitlements = (queryClient: QueryClient) => {
return {
mutationFn: API.refreshEntitlements,
mutationFn: client.api.refreshEntitlements,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: entitlementsQueryKey,

View File

@ -1,5 +1,5 @@
import type { UseQueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { Experiments } from "api/typesGenerated";
import { getMetadataAsJSON } from "utils/metadata";
import { cachedQuery } from "./util";
@ -11,13 +11,13 @@ export const experiments = (): UseQueryOptions<Experiments> => {
return cachedQuery({
initialData: initialExperimentsData,
queryKey: experimentsKey,
queryFn: () => API.getExperiments(),
queryFn: () => client.api.getExperiments(),
});
};
export const availableExperiments = () => {
return {
queryKey: ["availableExperiments"],
queryFn: async () => API.getAvailableExperiments(),
queryFn: async () => client.api.getAvailableExperiments(),
};
};

View File

@ -1,25 +1,25 @@
import type { QueryClient, UseMutationOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { ExternalAuth } from "api/typesGenerated";
// Returns all configured external auths for a given user.
export const externalAuths = () => {
return {
queryKey: ["external-auth"],
queryFn: () => API.getUserExternalAuthProviders(),
queryFn: () => client.api.getUserExternalAuthProviders(),
};
};
export const externalAuthProvider = (providerId: string) => {
return {
queryKey: ["external-auth", providerId],
queryFn: () => API.getExternalAuthProvider(providerId),
queryFn: () => client.api.getExternalAuthProvider(providerId),
};
};
export const externalAuthDevice = (providerId: string) => {
return {
queryFn: () => API.getExternalAuthDevice(providerId),
queryFn: () => client.api.getExternalAuthDevice(providerId),
queryKey: ["external-auth", providerId, "device"],
};
};
@ -31,7 +31,7 @@ export const exchangeExternalAuthDevice = (
) => {
return {
queryFn: () =>
API.exchangeExternalAuthDevice(providerId, {
client.api.exchangeExternalAuthDevice(providerId, {
device_code: deviceCode,
}),
queryKey: ["external-auth", providerId, "device", deviceCode],
@ -46,7 +46,7 @@ export const validateExternalAuth = (
queryClient: QueryClient,
): UseMutationOptions<ExternalAuth, unknown, string> => {
return {
mutationFn: API.getExternalAuthProvider,
mutationFn: client.api.getExternalAuthProvider,
onSuccess: (data, providerId) => {
queryClient.setQueryData(["external-auth", providerId], data);
},
@ -55,7 +55,7 @@ export const validateExternalAuth = (
export const unlinkExternalAuths = (queryClient: QueryClient) => {
return {
mutationFn: API.unlinkExternalAuthProvider,
mutationFn: client.api.unlinkExternalAuthProvider,
onSuccess: async () => {
await queryClient.invalidateQueries(["external-auth"]);
},

View File

@ -1,14 +1,14 @@
import * as API from "api/api";
import { client } from "api/api";
export const uploadFile = () => {
return {
mutationFn: API.uploadFile,
mutationFn: client.api.uploadFile,
};
};
export const file = (fileId: string) => {
return {
queryKey: ["files", fileId],
queryFn: () => API.getFile(fileId),
queryFn: () => client.api.getFile(fileId),
};
};

View File

@ -1,6 +1,5 @@
import type { QueryClient, UseQueryOptions } from "react-query";
import * as API from "api/api";
import { checkAuthorization } from "api/api";
import { client } from "api/api";
import type {
CreateGroupRequest,
Group,
@ -15,14 +14,14 @@ const getGroupQueryKey = (groupId: string) => ["group", groupId];
export const groups = (organizationId: string) => {
return {
queryKey: GROUPS_QUERY_KEY,
queryFn: () => API.getGroups(organizationId),
queryFn: () => client.api.getGroups(organizationId),
} satisfies UseQueryOptions<Group[]>;
};
export const group = (groupId: string) => {
return {
queryKey: getGroupQueryKey(groupId),
queryFn: () => API.getGroup(groupId),
queryFn: () => client.api.getGroup(groupId),
};
};
@ -72,7 +71,7 @@ export const groupPermissions = (groupId: string) => {
return {
queryKey: [...getGroupQueryKey(groupId), "permissions"],
queryFn: () =>
checkAuthorization({
client.api.checkAuthorization({
checks: {
canUpdateGroup: {
object: {
@ -92,7 +91,7 @@ export const createGroup = (queryClient: QueryClient) => {
organizationId,
...request
}: CreateGroupRequest & { organizationId: string }) =>
API.createGroup(organizationId, request),
client.api.createGroup(organizationId, request),
onSuccess: async () => {
await queryClient.invalidateQueries(GROUPS_QUERY_KEY);
},
@ -105,7 +104,7 @@ export const patchGroup = (queryClient: QueryClient) => {
groupId,
...request
}: PatchGroupRequest & { groupId: string }) =>
API.patchGroup(groupId, request),
client.api.patchGroup(groupId, request),
onSuccess: async (updatedGroup: Group) =>
invalidateGroup(queryClient, updatedGroup.id),
};
@ -113,7 +112,7 @@ export const patchGroup = (queryClient: QueryClient) => {
export const deleteGroup = (queryClient: QueryClient) => {
return {
mutationFn: API.deleteGroup,
mutationFn: client.api.deleteGroup,
onSuccess: async (_: void, groupId: string) =>
invalidateGroup(queryClient, groupId),
};
@ -122,7 +121,7 @@ export const deleteGroup = (queryClient: QueryClient) => {
export const addMember = (queryClient: QueryClient) => {
return {
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
API.addMember(groupId, userId),
client.api.addMember(groupId, userId),
onSuccess: async (updatedGroup: Group) =>
invalidateGroup(queryClient, updatedGroup.id),
};
@ -131,7 +130,7 @@ export const addMember = (queryClient: QueryClient) => {
export const removeMember = (queryClient: QueryClient) => {
return {
mutationFn: ({ groupId, userId }: { groupId: string; userId: string }) =>
API.removeMember(groupId, userId),
client.api.removeMember(groupId, userId),
onSuccess: async (updatedGroup: Group) =>
invalidateGroup(queryClient, updatedGroup.id),
};

View File

@ -1,22 +1,26 @@
import * as API from "api/api";
import {
type InsightsParams,
type InsightsTemplateParams,
client,
} from "api/api";
export const insightsTemplate = (params: API.InsightsTemplateParams) => {
export const insightsTemplate = (params: InsightsTemplateParams) => {
return {
queryKey: ["insights", "templates", params.template_ids, params],
queryFn: () => API.getInsightsTemplate(params),
queryFn: () => client.api.getInsightsTemplate(params),
};
};
export const insightsUserLatency = (params: API.InsightsParams) => {
export const insightsUserLatency = (params: InsightsParams) => {
return {
queryKey: ["insights", "userLatency", params.template_ids, params],
queryFn: () => API.getInsightsUserLatency(params),
queryFn: () => client.api.getInsightsUserLatency(params),
};
};
export const insightsUserActivity = (params: API.InsightsParams) => {
export const insightsUserActivity = (params: InsightsParams) => {
return {
queryKey: ["insights", "userActivity", params.template_ids, params],
queryFn: () => API.getInsightsUserActivity(params),
queryFn: () => client.api.getInsightsUserActivity(params),
};
};

View File

@ -1,9 +1,9 @@
import type { GetJFrogXRayScanParams } from "api/api";
import * as API from "api/api";
import { client } from "api/api";
export const xrayScan = (params: GetJFrogXRayScanParams) => {
return {
queryKey: ["xray", params],
queryFn: () => API.getJFrogXRayScan(params),
queryFn: () => client.api.getJFrogXRayScan(params),
};
};

View File

@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type * as TypesGen from "api/typesGenerated";
const appsKey = ["oauth2-provider", "apps"];
@ -10,20 +10,20 @@ const appSecretsKey = (appId: string) => appKey(appId).concat("secrets");
export const getApps = (userId?: string) => {
return {
queryKey: userId ? appsKey.concat(userId) : appsKey,
queryFn: () => API.getOAuth2ProviderApps({ user_id: userId }),
queryFn: () => client.api.getOAuth2ProviderApps({ user_id: userId }),
};
};
export const getApp = (id: string) => {
return {
queryKey: appKey(id),
queryFn: () => API.getOAuth2ProviderApp(id),
queryFn: () => client.api.getOAuth2ProviderApp(id),
};
};
export const postApp = (queryClient: QueryClient) => {
return {
mutationFn: API.postOAuth2ProviderApp,
mutationFn: client.api.postOAuth2ProviderApp,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: appsKey,
@ -40,7 +40,7 @@ export const putApp = (queryClient: QueryClient) => {
}: {
id: string;
req: TypesGen.PutOAuth2ProviderAppRequest;
}) => API.putOAuth2ProviderApp(id, req),
}) => client.api.putOAuth2ProviderApp(id, req),
onSuccess: async (app: TypesGen.OAuth2ProviderApp) => {
await queryClient.invalidateQueries({
queryKey: appKey(app.id),
@ -51,7 +51,7 @@ export const putApp = (queryClient: QueryClient) => {
export const deleteApp = (queryClient: QueryClient) => {
return {
mutationFn: API.deleteOAuth2ProviderApp,
mutationFn: client.api.deleteOAuth2ProviderApp,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: appsKey,
@ -63,13 +63,13 @@ export const deleteApp = (queryClient: QueryClient) => {
export const getAppSecrets = (id: string) => {
return {
queryKey: appSecretsKey(id),
queryFn: () => API.getOAuth2ProviderAppSecrets(id),
queryFn: () => client.api.getOAuth2ProviderAppSecrets(id),
};
};
export const postAppSecret = (queryClient: QueryClient) => {
return {
mutationFn: API.postOAuth2ProviderAppSecret,
mutationFn: client.api.postOAuth2ProviderAppSecret,
onSuccess: async (
_: TypesGen.OAuth2ProviderAppSecretFull,
appId: string,
@ -84,7 +84,7 @@ export const postAppSecret = (queryClient: QueryClient) => {
export const deleteAppSecret = (queryClient: QueryClient) => {
return {
mutationFn: ({ appId, secretId }: { appId: string; secretId: string }) =>
API.deleteOAuth2ProviderAppSecret(appId, secretId),
client.api.deleteOAuth2ProviderAppSecret(appId, secretId),
onSuccess: async (_: void, { appId }: { appId: string }) => {
await queryClient.invalidateQueries({
queryKey: appSecretsKey(appId),
@ -95,7 +95,7 @@ export const deleteAppSecret = (queryClient: QueryClient) => {
export const revokeApp = (queryClient: QueryClient, userId: string) => {
return {
mutationFn: API.revokeOAuth2ProviderApp,
mutationFn: client.api.revokeOAuth2ProviderApp,
onSuccess: async () => {
await queryClient.invalidateQueries({
queryKey: userAppsKey(userId),

View File

@ -1,8 +1,8 @@
import * as API from "api/api";
import { client } from "api/api";
export const roles = () => {
return {
queryKey: ["roles"],
queryFn: API.getRoles,
queryFn: client.api.getRoles,
};
};

View File

@ -1,5 +1,5 @@
import type { QueryClient, QueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type {
UpdateUserQuietHoursScheduleRequest,
UserQuietHoursScheduleResponse,
@ -16,7 +16,7 @@ export const userQuietHoursSchedule = (
): QueryOptions<UserQuietHoursScheduleResponse> => {
return {
queryKey: userQuietHoursScheduleKey(userId),
queryFn: () => API.getUserQuietHoursSchedule(userId),
queryFn: () => client.api.getUserQuietHoursSchedule(userId),
};
};
@ -26,7 +26,7 @@ export const updateUserQuietHoursSchedule = (
) => {
return {
mutationFn: (request: UpdateUserQuietHoursScheduleRequest) =>
API.updateUserQuietHoursSchedule(userId, request),
client.api.updateUserQuietHoursSchedule(userId, request),
onSuccess: async () => {
await queryClient.invalidateQueries(userQuietHoursScheduleKey(userId));
},

View File

@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type { GitSSHKey } from "api/typesGenerated";
const getUserSSHKeyQueryKey = (userId: string) => [userId, "sshKey"];
@ -7,7 +7,7 @@ const getUserSSHKeyQueryKey = (userId: string) => [userId, "sshKey"];
export const userSSHKey = (userId: string) => {
return {
queryKey: getUserSSHKeyQueryKey(userId),
queryFn: () => API.getUserSSHKey(userId),
queryFn: () => client.api.getUserSSHKey(userId),
};
};
@ -16,7 +16,7 @@ export const regenerateUserSSHKey = (
queryClient: QueryClient,
) => {
return {
mutationFn: () => API.regenerateUserSSHKey(userId),
mutationFn: () => client.api.regenerateUserSSHKey(userId),
onSuccess: (newKey: GitSSHKey) => {
queryClient.setQueryData(getUserSSHKeyQueryKey(userId), newKey);
},

View File

@ -1,5 +1,5 @@
import type { MutationOptions, QueryClient, QueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type {
CreateTemplateRequest,
CreateTemplateVersionRequest,
@ -26,7 +26,7 @@ export const templateByName = (
): QueryOptions<Template> => {
return {
queryKey: templateByNameKey(organizationId, name),
queryFn: async () => API.getTemplateByName(organizationId, name),
queryFn: async () => client.api.getTemplateByName(organizationId, name),
};
};
@ -39,27 +39,27 @@ const getTemplatesQueryKey = (organizationId: string, deprecated?: boolean) => [
export const templates = (organizationId: string, deprecated?: boolean) => {
return {
queryKey: getTemplatesQueryKey(organizationId, deprecated),
queryFn: () => API.getTemplates(organizationId, { deprecated }),
queryFn: () => client.api.getTemplates(organizationId, { deprecated }),
};
};
export const templateACL = (templateId: string) => {
return {
queryKey: ["templateAcl", templateId],
queryFn: () => API.getTemplateACL(templateId),
queryFn: () => client.api.getTemplateACL(templateId),
};
};
export const setUserRole = (
queryClient: QueryClient,
): MutationOptions<
Awaited<ReturnType<typeof API.updateTemplateACL>>,
Awaited<ReturnType<typeof client.api.updateTemplateACL>>,
unknown,
{ templateId: string; userId: string; role: TemplateRole }
> => {
return {
mutationFn: ({ templateId, userId, role }) =>
API.updateTemplateACL(templateId, {
client.api.updateTemplateACL(templateId, {
user_perms: {
[userId]: role,
},
@ -73,13 +73,13 @@ export const setUserRole = (
export const setGroupRole = (
queryClient: QueryClient,
): MutationOptions<
Awaited<ReturnType<typeof API.updateTemplateACL>>,
Awaited<ReturnType<typeof client.api.updateTemplateACL>>,
unknown,
{ templateId: string; groupId: string; role: TemplateRole }
> => {
return {
mutationFn: ({ templateId, groupId, role }) =>
API.updateTemplateACL(templateId, {
client.api.updateTemplateACL(templateId, {
group_perms: {
[groupId]: role,
},
@ -93,14 +93,14 @@ export const setGroupRole = (
export const templateExamples = (organizationId: string) => {
return {
queryKey: [...getTemplatesQueryKey(organizationId), "examples"],
queryFn: () => API.getTemplateExamples(organizationId),
queryFn: () => client.api.getTemplateExamples(organizationId),
};
};
export const templateVersion = (versionId: string) => {
return {
queryKey: ["templateVersion", versionId],
queryFn: () => API.getTemplateVersion(versionId),
queryFn: () => client.api.getTemplateVersion(versionId),
};
};
@ -112,14 +112,18 @@ export const templateVersionByName = (
return {
queryKey: ["templateVersion", organizationId, templateName, versionName],
queryFn: () =>
API.getTemplateVersionByName(organizationId, templateName, versionName),
client.api.getTemplateVersionByName(
organizationId,
templateName,
versionName,
),
};
};
export const templateVersions = (templateId: string) => {
return {
queryKey: ["templateVersions", templateId],
queryFn: () => API.getTemplateVersions(templateId),
queryFn: () => client.api.getTemplateVersions(templateId),
};
};
@ -132,14 +136,14 @@ export const templateVersionVariablesKey = (versionId: string) => [
export const templateVersionVariables = (versionId: string) => {
return {
queryKey: templateVersionVariablesKey(versionId),
queryFn: () => API.getTemplateVersionVariables(versionId),
queryFn: () => client.api.getTemplateVersionVariables(versionId),
};
};
export const createTemplateVersion = (organizationId: string) => {
return {
mutationFn: async (request: CreateTemplateVersionRequest) => {
const newVersion = await API.createTemplateVersion(
const newVersion = await client.api.createTemplateVersion(
organizationId,
request,
);
@ -151,7 +155,7 @@ export const createTemplateVersion = (organizationId: string) => {
export const createAndBuildTemplateVersion = (organizationId: string) => {
return {
mutationFn: async (request: CreateTemplateVersionRequest) => {
const newVersion = await API.createTemplateVersion(
const newVersion = await client.api.createTemplateVersion(
organizationId,
request,
);
@ -167,7 +171,7 @@ export const updateActiveTemplateVersion = (
) => {
return {
mutationFn: (versionId: string) =>
API.updateActiveTemplateVersion(template.id, {
client.api.updateActiveTemplateVersion(template.id, {
id: versionId,
}),
onSuccess: async () => {
@ -185,7 +189,7 @@ export const templaceACLAvailable = (
) => {
return {
queryKey: ["template", templateId, "aclAvailable", options],
queryFn: () => API.getTemplateACLAvailable(templateId, options),
queryFn: () => client.api.getTemplateACLAvailable(templateId, options),
};
};
@ -198,7 +202,7 @@ export const templateVersionExternalAuthKey = (versionId: string) => [
export const templateVersionExternalAuth = (versionId: string) => {
return {
queryKey: templateVersionExternalAuthKey(versionId),
queryFn: () => API.getTemplateVersionExternalAuth(versionId),
queryFn: () => client.api.getTemplateVersionExternalAuth(versionId),
};
};
@ -217,13 +221,13 @@ export type CreateTemplateOptions = {
};
const createTemplateFn = async (options: CreateTemplateOptions) => {
const version = await API.createTemplateVersion(
const version = await client.api.createTemplateVersion(
options.organizationId,
options.version,
);
options.onCreateVersion?.(version);
await waitBuildToBeFinished(version, options.onTemplateVersionChanges);
return API.createTemplate(options.organizationId, {
return client.api.createTemplate(options.organizationId, {
...options.template,
template_version_id: version.id,
});
@ -232,21 +236,21 @@ const createTemplateFn = async (options: CreateTemplateOptions) => {
export const templateVersionLogs = (versionId: string) => {
return {
queryKey: ["templateVersion", versionId, "logs"],
queryFn: () => API.getTemplateVersionLogs(versionId),
queryFn: () => client.api.getTemplateVersionLogs(versionId),
};
};
export const richParameters = (versionId: string) => {
return {
queryKey: ["templateVersion", versionId, "richParameters"],
queryFn: () => API.getTemplateVersionRichParameters(versionId),
queryFn: () => client.api.getTemplateVersionRichParameters(versionId),
};
};
export const resources = (versionId: string) => {
return {
queryKey: ["templateVersion", versionId, "resources"],
queryFn: () => API.getTemplateVersionResources(versionId),
queryFn: () => client.api.getTemplateVersionResources(versionId),
};
};
@ -254,7 +258,7 @@ export const templateFiles = (fileId: string) => {
return {
queryKey: ["templateFiles", fileId],
queryFn: async () => {
const tarFile = await API.getFile(fileId);
const tarFile = await client.api.getFile(fileId);
return getTemplateVersionFiles(tarFile);
},
};
@ -274,7 +278,7 @@ export const previousTemplateVersion = (
"previous",
],
queryFn: async () => {
const result = await API.getPreviousTemplateVersionByName(
const result = await client.api.getPreviousTemplateVersionByName(
organizationId,
templateName,
versionName,
@ -294,7 +298,7 @@ const waitBuildToBeFinished = async (
do {
// When pending we want to poll more frequently
await delay(jobStatus === "pending" ? 250 : 1000);
data = await API.getTemplateVersion(version.id);
data = await client.api.getTemplateVersion(version.id);
onRequest?.(data);
jobStatus = data.job.status;

View File

@ -1,8 +1,8 @@
import * as API from "api/api";
import { client } from "api/api";
export const updateCheck = () => {
return {
queryKey: ["updateCheck"],
queryFn: () => API.getUpdateCheck(),
queryFn: () => client.api.getUpdateCheck(),
};
};

View File

@ -4,7 +4,7 @@ import type {
UseMutationOptions,
UseQueryOptions,
} from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type {
AuthorizationRequest,
GetUsersResponse,
@ -39,14 +39,14 @@ export function paginatedUsers(
},
queryKey: ({ payload }) => usersKey(payload),
queryFn: ({ payload, signal }) => API.getUsers(payload, signal),
queryFn: ({ payload, signal }) => client.api.getUsers(payload, signal),
};
}
export const users = (req: UsersRequest): UseQueryOptions<GetUsersResponse> => {
return {
queryKey: usersKey(req),
queryFn: ({ signal }) => API.getUsers(req, signal),
queryFn: ({ signal }) => client.api.getUsers(req, signal),
cacheTime: 5 * 1000 * 60,
};
};
@ -57,13 +57,13 @@ export const updatePassword = () => {
userId,
...request
}: UpdateUserPasswordRequest & { userId: string }) =>
API.updateUserPassword(userId, request),
client.api.updateUserPassword(userId, request),
};
};
export const createUser = (queryClient: QueryClient) => {
return {
mutationFn: API.createUser,
mutationFn: client.api.createUser,
onSuccess: async () => {
await queryClient.invalidateQueries(["users"]);
},
@ -72,13 +72,13 @@ export const createUser = (queryClient: QueryClient) => {
export const createFirstUser = () => {
return {
mutationFn: API.createFirstUser,
mutationFn: client.api.createFirstUser,
};
};
export const suspendUser = (queryClient: QueryClient) => {
return {
mutationFn: API.suspendUser,
mutationFn: client.api.suspendUser,
onSuccess: async () => {
await queryClient.invalidateQueries(["users"]);
},
@ -87,7 +87,7 @@ export const suspendUser = (queryClient: QueryClient) => {
export const activateUser = (queryClient: QueryClient) => {
return {
mutationFn: API.activateUser,
mutationFn: client.api.activateUser,
onSuccess: async () => {
await queryClient.invalidateQueries(["users"]);
},
@ -96,7 +96,7 @@ export const activateUser = (queryClient: QueryClient) => {
export const deleteUser = (queryClient: QueryClient) => {
return {
mutationFn: API.deleteUser,
mutationFn: client.api.deleteUser,
onSuccess: async () => {
await queryClient.invalidateQueries(["users"]);
},
@ -106,7 +106,7 @@ export const deleteUser = (queryClient: QueryClient) => {
export const updateRoles = (queryClient: QueryClient) => {
return {
mutationFn: ({ userId, roles }: { userId: string; roles: string[] }) =>
API.updateUserRoles(roles, userId),
client.api.updateUserRoles(roles, userId),
onSuccess: async () => {
await queryClient.invalidateQueries(["users"]);
},
@ -120,7 +120,7 @@ export const authMethods = () => {
// Even the endpoint being /users/authmethods we don't want to revalidate it
// when users change so its better add a unique query key
queryKey: ["authMethods"],
queryFn: API.getAuthMethods,
queryFn: client.api.getAuthMethods,
};
};
@ -132,14 +132,14 @@ export const me = (): UseQueryOptions<User> & {
return cachedQuery({
initialData: initialUserData,
queryKey: meKey,
queryFn: API.getAuthenticatedUser,
queryFn: client.api.getAuthenticatedUser,
});
};
export function apiKey(): UseQueryOptions<GenerateAPIKeyResponse> {
return {
queryKey: [...meKey, "apiKey"],
queryFn: () => API.getApiKey(),
queryFn: () => client.api.getApiKey(),
};
}
@ -148,7 +148,7 @@ export const hasFirstUser = (): UseQueryOptions<boolean> => {
// This cannot be false otherwise it will not fetch!
initialData: Boolean(initialUserData) || undefined,
queryKey: ["hasFirstUser"],
queryFn: API.hasFirstUser,
queryFn: client.api.hasFirstUser,
});
};
@ -178,10 +178,10 @@ const loginFn = async ({
password: string;
authorization: AuthorizationRequest;
}) => {
await API.login(email, password);
await client.api.login(email, password);
const [user, permissions] = await Promise.all([
API.getAuthenticatedUser(),
API.checkAuthorization(authorization),
client.api.getAuthenticatedUser(),
client.api.checkAuthorization(authorization),
]);
return {
user,
@ -191,7 +191,7 @@ const loginFn = async ({
export const logout = (queryClient: QueryClient) => {
return {
mutationFn: API.logout,
mutationFn: client.api.logout,
onSuccess: () => {
queryClient.removeQueries();
},
@ -201,7 +201,7 @@ export const logout = (queryClient: QueryClient) => {
export const updateProfile = (userId: string) => {
return {
mutationFn: (req: UpdateUserProfileRequest) =>
API.updateProfile(userId, req),
client.api.updateProfile(userId, req),
};
};
@ -215,7 +215,7 @@ export const updateAppearanceSettings = (
unknown
> => {
return {
mutationFn: (req) => API.updateAppearanceSettings(userId, req),
mutationFn: (req) => client.api.updateAppearanceSettings(userId, req),
onMutate: async (patch) => {
// Mutate the `queryClient` optimistically to make the theme switcher
// more responsive.

View File

@ -1,5 +1,5 @@
import type { QueryOptions, UseInfiniteQueryOptions } from "react-query";
import * as API from "api/api";
import { client } from "api/api";
import type {
WorkspaceBuild,
WorkspaceBuildParameter,
@ -13,7 +13,7 @@ export function workspaceBuildParametersKey(workspaceBuildId: string) {
export function workspaceBuildParameters(workspaceBuildId: string) {
return {
queryKey: workspaceBuildParametersKey(workspaceBuildId),
queryFn: () => API.getWorkspaceBuildParameters(workspaceBuildId),
queryFn: () => client.api.getWorkspaceBuildParameters(workspaceBuildId),
} as const satisfies QueryOptions<WorkspaceBuildParameter[]>;
}
@ -25,7 +25,11 @@ export const workspaceBuildByNumber = (
return {
queryKey: ["workspaceBuild", username, workspaceName, buildNumber],
queryFn: () =>
API.getWorkspaceBuildByNumber(username, workspaceName, buildNumber),
client.api.getWorkspaceBuildByNumber(
username,
workspaceName,
buildNumber,
),
};
};
@ -49,7 +53,7 @@ export const infiniteWorkspaceBuilds = (
return pages.length + 1;
},
queryFn: ({ pageParam = 0 }) => {
return API.getWorkspaceBuilds(workspaceId, {
return client.api.getWorkspaceBuilds(workspaceId, {
limit,
offset: pageParam <= 0 ? 0 : (pageParam - 1) * limit,
});

View File

@ -1,4 +1,4 @@
import * as API from "api/api";
import { client } from "api/api";
export const getWorkspaceQuotaQueryKey = (username: string) => [
username,
@ -8,7 +8,7 @@ export const getWorkspaceQuotaQueryKey = (username: string) => [
export const workspaceQuota = (username: string) => {
return {
queryKey: getWorkspaceQuotaQueryKey(username),
queryFn: () => API.getWorkspaceQuota(username),
queryFn: () => client.api.getWorkspaceQuota(username),
};
};
@ -20,6 +20,6 @@ export const getWorkspaceResolveAutostartQueryKey = (workspaceId: string) => [
export const workspaceResolveAutostart = (workspaceId: string) => {
return {
queryKey: getWorkspaceResolveAutostartQueryKey(workspaceId),
queryFn: () => API.getWorkspaceResolveAutostart(workspaceId),
queryFn: () => client.api.getWorkspaceResolveAutostart(workspaceId),
};
};

View File

@ -1,8 +1,4 @@
import {
deleteWorkspaceAgentSharedPort,
getWorkspaceAgentSharedPorts,
upsertWorkspaceAgentSharedPort,
} from "api/api";
import { client } from "api/api";
import type {
DeleteWorkspaceAgentPortShareRequest,
UpsertWorkspaceAgentPortShareRequest,
@ -11,14 +7,14 @@ import type {
export const workspacePortShares = (workspaceId: string) => {
return {
queryKey: ["sharedPorts", workspaceId],
queryFn: () => getWorkspaceAgentSharedPorts(workspaceId),
queryFn: () => client.api.getWorkspaceAgentSharedPorts(workspaceId),
};
};
export const upsertWorkspacePortShare = (workspaceId: string) => {
return {
mutationFn: async (options: UpsertWorkspaceAgentPortShareRequest) => {
await upsertWorkspaceAgentSharedPort(workspaceId, options);
await client.api.upsertWorkspaceAgentSharedPort(workspaceId, options);
},
};
};
@ -26,7 +22,7 @@ export const upsertWorkspacePortShare = (workspaceId: string) => {
export const deleteWorkspacePortShare = (workspaceId: string) => {
return {
mutationFn: async (options: DeleteWorkspaceAgentPortShareRequest) => {
await deleteWorkspaceAgentSharedPort(workspaceId, options);
await client.api.deleteWorkspaceAgentSharedPort(workspaceId, options);
},
};
};

View File

@ -4,8 +4,7 @@ import type {
QueryOptions,
UseMutationOptions,
} from "react-query";
import * as API from "api/api";
import { putWorkspaceExtension } from "api/api";
import { type DeleteWorkspaceOptions, client } from "api/api";
import type {
CreateWorkspaceRequest,
ProvisionerLogLevel,
@ -28,7 +27,9 @@ export const workspaceByOwnerAndName = (owner: string, name: string) => {
return {
queryKey: workspaceByOwnerAndNameKey(owner, name),
queryFn: () =>
API.getWorkspaceByOwnerAndName(owner, name, { include_deleted: true }),
client.api.getWorkspaceByOwnerAndName(owner, name, {
include_deleted: true,
}),
};
};
@ -49,7 +50,7 @@ export const createWorkspace = (queryClient: QueryClient) => {
return {
mutationFn: async (variables: CreateWorkspaceMutationVariables) => {
const { userId, organizationId, ...req } = variables;
return API.createWorkspace(organizationId, userId, req);
return client.api.createWorkspace(organizationId, userId, req);
},
onSuccess: async () => {
await queryClient.invalidateQueries(["workspaces"]);
@ -71,14 +72,14 @@ export const autoCreateWorkspace = (queryClient: QueryClient) => {
if (versionId) {
templateVersionParameters = { template_version_id: versionId };
} else {
const template = await API.getTemplateByName(
const template = await client.api.getTemplateByName(
organizationId,
templateName,
);
templateVersionParameters = { template_id: template.id };
}
return API.createWorkspace(organizationId, "me", {
return client.api.createWorkspace(organizationId, "me", {
...templateVersionParameters,
name: defaultName,
rich_parameter_values: defaultBuildParameters,
@ -102,7 +103,7 @@ export function workspaces(config: WorkspacesRequest = {}) {
return {
queryKey: workspacesKey(config),
queryFn: () => API.getWorkspaces({ q, limit }),
queryFn: () => client.api.getWorkspaces({ q, limit }),
} as const satisfies QueryOptions<WorkspacesResponse>;
}
@ -111,7 +112,7 @@ export const updateDeadline = (
): UseMutationOptions<void, unknown, Dayjs> => {
return {
mutationFn: (deadline: Dayjs) => {
return putWorkspaceExtension(workspace.id, deadline);
return client.api.putWorkspaceExtension(workspace.id, deadline);
},
};
};
@ -128,7 +129,11 @@ export const changeVersion = (
versionId: string;
buildParameters?: WorkspaceBuildParameter[];
}) => {
return API.changeWorkspaceVersion(workspace, versionId, buildParameters);
return client.api.changeWorkspaceVersion(
workspace,
versionId,
buildParameters,
);
},
onSuccess: async (build: WorkspaceBuild) => {
await updateWorkspaceBuild(build, queryClient);
@ -142,7 +147,7 @@ export const updateWorkspace = (
) => {
return {
mutationFn: (buildParameters?: WorkspaceBuildParameter[]) => {
return API.updateWorkspace(workspace, buildParameters);
return client.api.updateWorkspace(workspace, buildParameters);
},
onSuccess: async (build: WorkspaceBuild) => {
await updateWorkspaceBuild(build, queryClient);
@ -155,8 +160,8 @@ export const deleteWorkspace = (
queryClient: QueryClient,
) => {
return {
mutationFn: (options: API.DeleteWorkspaceOptions) => {
return API.deleteWorkspace(workspace.id, options);
mutationFn: (options: DeleteWorkspaceOptions) => {
return client.api.deleteWorkspace(workspace.id, options);
},
onSuccess: async (build: WorkspaceBuild) => {
await updateWorkspaceBuild(build, queryClient);
@ -170,7 +175,7 @@ export const stopWorkspace = (
) => {
return {
mutationFn: ({ logLevel }: { logLevel?: ProvisionerLogLevel }) => {
return API.stopWorkspace(workspace.id, logLevel);
return client.api.stopWorkspace(workspace.id, logLevel);
},
onSuccess: async (build: WorkspaceBuild) => {
await updateWorkspaceBuild(build, queryClient);
@ -190,7 +195,7 @@ export const startWorkspace = (
buildParameters?: WorkspaceBuildParameter[];
logLevel?: ProvisionerLogLevel;
}) => {
return API.startWorkspace(
return client.api.startWorkspace(
workspace.id,
workspace.latest_build.template_version_id,
logLevel,
@ -206,7 +211,7 @@ export const startWorkspace = (
export const cancelBuild = (workspace: Workspace, queryClient: QueryClient) => {
return {
mutationFn: () => {
return API.cancelWorkspaceBuild(workspace.latest_build.id);
return client.api.cancelWorkspaceBuild(workspace.latest_build.id);
},
onSuccess: async () => {
await queryClient.invalidateQueries({
@ -219,7 +224,7 @@ export const cancelBuild = (workspace: Workspace, queryClient: QueryClient) => {
export const activate = (workspace: Workspace, queryClient: QueryClient) => {
return {
mutationFn: () => {
return API.updateWorkspaceDormancy(workspace.id, false);
return client.api.updateWorkspaceDormancy(workspace.id, false);
},
onSuccess: (updatedWorkspace: Workspace) => {
queryClient.setQueryData(
@ -263,9 +268,9 @@ export const toggleFavorite = (
return {
mutationFn: () => {
if (workspace.favorite) {
return API.deleteFavoriteWorkspace(workspace.id);
return client.api.deleteFavoriteWorkspace(workspace.id);
} else {
return API.putFavoriteWorkspace(workspace.id);
return client.api.putFavoriteWorkspace(workspace.id);
}
},
onSuccess: async () => {

View File

@ -1,5 +1,5 @@
import type { FC } from "react";
import { getUsers } from "api/api";
import { client } from "api/api";
import { useAuthenticated } from "contexts/auth/RequireAuth";
import { UserAvatar } from "../UserAvatar/UserAvatar";
import { FilterSearchMenu, OptionItem } from "./filter";
@ -42,7 +42,7 @@ export const useUserFilterMenu = ({
};
}
const usersRes = await getUsers({ q: value, limit: 1 });
const usersRes = await client.api.getUsers({ q: value, limit: 1 });
const firstUser = usersRes.users.at(0);
if (firstUser && firstUser.username === value) {
return {
@ -54,7 +54,7 @@ export const useUserFilterMenu = ({
return null;
},
getOptions: async (query) => {
const usersRes = await getUsers({ q: query, limit: 25 });
const usersRes = await client.api.getUsers({ q: query, limit: 25 });
let options: UserOption[] = usersRes.users.map((user) => ({
label: user.username,
value: user.username,

View File

@ -8,7 +8,7 @@ import {
useState,
} from "react";
import { useQuery } from "react-query";
import { getWorkspaceProxies, getWorkspaceProxyRegions } from "api/api";
import { client } from "api/api";
import { cachedQuery } from "api/queries/util";
import type { Region, WorkspaceProxy } from "api/typesGenerated";
import { useAuthenticated } from "contexts/auth/RequireAuth";
@ -120,8 +120,8 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
const { permissions } = useAuthenticated();
const query = async (): Promise<readonly Region[]> => {
const endpoint = permissions.editWorkspaceProxies
? getWorkspaceProxies
: getWorkspaceProxyRegions;
? client.api.getWorkspaceProxies
: client.api.getWorkspaceProxyRegions;
const resp = await endpoint();
return resp.regions;
};

View File

@ -1,6 +1,6 @@
import { type FC, useEffect } from "react";
import { Outlet, Navigate, useLocation } from "react-router-dom";
import { axiosInstance } from "api/api";
import { client } from "api/api";
import { isApiError } from "api/errors";
import { Loader } from "components/Loader/Loader";
import { ProxyProvider } from "contexts/ProxyContext";
@ -22,6 +22,7 @@ export const RequireAuth: FC = () => {
return;
}
const axiosInstance = client.getAxiosInstance();
const interceptorHandle = axiosInstance.interceptors.response.use(
(okResponse) => okResponse,
(error: unknown) => {

View File

@ -1,6 +1,6 @@
import PerformanceObserver from "@fastly/performance-observer-polyfill";
import { useEffect, useReducer, useState } from "react";
import { axiosInstance } from "api/api";
import { client } from "api/api";
import type { Region } from "api/typesGenerated";
import { generateRandomString } from "utils/random";
@ -197,6 +197,7 @@ export const useProxyLatency = (
// The resource requests include xmlhttp requests.
observer.observe({ entryTypes: ["resource"] });
const axiosInstance = client.getAxiosInstance();
const proxyRequests = Object.keys(proxyChecks).map((latencyURL) => {
return axiosInstance.get(latencyURL, {
withCredentials: false,

View File

@ -4,7 +4,7 @@ import CircularProgress from "@mui/material/CircularProgress";
import Link from "@mui/material/Link";
import Tooltip from "@mui/material/Tooltip";
import { type FC, useState } from "react";
import { getApiKey } from "api/api";
import { client } from "api/api";
import type * as TypesGen from "api/typesGenerated";
import { useProxy } from "contexts/ProxyContext";
import { createAppLinkHref } from "utils/apps";
@ -145,7 +145,7 @@ export const AppLink: FC<AppLinkProps> = ({ app, workspace, agent }) => {
let url = href;
if (hasMagicToken !== -1) {
setFetchingSessionToken(true);
const key = await getApiKey();
const key = await client.api.getApiKey();
url = href.replaceAll(magicTokenString, key.key);
setFetchingSessionToken(false);
}

View File

@ -19,7 +19,7 @@ import { type FormikContextType, useFormik } from "formik";
import { useState, type FC } from "react";
import { useQuery, useMutation } from "react-query";
import * as Yup from "yup";
import { getAgentListeningPorts } from "api/api";
import { client } from "api/api";
import {
deleteWorkspacePortShare,
upsertWorkspacePortShare,
@ -70,7 +70,7 @@ export const PortForwardButton: FC<PortForwardButtonProps> = (props) => {
const portsQuery = useQuery({
queryKey: ["portForward", agent.id],
queryFn: () => getAgentListeningPorts(agent.id),
queryFn: () => client.api.getAgentListeningPorts(agent.id),
enabled: agent.status === "connected",
refetchInterval: 5_000,
});

View File

@ -3,7 +3,7 @@ import ButtonGroup from "@mui/material/ButtonGroup";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import { type FC, useState, useRef } from "react";
import { getApiKey } from "api/api";
import { client } from "api/api";
import type { DisplayApp } from "api/typesGenerated";
import { VSCodeIcon } from "components/Icons/VSCodeIcon";
import { VSCodeInsidersIcon } from "components/Icons/VSCodeInsidersIcon";
@ -119,7 +119,8 @@ const VSCodeButton: FC<VSCodeDesktopButtonProps> = ({
disabled={loading}
onClick={() => {
setLoading(true);
getApiKey()
client.api
.getApiKey()
.then(({ key }) => {
const query = new URLSearchParams({
owner: userName,
@ -163,7 +164,8 @@ const VSCodeInsidersButton: FC<VSCodeDesktopButtonProps> = ({
disabled={loading}
onClick={() => {
setLoading(true);
getApiKey()
client.api
.getApiKey()
.then(({ key }) => {
const query = new URLSearchParams({
owner: userName,

View File

@ -1,7 +1,7 @@
import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { HttpResponse, http } from "msw";
import * as API from "api/api";
import { client } from "api/api";
import { DEFAULT_RECORDS_PER_PAGE } from "components/PaginationWidget/utils";
import {
MockAuditLog,
@ -61,10 +61,12 @@ describe("AuditPage", () => {
it("renders page 5", async () => {
// Given
const page = 5;
const getAuditLogsSpy = jest.spyOn(API, "getAuditLogs").mockResolvedValue({
audit_logs: [MockAuditLog, MockAuditLog2],
count: 2,
});
const getAuditLogsSpy = jest
.spyOn(client.api, "getAuditLogs")
.mockResolvedValue({
audit_logs: [MockAuditLog, MockAuditLog2],
count: 2,
});
// When
await renderPage({ page: page });
@ -82,7 +84,7 @@ describe("AuditPage", () => {
describe("Filtering", () => {
it("filters by URL", async () => {
const getAuditLogsSpy = jest
.spyOn(API, "getAuditLogs")
.spyOn(client.api, "getAuditLogs")
.mockResolvedValue({ audit_logs: [MockAuditLog], count: 1 });
const query = "resource_type:workspace action:create";
@ -98,7 +100,7 @@ describe("AuditPage", () => {
it("resets page to 1 when filter is changed", async () => {
await renderPage({ page: 2 });
const getAuditLogsSpy = jest.spyOn(API, "getAuditLogs");
const getAuditLogsSpy = jest.spyOn(client.api, "getAuditLogs");
getAuditLogsSpy.mockClear();
const filterField = screen.getByLabelText("Filter");

View File

@ -1,6 +1,6 @@
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import {
MockTemplateExample,
MockTemplateVersion,
@ -35,14 +35,14 @@ test("Create template from starter template", async () => {
const { router, container } = await renderPage(searchParams);
const form = container.querySelector("form") as HTMLFormElement;
jest.spyOn(API, "createTemplateVersion").mockResolvedValueOnce({
jest.spyOn(client.api, "createTemplateVersion").mockResolvedValueOnce({
...MockTemplateVersion,
job: {
...MockTemplateVersion.job,
status: "pending",
},
});
jest.spyOn(API, "getTemplateVersion").mockResolvedValue({
jest.spyOn(client.api, "getTemplateVersion").mockResolvedValue({
...MockTemplateVersion,
job: {
...MockTemplateVersion.job,
@ -51,7 +51,7 @@ test("Create template from starter template", async () => {
},
});
jest
.spyOn(API, "getTemplateVersionVariables")
.spyOn(client.api, "getTemplateVersionVariables")
.mockResolvedValue([
MockTemplateVersionVariable1,
MockTemplateVersionVariable2,
@ -85,35 +85,42 @@ test("Create template from starter template", async () => {
// Setup the mock for the second template version creation before submit the form
jest.clearAllMocks();
jest
.spyOn(API, "createTemplateVersion")
.spyOn(client.api, "createTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest.spyOn(API, "getTemplateVersion").mockResolvedValue(MockTemplateVersion);
jest.spyOn(API, "createTemplate").mockResolvedValue(MockTemplate);
jest
.spyOn(client.api, "getTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest.spyOn(client.api, "createTemplate").mockResolvedValue(MockTemplate);
await userEvent.click(
within(form).getByRole("button", { name: /create template/i }),
);
await waitFor(() => expect(API.createTemplate).toBeCalledTimes(1));
await waitFor(() => expect(client.api.createTemplate).toBeCalledTimes(1));
expect(router.state.location.pathname).toEqual(
`/templates/${MockTemplate.name}/files`,
);
expect(API.createTemplateVersion).toHaveBeenCalledWith(MockOrganization.id, {
example_id: "aws-windows",
provisioner: "terraform",
storage_method: "file",
tags: {},
user_variable_values: [
{ name: "first_variable", value: "First value" },
{ name: "second_variable", value: "2" },
{ name: "third_variable", value: "true" },
],
});
expect(client.api.createTemplateVersion).toHaveBeenCalledWith(
MockOrganization.id,
{
example_id: "aws-windows",
provisioner: "terraform",
storage_method: "file",
tags: {},
user_variable_values: [
{ name: "first_variable", value: "First value" },
{ name: "second_variable", value: "2" },
{ name: "third_variable", value: "true" },
],
},
);
});
test("Create template from duplicating a template", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(API, "getTemplateVersion").mockResolvedValue(MockTemplateVersion);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
jest
.spyOn(API, "getTemplateVersionVariables")
.spyOn(client.api, "getTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest
.spyOn(client.api, "getTemplateVersionVariables")
.mockResolvedValue([MockTemplateVersionVariable1]);
const searchParams = new URLSearchParams({
@ -135,10 +142,12 @@ test("Create template from duplicating a template", async () => {
).toHaveValue(MockTemplateVersionVariable1.value);
// Create template
jest
.spyOn(API, "createTemplateVersion")
.spyOn(client.api, "createTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest.spyOn(API, "getTemplateVersion").mockResolvedValue(MockTemplateVersion);
jest.spyOn(API, "createTemplate").mockResolvedValue(MockTemplate);
jest
.spyOn(client.api, "getTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest.spyOn(client.api, "createTemplate").mockResolvedValue(MockTemplate);
await userEvent.click(
screen.getByRole("button", { name: /create template/i }),
);

View File

@ -1,6 +1,6 @@
import { screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import {
renderWithAuth,
waitForLoaderToBeRemoved,
@ -9,7 +9,7 @@ import { CreateTokenPage } from "./CreateTokenPage";
describe("TokenPage", () => {
it("shows the success modal", async () => {
jest.spyOn(API, "createToken").mockResolvedValueOnce({
jest.spyOn(client.api, "createToken").mockResolvedValueOnce({
key: "abcd",
});

View File

@ -3,7 +3,7 @@ import { type FC, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery } from "react-query";
import { useNavigate } from "react-router-dom";
import { createToken, getTokenConfig } from "api/api";
import { client } from "api/api";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { CodeExample } from "components/CodeExample/CodeExample";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
@ -28,7 +28,7 @@ export const CreateTokenPage: FC = () => {
isError: creationFailed,
isSuccess: creationSuccessful,
data: newToken,
} = useMutation(createToken);
} = useMutation(client.api.createToken);
const {
data: tokenConfig,
isLoading: fetchingTokenConfig,
@ -36,7 +36,7 @@ export const CreateTokenPage: FC = () => {
error: tokenFetchError,
} = useQuery({
queryKey: ["tokenconfig"],
queryFn: getTokenConfig,
queryFn: client.api.getTokenConfig,
});
const [formError, setFormError] = useState<unknown>(undefined);

View File

@ -1,6 +1,6 @@
import { fireEvent, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import {
MockTemplate,
MockUser,
@ -36,14 +36,16 @@ const renderCreateWorkspacePage = () => {
describe("CreateWorkspacePage", () => {
it("succeeds with default owner", async () => {
jest
.spyOn(API, "getUsers")
.spyOn(client.api, "getUsers")
.mockResolvedValueOnce({ users: [MockUser], count: 1 });
jest
.spyOn(API, "getWorkspaceQuota")
.spyOn(client.api, "getWorkspaceQuota")
.mockResolvedValueOnce(MockWorkspaceQuota);
jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(API, "getTemplateVersionRichParameters")
.spyOn(client.api, "createWorkspace")
.mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([MockTemplateVersionParameter1]);
renderCreateWorkspacePage();
@ -59,7 +61,7 @@ describe("CreateWorkspacePage", () => {
await userEvent.click(submitButton);
await waitFor(() =>
expect(API.createWorkspace).toBeCalledWith(
expect(client.api.createWorkspace).toBeCalledWith(
MockUser.organization_ids[0],
MockUser.id,
expect.objectContaining({
@ -73,7 +75,7 @@ describe("CreateWorkspacePage", () => {
const param = "first_parameter";
const paramValue = "It works!";
jest
.spyOn(API, "getTemplateVersionRichParameters")
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([MockTemplateVersionParameter1]);
renderWithAuth(<CreateWorkspacePage />, {
@ -89,7 +91,7 @@ describe("CreateWorkspacePage", () => {
it("rich parameter: number validation fails", async () => {
jest
.spyOn(API, "getTemplateVersionRichParameters")
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([
MockTemplateVersionParameter1,
MockTemplateVersionParameter2,
@ -124,7 +126,7 @@ describe("CreateWorkspacePage", () => {
it("rich parameter: string validation fails", async () => {
jest
.spyOn(API, "getTemplateVersionRichParameters")
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([
MockTemplateVersionParameter1,
MockTemplateVersionParameter3,
@ -157,14 +159,16 @@ describe("CreateWorkspacePage", () => {
});
it("rich parameter: number validation fails with custom error", async () => {
jest.spyOn(API, "getTemplateVersionRichParameters").mockResolvedValueOnce([
MockTemplateVersionParameter1,
{
...MockTemplateVersionParameter2,
validation_error: "These are values: {min}, {max}, and {value}.",
validation_monotonic: undefined, // only needs min-max rules
},
]);
jest
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([
MockTemplateVersionParameter1,
{
...MockTemplateVersionParameter2,
validation_error: "These are values: {min}, {max}, and {value}.",
validation_monotonic: undefined, // only needs min-max rules
},
]);
renderCreateWorkspacePage();
await waitForLoaderToBeRemoved();
@ -187,14 +191,16 @@ describe("CreateWorkspacePage", () => {
it("external auth authenticates and succeeds", async () => {
jest
.spyOn(API, "getWorkspaceQuota")
.spyOn(client.api, "getWorkspaceQuota")
.mockResolvedValueOnce(MockWorkspaceQuota);
jest
.spyOn(API, "getUsers")
.spyOn(client.api, "getUsers")
.mockResolvedValueOnce({ users: [MockUser], count: 1 });
jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(API, "getTemplateVersionExternalAuth")
.spyOn(client.api, "createWorkspace")
.mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(client.api, "getTemplateVersionExternalAuth")
.mockResolvedValue([MockTemplateVersionExternalAuthGithub]);
renderCreateWorkspacePage();
@ -210,7 +216,7 @@ describe("CreateWorkspacePage", () => {
await userEvent.click(githubButton);
jest
.spyOn(API, "getTemplateVersionExternalAuth")
.spyOn(client.api, "getTemplateVersionExternalAuth")
.mockResolvedValue([MockTemplateVersionExternalAuthGithubAuthenticated]);
await screen.findByText(
@ -223,7 +229,7 @@ describe("CreateWorkspacePage", () => {
await userEvent.click(submitButton);
await waitFor(() =>
expect(API.createWorkspace).toBeCalledWith(
expect(client.api.createWorkspace).toBeCalledWith(
MockUser.organization_ids[0],
MockUser.id,
expect.objectContaining({
@ -235,14 +241,16 @@ describe("CreateWorkspacePage", () => {
it("optional external auth is optional", async () => {
jest
.spyOn(API, "getWorkspaceQuota")
.spyOn(client.api, "getWorkspaceQuota")
.mockResolvedValueOnce(MockWorkspaceQuota);
jest
.spyOn(API, "getUsers")
.spyOn(client.api, "getUsers")
.mockResolvedValueOnce({ users: [MockUser], count: 1 });
jest.spyOn(API, "createWorkspace").mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(API, "getTemplateVersionExternalAuth")
.spyOn(client.api, "createWorkspace")
.mockResolvedValueOnce(MockWorkspace);
jest
.spyOn(client.api, "getTemplateVersionExternalAuth")
.mockResolvedValue([
{ ...MockTemplateVersionExternalAuthGithub, optional: true },
]);
@ -263,7 +271,7 @@ describe("CreateWorkspacePage", () => {
await userEvent.click(submitButton);
await waitFor(() =>
expect(API.createWorkspace).toBeCalledWith(
expect(client.api.createWorkspace).toBeCalledWith(
MockUser.organization_ids[0],
MockUser.id,
expect.objectContaining({
@ -276,7 +284,7 @@ describe("CreateWorkspacePage", () => {
it("auto create a workspace if uses mode=auto", async () => {
const param = "first_parameter";
const paramValue = "It works!";
const createWorkspaceSpy = jest.spyOn(API, "createWorkspace");
const createWorkspaceSpy = jest.spyOn(client.api, "createWorkspace");
renderWithAuth(<CreateWorkspacePage />, {
route:
@ -307,10 +315,10 @@ describe("CreateWorkspacePage", () => {
it("disables mode=auto if a required external auth provider is not connected", async () => {
const param = "first_parameter";
const paramValue = "It works!";
const createWorkspaceSpy = jest.spyOn(API, "createWorkspace");
const createWorkspaceSpy = jest.spyOn(client.api, "createWorkspace");
const externalAuthSpy = jest
.spyOn(API, "getTemplateVersionExternalAuth")
.spyOn(client.api, "getTemplateVersionExternalAuth")
.mockResolvedValue([MockTemplateVersionExternalAuthGithub]);
renderWithAuth(<CreateWorkspacePage />, {
@ -336,7 +344,7 @@ describe("CreateWorkspacePage", () => {
it("auto create a workspace if uses mode=auto and version=version-id", async () => {
const param = "first_parameter";
const paramValue = "It works!";
const createWorkspaceSpy = jest.spyOn(API, "createWorkspace");
const createWorkspaceSpy = jest.spyOn(client.api, "createWorkspace");
renderWithAuth(<CreateWorkspacePage />, {
route:

View File

@ -2,7 +2,7 @@ import { type FC, useCallback, useEffect, useState, useRef } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { getUserParameters } from "api/api";
import { client } from "api/api";
import type { ApiErrorResponse } from "api/errors";
import { checkAuthorization } from "api/queries/authCheck";
import {
@ -99,7 +99,7 @@ const CreateWorkspacePage: FC = () => {
const autofillEnabled = experiments.includes("auto-fill-parameters");
const userParametersQuery = useQuery({
queryKey: ["userParameters"],
queryFn: () => getUserParameters(templateQuery.data!.id),
queryFn: () => client.api.getUserParameters(templateQuery.data!.id),
enabled: autofillEnabled && templateQuery.isSuccess,
});
const autofillParameters = getAutofillParameters(

View File

@ -2,7 +2,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation } from "react-query";
import { useNavigate } from "react-router-dom";
import { createLicense } from "api/api";
import { client } from "api/api";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import { pageTitle } from "utils/page";
import { AddNewLicensePageView } from "./AddNewLicensePageView";
@ -14,7 +14,7 @@ const AddNewLicensePage: FC = () => {
mutate: saveLicenseKeyApi,
isLoading: isCreating,
error: savingLicenseError,
} = useMutation(createLicense, {
} = useMutation(client.api.createLicense, {
onSuccess: () => {
displaySuccess("You have successfully added a license");
navigate("/deployment/licenses?success=true");

View File

@ -3,7 +3,7 @@ import { Helmet } from "react-helmet-async";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useSearchParams } from "react-router-dom";
import useToggle from "react-use/lib/useToggle";
import { getLicenses, removeLicense } from "api/api";
import { client } from "api/api";
import { getErrorMessage } from "api/errors";
import { entitlements, refreshEntitlements } from "api/queries/entitlements";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
@ -32,7 +32,7 @@ const LicensesSettingsPage: FC = () => {
}, [entitlementsQuery.error]);
const { mutate: removeLicenseApi, isLoading: isRemovingLicense } =
useMutation(removeLicense, {
useMutation(client.api.removeLicense, {
onSuccess: () => {
displaySuccess("Successfully removed license");
void queryClient.invalidateQueries(["licenses"]);
@ -44,7 +44,7 @@ const LicensesSettingsPage: FC = () => {
const { data: licenses, isLoading } = useQuery({
queryKey: ["licenses"],
queryFn: () => getLicenses(),
queryFn: () => client.api.getLicenses(),
});
useEffect(() => {

View File

@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import { TemplateLayout } from "pages/TemplatePage/TemplateLayout";
import {
MockTemplate,
@ -15,7 +15,7 @@ import TemplateEmbedPage from "./TemplateEmbedPage";
test("Users can fill the parameters and copy the open in coder url", async () => {
jest
.spyOn(API, "getTemplateVersionRichParameters")
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValue([parameter1, parameter2]);
renderWithAuth(

View File

@ -7,7 +7,7 @@ import RadioGroup from "@mui/material/RadioGroup";
import { type FC, useEffect, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useQuery } from "react-query";
import { getTemplateVersionRichParameters } from "api/api";
import { client } from "api/api";
import type { Template, TemplateVersionParameter } from "api/typesGenerated";
import { FormSection, VerticalForm } from "components/Form/Form";
import { Loader } from "components/Loader/Loader";
@ -24,7 +24,8 @@ const TemplateEmbedPage: FC = () => {
const { template } = useTemplateLayoutContext();
const { data: templateParameters } = useQuery({
queryKey: ["template", template.id, "embed"],
queryFn: () => getTemplateVersionRichParameters(template.active_version_id),
queryFn: () =>
client.api.getTemplateVersionRichParameters(template.active_version_id),
});
return (

View File

@ -7,11 +7,7 @@ import {
} from "react";
import { useQuery } from "react-query";
import { Outlet, useLocation, useNavigate, useParams } from "react-router-dom";
import {
checkAuthorization,
getTemplateByName,
getTemplateVersion,
} from "api/api";
import { client } from "api/api";
import type { AuthorizationRequest } from "api/typesGenerated";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { Loader } from "components/Loader/Loader";
@ -39,10 +35,14 @@ const templatePermissions = (
});
const fetchTemplate = async (organizationId: string, templateName: string) => {
const template = await getTemplateByName(organizationId, templateName);
const template = await client.api.getTemplateByName(
organizationId,
templateName,
);
const [activeVersion, permissions] = await Promise.all([
getTemplateVersion(template.active_version_id),
checkAuthorization({
client.api.getTemplateVersion(template.active_version_id),
client.api.checkAuthorization({
checks: templatePermissions(template.id),
}),
]);

View File

@ -1,7 +1,7 @@
import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useQuery } from "react-query";
import { getTemplateVersionResources } from "api/api";
import { client } from "api/api";
import { useTemplateLayoutContext } from "pages/TemplatePage/TemplateLayout";
import { getTemplatePageTitle } from "../utils";
import { TemplateSummaryPageView } from "./TemplateSummaryPageView";
@ -10,7 +10,7 @@ export const TemplateSummaryPage: FC = () => {
const { template, activeVersion } = useTemplateLayoutContext();
const { data: resources } = useQuery({
queryKey: ["templates", template.id, "resources"],
queryFn: () => getTemplateVersionResources(activeVersion.id),
queryFn: () => client.api.getTemplateVersionResources(activeVersion.id),
});
return (

View File

@ -1,11 +1,7 @@
import { useState } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery } from "react-query";
import {
archiveTemplateVersion,
getTemplateVersions,
updateActiveTemplateVersion,
} from "api/api";
import { client } from "api/api";
import { getErrorMessage } from "api/errors";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
@ -17,7 +13,7 @@ const TemplateVersionsPage = () => {
const { template, permissions } = useTemplateLayoutContext();
const { data } = useQuery({
queryKey: ["template", "versions", template.id],
queryFn: () => getTemplateVersions(template.id),
queryFn: () => client.api.getTemplateVersions(template.id),
});
// We use this to update the active version in the UI without having to refetch the template
const [latestActiveVersion, setLatestActiveVersion] = useState(
@ -25,7 +21,7 @@ const TemplateVersionsPage = () => {
);
const { mutate: promoteVersion, isLoading: isPromoting } = useMutation({
mutationFn: (templateVersionId: string) => {
return updateActiveTemplateVersion(template.id, {
return client.api.updateActiveTemplateVersion(template.id, {
id: templateVersionId,
});
},
@ -41,7 +37,7 @@ const TemplateVersionsPage = () => {
const { mutate: archiveVersion, isLoading: isArchiving } = useMutation({
mutationFn: (templateVersionId: string) => {
return archiveTemplateVersion(templateVersionId);
return client.api.archiveTemplateVersion(templateVersionId);
},
onSuccess: async () => {
// The reload is unfortunate. When a version is archived, we should hide

View File

@ -1,5 +1,5 @@
import { act, renderHook, waitFor } from "@testing-library/react";
import * as API from "api/api";
import { client } from "api/api";
import { MockTemplate } from "testHelpers/entities";
import { useDeletionDialogState } from "./useDeletionDialogState";
@ -23,9 +23,9 @@ test("confirm template deletion", async () => {
expect(result.current.isDeleteDialogOpen).toBeTruthy();
// Confirm delete
jest.spyOn(API, "deleteTemplate");
jest.spyOn(client.api, "deleteTemplate");
await act(async () => result.current.confirmDelete());
await waitFor(() => expect(API.deleteTemplate).toBeCalledTimes(1));
await waitFor(() => expect(client.api.deleteTemplate).toBeCalledTimes(1));
expect(onDeleteTemplate).toBeCalledTimes(1);
});

View File

@ -1,5 +1,5 @@
import { useState } from "react";
import { deleteTemplate } from "api/api";
import { client } from "api/api";
import { getErrorMessage } from "api/errors";
import { displayError } from "components/GlobalSnackbar/utils";
@ -27,7 +27,7 @@ export const useDeletionDialogState = (
const confirmDelete = async () => {
try {
setState({ status: "deleting" });
await deleteTemplate(templateId);
await client.api.deleteTemplate(templateId);
onDelete();
} catch (e) {
setState({ status: "confirming" });

View File

@ -1,7 +1,7 @@
import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { http, HttpResponse } from "msw";
import * as API from "api/api";
import { client, withDefaultFeatures } from "api/api";
import type { Template, UpdateTemplateMeta } from "api/typesGenerated";
import { Language as FooterFormLanguage } from "components/FormFooter/FormFooter";
import { MockEntitlements, MockTemplate } from "testHelpers/entities";
@ -104,12 +104,14 @@ const fillAndSubmitForm = async ({
describe("TemplateSettingsPage", () => {
it("succeeds", async () => {
await renderTemplateSettingsPage();
jest.spyOn(API, "updateTemplateMeta").mockResolvedValueOnce({
jest.spyOn(client.api, "updateTemplateMeta").mockResolvedValueOnce({
...MockTemplate,
...validFormValues,
});
await fillAndSubmitForm(validFormValues);
await waitFor(() => expect(API.updateTemplateMeta).toBeCalledTimes(1));
await waitFor(() =>
expect(client.api.updateTemplateMeta).toBeCalledTimes(1),
);
});
it("allows a description of 128 chars", () => {
@ -138,13 +140,16 @@ describe("TemplateSettingsPage", () => {
http.get("/api/v2/entitlements", () => {
return HttpResponse.json({
...MockEntitlements,
features: API.withDefaultFeatures({
features: withDefaultFeatures({
access_control: { enabled: true, entitlement: "entitled" },
}),
});
}),
);
const updateTemplateMetaSpy = jest.spyOn(API, "updateTemplateMeta");
const updateTemplateMetaSpy = jest.spyOn(
client.api,
"updateTemplateMeta",
);
const deprecationMessage = "This template is deprecated";
await renderTemplateSettingsPage();
@ -163,13 +168,16 @@ describe("TemplateSettingsPage", () => {
http.get("/api/v2/entitlements", () => {
return HttpResponse.json({
...MockEntitlements,
features: API.withDefaultFeatures({
features: withDefaultFeatures({
access_control: { enabled: false, entitlement: "not_entitled" },
}),
});
}),
);
const updateTemplateMetaSpy = jest.spyOn(API, "updateTemplateMeta");
const updateTemplateMetaSpy = jest.spyOn(
client.api,
"updateTemplateMeta",
);
await renderTemplateSettingsPage();
await deprecateTemplate(

View File

@ -2,7 +2,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQueryClient } from "react-query";
import { useNavigate, useParams } from "react-router-dom";
import { updateTemplateMeta } from "api/api";
import { client } from "api/api";
import { templateByNameKey } from "api/queries/templates";
import type { UpdateTemplateMeta } from "api/typesGenerated";
import { displaySuccess } from "components/GlobalSnackbar/utils";
@ -31,7 +31,9 @@ export const TemplateSettingsPage: FC = () => {
isLoading: isSubmitting,
error: submitError,
} = useMutation(
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
(data: UpdateTemplateMeta) => {
return client.api.updateTemplateMeta(template.id, data);
},
{
onSuccess: async (data) => {
// This update has a chance to return a 304 which means nothing was updated.

View File

@ -1,6 +1,6 @@
import { screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import { Language as FooterFormLanguage } from "components/FormFooter/FormFooter";
import {
MockEntitlementsWithScheduling,
@ -127,38 +127,38 @@ function waitForWithCutoff(callback: () => void | Promise<void>) {
describe("TemplateSchedulePage", () => {
beforeEach(() => {
jest
.spyOn(API, "getEntitlements")
.spyOn(client.api, "getEntitlements")
.mockResolvedValue(MockEntitlementsWithScheduling);
});
it("Calls the API when user fills in and submits a form", async () => {
await renderTemplateSchedulePage();
jest.spyOn(API, "updateTemplateMeta").mockResolvedValueOnce({
jest.spyOn(client.api, "updateTemplateMeta").mockResolvedValueOnce({
...MockTemplate,
...validFormValues,
});
await fillAndSubmitForm(validFormValues);
await waitForWithCutoff(() =>
expect(API.updateTemplateMeta).toBeCalledTimes(1),
expect(client.api.updateTemplateMeta).toBeCalledTimes(1),
);
});
test("default is converted to and from hours", async () => {
await renderTemplateSchedulePage();
jest.spyOn(API, "updateTemplateMeta").mockResolvedValueOnce({
jest.spyOn(client.api, "updateTemplateMeta").mockResolvedValueOnce({
...MockTemplate,
...validFormValues,
});
await fillAndSubmitForm(validFormValues);
await waitForWithCutoff(() =>
expect(API.updateTemplateMeta).toBeCalledTimes(1),
expect(client.api.updateTemplateMeta).toBeCalledTimes(1),
);
await waitForWithCutoff(() => {
expect(API.updateTemplateMeta).toBeCalledWith(
expect(client.api.updateTemplateMeta).toBeCalledWith(
"test-template",
expect.objectContaining({
default_ttl_ms: (validFormValues.default_ttl_ms || 0) * 3600000,
@ -170,18 +170,18 @@ describe("TemplateSchedulePage", () => {
test("failure, dormancy, and dormancy auto-deletion converted to and from days", async () => {
await renderTemplateSchedulePage();
jest.spyOn(API, "updateTemplateMeta").mockResolvedValueOnce({
jest.spyOn(client.api, "updateTemplateMeta").mockResolvedValueOnce({
...MockTemplate,
...validFormValues,
});
await fillAndSubmitForm(validFormValues);
await waitForWithCutoff(() =>
expect(API.updateTemplateMeta).toBeCalledTimes(1),
expect(client.api.updateTemplateMeta).toBeCalledTimes(1),
);
await waitForWithCutoff(() => {
expect(API.updateTemplateMeta).toBeCalledWith(
expect(client.api.updateTemplateMeta).toBeCalledWith(
"test-template",
expect.objectContaining({
failure_ttl_ms: (validFormValues.failure_ttl_ms || 0) * 86400000,

View File

@ -2,7 +2,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQueryClient } from "react-query";
import { useNavigate, useParams } from "react-router-dom";
import { updateTemplateMeta } from "api/api";
import { client } from "api/api";
import { templateByNameKey } from "api/queries/templates";
import type { UpdateTemplateMeta } from "api/typesGenerated";
import { displaySuccess } from "components/GlobalSnackbar/utils";
@ -27,7 +27,8 @@ const TemplateSchedulePage: FC = () => {
isLoading: isSubmitting,
error: submitError,
} = useMutation(
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
(data: UpdateTemplateMeta) =>
client.api.updateTemplateMeta(template.id, data),
{
onSuccess: async () => {
await queryClient.invalidateQueries(

View File

@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import { Language as FooterFormLanguage } from "components/FormFooter/FormFooter";
import {
MockTemplate,
@ -32,12 +32,14 @@ const renderTemplateVariablesPage = async () => {
describe("TemplateVariablesPage", () => {
it("renders with variables", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValueOnce(MockTemplate);
jest
.spyOn(API, "getTemplateVersion")
.spyOn(client.api, "getTemplateByName")
.mockResolvedValueOnce(MockTemplate);
jest
.spyOn(client.api, "getTemplateVersion")
.mockResolvedValueOnce(MockTemplateVersion);
jest
.spyOn(API, "getTemplateVersionVariables")
.spyOn(client.api, "getTemplateVersionVariables")
.mockResolvedValueOnce([
MockTemplateVersionVariable1,
MockTemplateVersionVariable2,
@ -57,22 +59,26 @@ describe("TemplateVariablesPage", () => {
});
it("user submits the form successfully", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValueOnce(MockTemplate);
jest
.spyOn(API, "getTemplateVersion")
.spyOn(client.api, "getTemplateByName")
.mockResolvedValueOnce(MockTemplate);
jest
.spyOn(client.api, "getTemplateVersion")
.mockResolvedValue(MockTemplateVersion);
jest
.spyOn(API, "getTemplateVersionVariables")
.spyOn(client.api, "getTemplateVersionVariables")
.mockResolvedValueOnce([
MockTemplateVersionVariable1,
MockTemplateVersionVariable2,
]);
jest
.spyOn(API, "createTemplateVersion")
.spyOn(client.api, "createTemplateVersion")
.mockResolvedValueOnce(MockTemplateVersion2);
jest.spyOn(API, "updateActiveTemplateVersion").mockResolvedValueOnce({
message: "done",
});
jest
.spyOn(client.api, "updateActiveTemplateVersion")
.mockResolvedValueOnce({
message: "done",
});
await renderTemplateVariablesPage();

View File

@ -26,6 +26,8 @@ import type { MonacoEditorProps } from "./MonacoEditor";
import { Language } from "./PublishTemplateVersionDialog";
import TemplateVersionEditorPage from "./TemplateVersionEditorPage";
const { client } = api;
// For some reason this component in Jest is throwing a MUI style warning so,
// since we don't need it for this test, we can mock it out
jest.mock(
@ -72,8 +74,8 @@ const buildTemplateVersion = async (
user: UserEvent,
topbar: HTMLElement,
) => {
jest.spyOn(api, "uploadFile").mockResolvedValueOnce({ hash: "hash" });
jest.spyOn(api, "createTemplateVersion").mockResolvedValue({
jest.spyOn(client.api, "uploadFile").mockResolvedValueOnce({ hash: "hash" });
jest.spyOn(client.api, "createTemplateVersion").mockResolvedValue({
...templateVersion,
job: {
...templateVersion.job,
@ -81,7 +83,7 @@ const buildTemplateVersion = async (
},
});
jest
.spyOn(api, "getTemplateVersionByName")
.spyOn(client.api, "getTemplateVersionByName")
.mockResolvedValue(templateVersion);
jest
.spyOn(api, "watchBuildLogsByTemplateVersionId")
@ -116,10 +118,10 @@ test("Use custom name, message and set it as active when publishing", async () =
// Publish
const patchTemplateVersion = jest
.spyOn(api, "patchTemplateVersion")
.spyOn(client.api, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const updateActiveTemplateVersion = jest
.spyOn(api, "updateActiveTemplateVersion")
.spyOn(client.api, "updateActiveTemplateVersion")
.mockResolvedValue({ message: "" });
const publishButton = within(topbar).getByRole("button", {
name: "Publish",
@ -162,10 +164,10 @@ test("Do not mark as active if promote is not checked", async () => {
// Publish
const patchTemplateVersion = jest
.spyOn(api, "patchTemplateVersion")
.spyOn(client.api, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const updateActiveTemplateVersion = jest
.spyOn(api, "updateActiveTemplateVersion")
.spyOn(client.api, "updateActiveTemplateVersion")
.mockResolvedValue({ message: "" });
const publishButton = within(topbar).getByRole("button", {
name: "Publish",
@ -207,7 +209,7 @@ test("Patch request is not send when there are no changes", async () => {
// Publish
const patchTemplateVersion = jest
.spyOn(api, "patchTemplateVersion")
.spyOn(client.api, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const publishButton = within(topbar).getByRole("button", {
name: "Publish",

View File

@ -2,7 +2,7 @@ import { type FC, useEffect, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
import { patchTemplateVersion, updateActiveTemplateVersion } from "api/api";
import { client } from "api/api";
import { file, uploadFile } from "api/queries/files";
import {
createTemplateVersion,
@ -323,12 +323,12 @@ const publishVersion = async (options: {
const publishActions: Promise<unknown>[] = [];
if (haveChanges) {
publishActions.push(patchTemplateVersion(version.id, data));
publishActions.push(client.api.patchTemplateVersion(version.id, data));
}
if (isActiveVersion) {
publishActions.push(
updateActiveTemplateVersion(version.template_id!, {
client.api.updateActiveTemplateVersion(version.template_id!, {
id: version.id,
}),
);

View File

@ -2,7 +2,7 @@ import "jest-canvas-mock";
import { waitFor } from "@testing-library/react";
import WS from "jest-websocket-mock";
import { HttpResponse, http } from "msw";
import * as API from "api/api";
import { client } from "api/api";
import {
MockUser,
MockWorkspace,
@ -56,7 +56,7 @@ describe("TerminalPage", () => {
it("loads the right workspace data", async () => {
jest
.spyOn(API, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValue(MockWorkspace);
new WS(
`ws://localhost/api/v2/workspaceagents/${MockWorkspaceAgent.id}/pty`,
@ -65,7 +65,7 @@ describe("TerminalPage", () => {
`/${MockUser.username}/${MockWorkspace.name}/terminal`,
);
await waitFor(() => {
expect(API.getWorkspaceByOwnerAndName).toHaveBeenCalledWith(
expect(client.api.getWorkspaceByOwnerAndName).toHaveBeenCalledWith(
MockUser.username,
MockWorkspace.name,
{ include_deleted: true },

View File

@ -1,5 +1,5 @@
import { fireEvent, screen, waitFor } from "@testing-library/react";
import * as API from "api/api";
import { client } from "api/api";
import { mockApiError } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import * as AccountForm from "./AccountForm";
@ -25,34 +25,36 @@ const fillAndSubmitForm = async () => {
describe("AccountPage", () => {
describe("when it is a success", () => {
it("shows the success message", async () => {
jest.spyOn(API, "updateProfile").mockImplementationOnce((userId, data) =>
Promise.resolve({
id: userId,
email: "user@coder.com",
created_at: new Date().toISOString(),
status: "active",
organization_ids: ["123"],
roles: [],
avatar_url: "",
last_seen_at: new Date().toISOString(),
login_type: "password",
theme_preference: "",
...data,
}),
);
jest
.spyOn(client.api, "updateProfile")
.mockImplementationOnce((userId, data) =>
Promise.resolve({
id: userId,
email: "user@coder.com",
created_at: new Date().toISOString(),
status: "active",
organization_ids: ["123"],
roles: [],
avatar_url: "",
last_seen_at: new Date().toISOString(),
login_type: "password",
theme_preference: "",
...data,
}),
);
renderWithAuth(<AccountPage />);
await fillAndSubmitForm();
const successMessage = await screen.findByText("Updated settings.");
expect(successMessage).toBeDefined();
expect(API.updateProfile).toBeCalledTimes(1);
expect(API.updateProfile).toBeCalledWith("me", newData);
expect(client.api.updateProfile).toBeCalledTimes(1);
expect(client.api.updateProfile).toBeCalledWith("me", newData);
});
});
describe("when the username is already taken", () => {
it("shows an error", async () => {
jest.spyOn(API, "updateProfile").mockRejectedValueOnce(
jest.spyOn(client.api, "updateProfile").mockRejectedValueOnce(
mockApiError({
message: "Invalid profile",
validations: [
@ -68,14 +70,14 @@ describe("AccountPage", () => {
"Username is already in use",
);
expect(errorMessage).toBeDefined();
expect(API.updateProfile).toBeCalledTimes(1);
expect(API.updateProfile).toBeCalledWith("me", newData);
expect(client.api.updateProfile).toBeCalledTimes(1);
expect(client.api.updateProfile).toBeCalledWith("me", newData);
});
});
describe("when it is an unknown error", () => {
it("shows a generic error message", async () => {
jest.spyOn(API, "updateProfile").mockRejectedValueOnce({
jest.spyOn(client.api, "updateProfile").mockRejectedValueOnce({
data: "unknown error",
});
@ -84,8 +86,8 @@ describe("AccountPage", () => {
const errorMessage = await screen.findByText("Something went wrong.");
expect(errorMessage).toBeDefined();
expect(API.updateProfile).toBeCalledTimes(1);
expect(API.updateProfile).toBeCalledWith("me", newData);
expect(client.api.updateProfile).toBeCalledTimes(1);
expect(client.api.updateProfile).toBeCalledWith("me", newData);
});
});
});

View File

@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import { MockUser } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import { AppearancePage } from "./AppearancePage";
@ -9,7 +9,7 @@ describe("appearance page", () => {
it("does nothing when selecting current theme", async () => {
renderWithAuth(<AppearancePage />);
jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({
jest.spyOn(client.api, "updateAppearanceSettings").mockResolvedValueOnce({
...MockUser,
theme_preference: "dark",
});
@ -18,13 +18,13 @@ describe("appearance page", () => {
await userEvent.click(dark);
// Check if the API was called correctly
expect(API.updateAppearanceSettings).toBeCalledTimes(0);
expect(client.api.updateAppearanceSettings).toBeCalledTimes(0);
});
it("changes theme to dark blue", async () => {
renderWithAuth(<AppearancePage />);
jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({
jest.spyOn(client.api, "updateAppearanceSettings").mockResolvedValueOnce({
...MockUser,
theme_preference: "darkBlue",
});
@ -33,8 +33,8 @@ describe("appearance page", () => {
await userEvent.click(darkBlue);
// Check if the API was called correctly
expect(API.updateAppearanceSettings).toBeCalledTimes(1);
expect(API.updateAppearanceSettings).toHaveBeenCalledWith("me", {
expect(client.api.updateAppearanceSettings).toBeCalledTimes(1);
expect(client.api.updateAppearanceSettings).toHaveBeenCalledWith("me", {
theme_preference: "darkBlue",
});
});
@ -42,7 +42,7 @@ describe("appearance page", () => {
it("changes theme to light", async () => {
renderWithAuth(<AppearancePage />);
jest.spyOn(API, "updateAppearanceSettings").mockResolvedValueOnce({
jest.spyOn(client.api, "updateAppearanceSettings").mockResolvedValueOnce({
...MockUser,
theme_preference: "light",
});
@ -51,8 +51,8 @@ describe("appearance page", () => {
await userEvent.click(light);
// Check if the API was called correctly
expect(API.updateAppearanceSettings).toBeCalledTimes(1);
expect(API.updateAppearanceSettings).toHaveBeenCalledWith("me", {
expect(client.api.updateAppearanceSettings).toBeCalledTimes(1);
expect(client.api.updateAppearanceSettings).toHaveBeenCalledWith("me", {
theme_preference: "light",
});
});

View File

@ -1,5 +1,5 @@
import { fireEvent, screen, within } from "@testing-library/react";
import * as API from "api/api";
import { client } from "api/api";
import { MockGitSSHKey, mockApiError } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import { Language as SSHKeysPageLanguage, SSHKeysPage } from "./SSHKeysPage";
@ -28,7 +28,7 @@ describe("SSH keys Page", () => {
const newUserSSHKey =
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDSC/ouD/LqiT1Rd99vDv/MwUmqzJuinLTMTpk5kVy66";
jest.spyOn(API, "regenerateUserSSHKey").mockResolvedValueOnce({
jest.spyOn(client.api, "regenerateUserSSHKey").mockResolvedValueOnce({
...MockGitSSHKey,
public_key: newUserSSHKey,
});
@ -43,7 +43,7 @@ describe("SSH keys Page", () => {
await screen.findByText("SSH Key regenerated successfully.");
// Check if the API was called correctly
expect(API.regenerateUserSSHKey).toBeCalledTimes(1);
expect(client.api.regenerateUserSSHKey).toBeCalledTimes(1);
// Check if the SSH key is updated
await screen.findByText(newUserSSHKey);
@ -57,7 +57,7 @@ describe("SSH keys Page", () => {
// Wait to the ssh be rendered on the screen
await screen.findByText(MockGitSSHKey.public_key);
jest.spyOn(API, "regenerateUserSSHKey").mockRejectedValueOnce(
jest.spyOn(client.api, "regenerateUserSSHKey").mockRejectedValueOnce(
mockApiError({
message: SSHKeysPageLanguage.regenerationError,
}),
@ -82,7 +82,7 @@ describe("SSH keys Page", () => {
expect(alert).toHaveTextContent(SSHKeysPageLanguage.regenerationError);
// Check if the API was called correctly
expect(API.regenerateUserSSHKey).toBeCalledTimes(1);
expect(client.api.regenerateUserSSHKey).toBeCalledTimes(1);
});
});
});

View File

@ -1,6 +1,6 @@
import { fireEvent, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { client } from "api/api";
import type { OAuthConversionResponse } from "api/typesGenerated";
import { MockAuthMethodsAll, mockApiError } from "testHelpers/entities";
import {
@ -37,29 +37,34 @@ const fillAndSubmitSecurityForm = () => {
};
beforeEach(() => {
jest.spyOn(API, "getAuthMethods").mockResolvedValue(MockAuthMethodsAll);
jest.spyOn(API, "getUserLoginType").mockResolvedValue({
jest
.spyOn(client.api, "getAuthMethods")
.mockResolvedValue(MockAuthMethodsAll);
jest.spyOn(client.api, "getUserLoginType").mockResolvedValue({
login_type: "password",
});
});
test("update password successfully", async () => {
jest
.spyOn(API, "updateUserPassword")
.spyOn(client.api, "updateUserPassword")
.mockImplementationOnce((_userId, _data) => Promise.resolve(undefined));
const { user } = await renderPage();
fillAndSubmitSecurityForm();
const successMessage = await screen.findByText("Updated password.");
expect(successMessage).toBeDefined();
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(user.id, newSecurityFormValues);
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(
user.id,
newSecurityFormValues,
);
await waitFor(() => expect(window.location).toBeAt("/"));
});
test("update password with incorrect old password", async () => {
jest.spyOn(API, "updateUserPassword").mockRejectedValueOnce(
jest.spyOn(client.api, "updateUserPassword").mockRejectedValueOnce(
mockApiError({
message: "Incorrect password.",
validations: [{ detail: "Incorrect password.", field: "old_password" }],
@ -72,12 +77,15 @@ test("update password with incorrect old password", async () => {
const errorMessage = await screen.findAllByText("Incorrect password.");
expect(errorMessage).toBeDefined();
expect(errorMessage).toHaveLength(2);
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(user.id, newSecurityFormValues);
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(
user.id,
newSecurityFormValues,
);
});
test("update password with invalid password", async () => {
jest.spyOn(API, "updateUserPassword").mockRejectedValueOnce(
jest.spyOn(client.api, "updateUserPassword").mockRejectedValueOnce(
mockApiError({
message: "Invalid password.",
validations: [{ detail: "Invalid password.", field: "password" }],
@ -90,12 +98,15 @@ test("update password with invalid password", async () => {
const errorMessage = await screen.findAllByText("Invalid password.");
expect(errorMessage).toBeDefined();
expect(errorMessage).toHaveLength(2);
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(user.id, newSecurityFormValues);
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(
user.id,
newSecurityFormValues,
);
});
test("update password when submit returns an unknown error", async () => {
jest.spyOn(API, "updateUserPassword").mockRejectedValueOnce({
jest.spyOn(client.api, "updateUserPassword").mockRejectedValueOnce({
data: "unknown error",
});
@ -104,15 +115,18 @@ test("update password when submit returns an unknown error", async () => {
const errorMessage = await screen.findByText("Something went wrong.");
expect(errorMessage).toBeDefined();
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(user.id, newSecurityFormValues);
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(
user.id,
newSecurityFormValues,
);
});
test("change login type to OIDC", async () => {
const user = userEvent.setup();
const { user: userData } = await renderPage();
const convertToOAUTHSpy = jest
.spyOn(API, "convertToOAUTH")
.spyOn(client.api, "convertToOAUTH")
.mockResolvedValue({
state_string: "some-state-string",
expires_at: "2021-01-01T00:00:00Z",

View File

@ -1,6 +1,6 @@
import type { ComponentProps, FC } from "react";
import { useMutation, useQuery } from "react-query";
import { getUserLoginType } from "api/api";
import { client } from "api/api";
import { authMethods, updatePassword } from "api/queries/users";
import { displaySuccess } from "components/GlobalSnackbar/utils";
import { Loader } from "components/Loader/Loader";
@ -19,7 +19,7 @@ export const SecurityPage: FC = () => {
const authMethodsQuery = useQuery(authMethods());
const { data: userLoginType } = useQuery({
queryKey: ["loginType"],
queryFn: getUserLoginType,
queryFn: client.api.getUserLoginType,
});
const singleSignOnSection = useSingleSignOnSection();

View File

@ -7,7 +7,7 @@ import Link from "@mui/material/Link";
import TextField from "@mui/material/TextField";
import { type FC, useState } from "react";
import { useMutation } from "react-query";
import { convertToOAUTH } from "api/api";
import { client } from "api/api";
import { getErrorMessage } from "api/errors";
import type {
AuthMethods,
@ -52,7 +52,7 @@ export const useSingleSignOnSection = () => {
const [loginTypeConfirmation, setLoginTypeConfirmation] =
useState<LoginTypeConfirmation>({ open: false, selectedType: undefined });
const mutation = useMutation(convertToOAUTH, {
const mutation = useMutation(client.api.convertToOAUTH, {
onSuccess: (data) => {
const loginTypeMsg =
data.to_type === "github" ? "Github" : "OpenID Connect";

View File

@ -4,7 +4,7 @@ import {
useQuery,
useQueryClient,
} from "react-query";
import { getTokens, deleteToken } from "api/api";
import { client } from "api/api";
import type { TokensFilter } from "api/typesGenerated";
// Load all tokens
@ -13,7 +13,7 @@ export const useTokensData = ({ include_all }: TokensFilter) => {
const result = useQuery({
queryKey,
queryFn: () =>
getTokens({
client.api.getTokens({
include_all,
}),
});
@ -29,7 +29,7 @@ export const useDeleteToken = (queryKey: QueryKey) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteToken,
mutationFn: client.api.deleteToken,
onSuccess: () => {
// Invalidate and refetch
void queryClient.invalidateQueries(queryKey);

View File

@ -1,7 +1,7 @@
import { fireEvent, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { HttpResponse, http } from "msw";
import * as API from "api/api";
import { client } from "api/api";
import type { Role } from "api/typesGenerated";
import {
MockUser,
@ -261,7 +261,7 @@ describe("UsersPage", () => {
await resetUserPassword(() => {
jest
.spyOn(API, "updateUserPassword")
.spyOn(client.api, "updateUserPassword")
.mockResolvedValueOnce(undefined);
});
@ -269,8 +269,8 @@ describe("UsersPage", () => {
await screen.findByText("Successfully updated the user password.");
// Check if the API was called correctly
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(MockUser.id, {
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(MockUser.id, {
password: expect.any(String),
old_password: "",
});
@ -281,15 +281,17 @@ describe("UsersPage", () => {
renderPage();
await resetUserPassword(() => {
jest.spyOn(API, "updateUserPassword").mockRejectedValueOnce({});
jest
.spyOn(client.api, "updateUserPassword")
.mockRejectedValueOnce({});
});
// Check if the error message is displayed
await screen.findByText("Error on resetting the user password.");
// Check if the API was called correctly
expect(API.updateUserPassword).toBeCalledTimes(1);
expect(API.updateUserPassword).toBeCalledWith(MockUser.id, {
expect(client.api.updateUserPassword).toBeCalledTimes(1);
expect(client.api.updateUserPassword).toBeCalledWith(MockUser.id, {
password: expect.any(String),
old_password: "",
});

View File

@ -1,6 +1,6 @@
import { screen, waitFor } from "@testing-library/react";
import WS from "jest-websocket-mock";
import * as API from "api/api";
import { client } from "api/api";
import {
MockWorkspace,
MockWorkspaceAgent,
@ -18,7 +18,7 @@ afterEach(() => {
describe("WorkspaceBuildPage", () => {
test("gets the right workspace build", async () => {
const getWorkspaceBuildSpy = jest
.spyOn(API, "getWorkspaceBuildByNumber")
.spyOn(client.api, "getWorkspaceBuildByNumber")
.mockResolvedValue(MockWorkspaceBuild);
renderWithAuth(<WorkspaceBuildPage />, {
route: `/@${MockWorkspace.owner_name}/${MockWorkspace.name}/builds/${MockWorkspace.latest_build.build_number}`,

View File

@ -3,7 +3,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useQuery } from "react-query";
import { useParams } from "react-router-dom";
import { getWorkspaceBuilds } from "api/api";
import { client } from "api/api";
import { workspaceBuildByNumber } from "api/queries/workspaceBuilds";
import { useWorkspaceBuildLogs } from "hooks/useWorkspaceBuildLogs";
import { pageTitle } from "utils/page";
@ -26,7 +26,7 @@ export const WorkspaceBuildPage: FC = () => {
const buildsQuery = useQuery({
queryKey: ["builds", username, build?.workspace_id],
queryFn: () => {
return getWorkspaceBuilds(build?.workspace_id ?? "", {
return client.api.getWorkspaceBuilds(build?.workspace_id ?? "", {
since: dayjs().add(-30, "day").toISOString(),
});
},

View File

@ -5,7 +5,7 @@ import visuallyHidden from "@mui/utils/visuallyHidden";
import { useFormik } from "formik";
import type { FC } from "react";
import { useQuery } from "react-query";
import { getWorkspaceParameters } from "api/api";
import { client } from "api/api";
import type {
TemplateVersionParameter,
Workspace,
@ -49,7 +49,7 @@ export const BuildParametersPopover: FC<BuildParametersPopoverProps> = ({
}) => {
const { data: parameters } = useQuery({
queryKey: ["workspace", workspace.id, "parameters"],
queryFn: () => getWorkspaceParameters(workspace),
queryFn: () => client.api.getWorkspaceParameters(workspace),
});
const ephemeralParameters = parameters
? parameters.templateVersionRichParameters.filter((p) => p.ephemeral)

View File

@ -1,7 +1,7 @@
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { HttpResponse, http } from "msw";
import * as api from "api/api";
import * as API from "api/api";
import type { TemplateVersionParameter, Workspace } from "api/typesGenerated";
import EventSourceMock from "eventsourcemock";
import {
@ -22,16 +22,22 @@ import { renderWithAuth } from "testHelpers/renderHelpers";
import { server } from "testHelpers/server";
import { WorkspacePage } from "./WorkspacePage";
const { client } = API;
// Renders the workspace page and waits for it be loaded
const renderWorkspacePage = async (workspace: Workspace) => {
jest.spyOn(api, "getWorkspaceByOwnerAndName").mockResolvedValue(workspace);
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([]);
jest
.spyOn(api, "getDeploymentConfig")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValue(workspace);
jest.spyOn(client.api, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([]);
jest
.spyOn(client.api, "getDeploymentConfig")
.mockResolvedValueOnce(MockDeploymentConfig);
jest
.spyOn(api, "watchWorkspaceAgentLogs")
.spyOn(API, "watchWorkspaceAgentLogs")
.mockImplementation((_, options) => {
options.onDone?.();
return new WebSocket("");
@ -87,7 +93,7 @@ describe("WorkspacePage", () => {
it("requests a delete job when the user presses Delete and confirms", async () => {
const user = userEvent.setup({ delay: 0 });
const deleteWorkspaceMock = jest
.spyOn(api, "deleteWorkspace")
.spyOn(client.api, "deleteWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
await renderWorkspacePage(MockWorkspace);
@ -127,7 +133,7 @@ describe("WorkspacePage", () => {
);
const deleteWorkspaceMock = jest
.spyOn(api, "deleteWorkspace")
.spyOn(client.api, "deleteWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuildDelete);
await renderWorkspacePage(MockFailedWorkspace);
@ -173,7 +179,7 @@ describe("WorkspacePage", () => {
);
const startWorkspaceMock = jest
.spyOn(api, "startWorkspace")
.spyOn(client.api, "startWorkspace")
.mockImplementation(() => Promise.resolve(MockWorkspaceBuild));
await testButton(MockStoppedWorkspace, "Start", startWorkspaceMock);
@ -181,7 +187,7 @@ describe("WorkspacePage", () => {
it("requests a stop job when the user presses Stop", async () => {
const stopWorkspaceMock = jest
.spyOn(api, "stopWorkspace")
.spyOn(client.api, "stopWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
await testButton(MockWorkspace, "Stop", stopWorkspaceMock);
@ -189,7 +195,7 @@ describe("WorkspacePage", () => {
it("requests a stop when the user presses Restart", async () => {
const stopWorkspaceMock = jest
.spyOn(api, "stopWorkspace")
.spyOn(client.api, "stopWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
// Render
@ -215,7 +221,7 @@ describe("WorkspacePage", () => {
);
const cancelWorkspaceMock = jest
.spyOn(api, "cancelWorkspaceBuild")
.spyOn(client.api, "cancelWorkspaceBuild")
.mockImplementation(() => Promise.resolve({ message: "job canceled" }));
await testButton(MockStartingWorkspace, "Cancel", cancelWorkspaceMock);
@ -224,11 +230,11 @@ describe("WorkspacePage", () => {
it("requests an update when the user presses Update", async () => {
// Mocks
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockOutdatedWorkspace);
const updateWorkspaceMock = jest
.spyOn(api, "updateWorkspace")
.spyOn(client.api, "updateWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
// Render
@ -249,12 +255,12 @@ describe("WorkspacePage", () => {
it("updates the parameters when they are missing during update", async () => {
// Mocks
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockOutdatedWorkspace);
const updateWorkspaceSpy = jest
.spyOn(api, "updateWorkspace")
.spyOn(client.api, "updateWorkspace")
.mockRejectedValueOnce(
new api.MissingBuildParameters(
new API.MissingBuildParameters(
[MockTemplateVersionParameter1, MockTemplateVersionParameter2],
MockOutdatedWorkspace.template_active_version_id,
),
@ -271,7 +277,7 @@ describe("WorkspacePage", () => {
// The update was called
await waitFor(() => {
expect(api.updateWorkspace).toBeCalled();
expect(client.api.updateWorkspace).toBeCalled();
updateWorkspaceSpy.mockClear();
});
@ -294,7 +300,7 @@ describe("WorkspacePage", () => {
// Check if the update was called using the values from the form
await waitFor(() => {
expect(api.updateWorkspace).toBeCalledWith(MockOutdatedWorkspace, [
expect(client.api.updateWorkspace).toBeCalledWith(MockOutdatedWorkspace, [
{
name: MockTemplateVersionParameter1.name,
value: "some-value",
@ -309,7 +315,7 @@ describe("WorkspacePage", () => {
it("restart the workspace with one time parameters when having the confirmation dialog", async () => {
localStorage.removeItem(`${MockUser.id}_ignoredWarnings`);
jest.spyOn(api, "getWorkspaceParameters").mockResolvedValue({
jest.spyOn(client.api, "getWorkspaceParameters").mockResolvedValue({
templateVersionRichParameters: [
{
...MockTemplateVersionParameter1,
@ -321,7 +327,7 @@ describe("WorkspacePage", () => {
],
buildParameters: [{ name: "rebuild", value: "false" }],
});
const restartWorkspaceSpy = jest.spyOn(api, "restartWorkspace");
const restartWorkspaceSpy = jest.spyOn(client.api, "restartWorkspace");
const user = userEvent.setup();
await renderWorkspacePage(MockWorkspace);
await user.click(screen.getByTestId("build-parameters-button"));
@ -351,7 +357,7 @@ describe("WorkspacePage", () => {
const retryDebugButtonRe = /^Debug$/i;
describe("Retries a failed 'Start' transition", () => {
const mockStart = jest.spyOn(api, "startWorkspace");
const mockStart = jest.spyOn(client.api, "startWorkspace");
const failedStart: Workspace = {
...MockFailedWorkspace,
latest_build: {
@ -384,7 +390,7 @@ describe("WorkspacePage", () => {
});
describe("Retries a failed 'Stop' transition", () => {
const mockStop = jest.spyOn(api, "stopWorkspace");
const mockStop = jest.spyOn(client.api, "stopWorkspace");
const failedStop: Workspace = {
...MockFailedWorkspace,
latest_build: {
@ -405,7 +411,7 @@ describe("WorkspacePage", () => {
});
describe("Retries a failed 'Delete' transition", () => {
const mockDelete = jest.spyOn(api, "deleteWorkspace");
const mockDelete = jest.spyOn(client.api, "deleteWorkspace");
const failedDelete: Workspace = {
...MockFailedWorkspace,
latest_build: {
@ -450,7 +456,7 @@ describe("WorkspacePage", () => {
return HttpResponse.json([parameter]);
}),
);
const startWorkspaceSpy = jest.spyOn(api, "startWorkspace");
const startWorkspaceSpy = jest.spyOn(client.api, "startWorkspace");
await renderWorkspacePage(workspace);
const retryWithBuildParametersButton = await screen.findByRole("button", {
@ -496,7 +502,7 @@ describe("WorkspacePage", () => {
return HttpResponse.json([parameter]);
}),
);
const startWorkspaceSpy = jest.spyOn(api, "startWorkspace");
const startWorkspaceSpy = jest.spyOn(client.api, "startWorkspace");
await renderWorkspacePage(workspace);
const retryWithBuildParametersButton = await screen.findByRole("button", {

View File

@ -3,7 +3,7 @@ import { type FC, useEffect, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useNavigate } from "react-router-dom";
import { MissingBuildParameters, restartWorkspace } from "api/api";
import { MissingBuildParameters, client } from "api/api";
import { getErrorMessage } from "api/errors";
import { buildInfo } from "api/queries/buildInfo";
import { deploymentConfig, deploymentSSHConfig } from "api/queries/deployment";
@ -80,7 +80,7 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
}>({ open: false });
const { mutate: mutateRestartWorkspace, isLoading: isRestarting } =
useMutation({
mutationFn: restartWorkspace,
mutationFn: client.api.restartWorkspace,
});
// SSH Prefix

View File

@ -5,7 +5,7 @@ import { HttpResponse, http } from "msw";
import type { FC } from "react";
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
import { RouterProvider, createMemoryRouter } from "react-router-dom";
import * as API from "api/api";
import { client } from "api/api";
import { workspaceByOwnerAndName } from "api/queries/workspaces";
import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar";
import { ThemeProvider } from "contexts/ThemeProvider";
@ -62,7 +62,7 @@ const renderScheduleControls = async () => {
test("add 3 hours to deadline", async () => {
const user = userEvent.setup();
const updateDeadlineSpy = jest
.spyOn(API, "putWorkspaceExtension")
.spyOn(client.api, "putWorkspaceExtension")
.mockResolvedValue();
await renderScheduleControls();
@ -91,7 +91,7 @@ test("add 3 hours to deadline", async () => {
test("remove 2 hours to deadline", async () => {
const user = userEvent.setup();
const updateDeadlineSpy = jest
.spyOn(API, "putWorkspaceExtension")
.spyOn(client.api, "putWorkspaceExtension")
.mockResolvedValue();
await renderScheduleControls();
@ -119,7 +119,7 @@ test("remove 2 hours to deadline", async () => {
test("rollback to previous deadline on error", async () => {
const user = userEvent.setup();
const initialScheduleMessage = "Stop in 3 hours";
jest.spyOn(API, "putWorkspaceExtension").mockRejectedValue({});
jest.spyOn(client.api, "putWorkspaceExtension").mockRejectedValue({});
await renderScheduleControls();
@ -139,7 +139,7 @@ test("rollback to previous deadline on error", async () => {
test("request is only sent once when clicking multiple times", async () => {
const user = userEvent.setup();
const updateDeadlineSpy = jest
.spyOn(API, "putWorkspaceExtension")
.spyOn(client.api, "putWorkspaceExtension")
.mockResolvedValue();
await renderScheduleControls();

View File

@ -1,6 +1,6 @@
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as api from "api/api";
import { client } from "api/api";
import {
MockWorkspace,
MockTemplateVersionParameter1,
@ -20,15 +20,17 @@ import WorkspaceParametersPage from "./WorkspaceParametersPage";
test("Submit the workspace settings page successfully", async () => {
// Mock the API calls that loads data
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockWorkspace);
jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([
MockTemplateVersionParameter1,
MockTemplateVersionParameter2,
// Immutable parameters
MockTemplateVersionParameter4,
]);
jest.spyOn(api, "getWorkspaceBuildParameters").mockResolvedValueOnce([
jest
.spyOn(client.api, "getTemplateVersionRichParameters")
.mockResolvedValueOnce([
MockTemplateVersionParameter1,
MockTemplateVersionParameter2,
// Immutable parameters
MockTemplateVersionParameter4,
]);
jest.spyOn(client.api, "getWorkspaceBuildParameters").mockResolvedValueOnce([
MockWorkspaceBuildParameter1,
MockWorkspaceBuildParameter2,
// Immutable value
@ -36,7 +38,7 @@ test("Submit the workspace settings page successfully", async () => {
]);
// Mock the API calls that submit data
const postWorkspaceBuildSpy = jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(client.api, "postWorkspaceBuild")
.mockResolvedValue(MockWorkspaceBuild);
// Setup event and rendering
const user = userEvent.setup();

View File

@ -4,7 +4,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery } from "react-query";
import { useNavigate } from "react-router-dom";
import { getWorkspaceParameters, postWorkspaceBuild } from "api/api";
import { client } from "api/api";
import { isApiValidationError } from "api/errors";
import { checkAuthorization } from "api/queries/authCheck";
import { templateByName } from "api/queries/templates";
@ -29,12 +29,12 @@ const WorkspaceParametersPage: FC = () => {
const workspace = useWorkspaceSettings();
const parameters = useQuery({
queryKey: ["workspace", workspace.id, "parameters"],
queryFn: () => getWorkspaceParameters(workspace),
queryFn: () => client.api.getWorkspaceParameters(workspace),
});
const navigate = useNavigate();
const updateParameters = useMutation({
mutationFn: (buildParameters: WorkspaceBuildParameter[]) =>
postWorkspaceBuild(workspace.id, {
client.api.postWorkspaceBuild(workspace.id, {
transition: "start",
rich_parameter_values: buildParameters,
}),
@ -93,7 +93,9 @@ const WorkspaceParametersPage: FC = () => {
export type WorkspaceParametersPageViewProps = {
workspace: Workspace;
canChangeVersions: boolean;
data: Awaited<ReturnType<typeof getWorkspaceParameters>> | undefined;
data:
| Awaited<ReturnType<typeof client.api.getWorkspaceParameters>>
| undefined;
submitError: unknown;
isSubmitting: boolean;
onSubmit: (formValues: WorkspaceParametersFormValues) => void;

View File

@ -1,5 +1,5 @@
import { screen } from "@testing-library/react";
import * as API from "api/api";
import { client } from "api/api";
import { defaultSchedule } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule";
import { MockTemplate } from "testHelpers/entities";
import { render } from "testHelpers/renderHelpers";
@ -271,7 +271,7 @@ const defaultFormProps: WorkspaceScheduleFormProps = {
describe("templateInheritance", () => {
it("disables the entire autostart feature appropriately", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
const props = {
...defaultFormProps,
template: {
@ -299,7 +299,7 @@ describe("templateInheritance", () => {
it("disables the autostart days of the week appropriately", async () => {
const enabledDayLabels = ["Sat", "Sun"];
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
const props = {
...defaultFormProps,
template: {
@ -343,7 +343,7 @@ describe("templateInheritance", () => {
allow_user_autostop: false,
},
};
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
render(<WorkspaceScheduleForm {...props} />);
const autoStopToggle = await screen.findByLabelText("Enable Autostop");
@ -355,7 +355,7 @@ describe("templateInheritance", () => {
expect(ttlInput).toBeDisabled();
});
it("disables secondary autostart fields if main feature switch is toggled off", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
render(
<WorkspaceScheduleForm
{...defaultFormProps}
@ -379,7 +379,7 @@ describe("templateInheritance", () => {
});
});
it("disables secondary autostop fields if main feature switch is toggled off", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
render(
<WorkspaceScheduleForm
{...defaultFormProps}
@ -398,7 +398,7 @@ describe("templateInheritance", () => {
});
test("form should be enabled when both auto stop and auto start features are disabled, given that the template permits these actions", async () => {
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
render(
<WorkspaceScheduleForm
{...defaultFormProps}
@ -423,7 +423,7 @@ test("form should be disabled when both auto stop and auto start features are di
allow_user_autostop: false,
},
};
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
jest.spyOn(client.api, "getTemplateByName").mockResolvedValue(MockTemplate);
render(<WorkspaceScheduleForm {...props} />);
const submitButton = await screen.findByRole("button", { name: "Submit" });

View File

@ -3,11 +3,7 @@ import { type FC, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQuery, useQueryClient } from "react-query";
import { useNavigate, useParams } from "react-router-dom";
import {
putWorkspaceAutostart,
putWorkspaceAutostop,
startWorkspace,
} from "api/api";
import { client } from "api/api";
import { checkAuthorization } from "api/queries/authCheck";
import { templateByName } from "api/queries/templates";
import { workspaceByOwnerAndNameKey } from "api/queries/workspaces";
@ -72,7 +68,10 @@ export const WorkspaceSchedulePage: FC = () => {
const [isConfirmingApply, setIsConfirmingApply] = useState(false);
const { mutate: updateWorkspace } = useMutation({
mutationFn: () =>
startWorkspace(workspace.id, workspace.template_active_version_id),
client.api.startWorkspace(
workspace.id,
workspace.template_active_version_id,
),
});
return (
@ -167,11 +166,11 @@ const submitSchedule = async (data: SubmitScheduleData) => {
const actions: Promise<void>[] = [];
if (autostartChanged) {
actions.push(putWorkspaceAutostart(workspace.id, autostart));
actions.push(client.api.putWorkspaceAutostart(workspace.id, autostart));
}
if (autostopChanged) {
actions.push(putWorkspaceAutostop(workspace.id, ttl));
actions.push(client.api.putWorkspaceAutostop(workspace.id, ttl));
}
return Promise.all(actions);

View File

@ -1,6 +1,6 @@
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as api from "api/api";
import { client } from "api/api";
import { MockWorkspace } from "testHelpers/entities";
import {
renderWithWorkspaceSettingsLayout,
@ -11,11 +11,11 @@ import WorkspaceSettingsPage from "./WorkspaceSettingsPage";
test("Submit the workspace settings page successfully", async () => {
// Mock the API calls that loads data
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce({ ...MockWorkspace });
// Mock the API calls that submit data
const patchWorkspaceSpy = jest
.spyOn(api, "patchWorkspace")
.spyOn(client.api, "patchWorkspace")
.mockResolvedValue();
// Setup event and rendering
const user = userEvent.setup();
@ -43,7 +43,7 @@ test("Submit the workspace settings page successfully", async () => {
test("Name field is disabled if renames are disabled", async () => {
// Mock the API calls that loads data
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(client.api, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce({ ...MockWorkspace, allow_renames: false });
renderWithWorkspaceSettingsLayout(<WorkspaceSettingsPage />, {
route: "/@test-user/test-workspace/settings",

View File

@ -2,7 +2,7 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation } from "react-query";
import { useNavigate, useParams } from "react-router-dom";
import { patchWorkspace, updateWorkspaceAutomaticUpdates } from "api/api";
import { client } from "api/api";
import { displaySuccess } from "components/GlobalSnackbar/utils";
import { pageTitle } from "utils/page";
import type { WorkspaceSettingsFormValues } from "./WorkspaceSettingsForm";
@ -22,8 +22,8 @@ const WorkspaceSettingsPage: FC = () => {
const mutation = useMutation({
mutationFn: async (formValues: WorkspaceSettingsFormValues) => {
await Promise.all([
patchWorkspace(workspace.id, { name: formValues.name }),
updateWorkspaceAutomaticUpdates(
client.api.patchWorkspace(workspace.id, { name: formValues.name }),
client.api.updateWorkspaceAutomaticUpdates(
workspace.id,
formValues.automatic_updates,
),

View File

@ -7,7 +7,7 @@ import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { type FC, type ReactNode, useMemo, useState, useEffect } from "react";
import { useQueries } from "react-query";
import { getTemplateVersion } from "api/api";
import { client } from "api/api";
import type { TemplateVersion, Workspace } from "api/typesGenerated";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
@ -129,7 +129,7 @@ export const BatchUpdateConfirmation: FC<BatchUpdateConfirmationProps> = ({
// ...but the query _also_ doesn't have everything we need, like the
// template display name!
...version,
...(await getTemplateVersion(version.id)),
...(await client.api.getTemplateVersion(version.id)),
}),
})),
});

View File

@ -1,7 +1,7 @@
import { screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { HttpResponse, http } from "msw";
import * as API from "api/api";
import { client } from "api/api";
import type { Workspace } from "api/typesGenerated";
import {
MockStoppedWorkspace,
@ -58,9 +58,9 @@ describe("WorkspacesPage", () => {
{ ...MockWorkspace, id: "3" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const deleteWorkspace = jest.spyOn(API, "deleteWorkspace");
const deleteWorkspace = jest.spyOn(client.api, "deleteWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -95,9 +95,9 @@ describe("WorkspacesPage", () => {
{ ...MockOutdatedWorkspace, id: "4" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const updateWorkspace = jest.spyOn(API, "updateWorkspace");
const updateWorkspace = jest.spyOn(client.api, "updateWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -134,9 +134,9 @@ describe("WorkspacesPage", () => {
{ ...MockOutdatedWorkspace, id: "3" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const updateWorkspace = jest.spyOn(API, "updateWorkspace");
const updateWorkspace = jest.spyOn(client.api, "updateWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -172,9 +172,9 @@ describe("WorkspacesPage", () => {
{ ...MockOutdatedWorkspace, id: "3" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const updateWorkspace = jest.spyOn(API, "updateWorkspace");
const updateWorkspace = jest.spyOn(client.api, "updateWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -212,9 +212,9 @@ describe("WorkspacesPage", () => {
{ ...MockWorkspace, id: "5" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const updateWorkspace = jest.spyOn(API, "updateWorkspace");
const updateWorkspace = jest.spyOn(client.api, "updateWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -254,9 +254,9 @@ describe("WorkspacesPage", () => {
{ ...MockWorkspace, id: "3" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const stopWorkspace = jest.spyOn(API, "stopWorkspace");
const stopWorkspace = jest.spyOn(client.api, "stopWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();
@ -281,9 +281,9 @@ describe("WorkspacesPage", () => {
{ ...MockStoppedWorkspace, id: "3" },
];
jest
.spyOn(API, "getWorkspaces")
.spyOn(client.api, "getWorkspaces")
.mockResolvedValue({ workspaces, count: workspaces.length });
const startWorkspace = jest.spyOn(API, "startWorkspace");
const startWorkspace = jest.spyOn(client.api, "startWorkspace");
const user = userEvent.setup();
renderWithAuth(<WorkspacesPage />);
await waitForLoaderToBeRemoved();

View File

@ -1,12 +1,5 @@
import { useMutation } from "react-query";
import {
deleteWorkspace,
deleteFavoriteWorkspace,
putFavoriteWorkspace,
startWorkspace,
stopWorkspace,
updateWorkspace,
} from "api/api";
import { client } from "api/api";
import type { Workspace } from "api/typesGenerated";
import { displayError } from "components/GlobalSnackbar/utils";
@ -21,7 +14,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
mutationFn: (workspaces: readonly Workspace[]) => {
return Promise.all(
workspaces.map((w) =>
startWorkspace(w.id, w.latest_build.template_version_id),
client.api.startWorkspace(w.id, w.latest_build.template_version_id),
),
);
},
@ -33,7 +26,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
const stopAllMutation = useMutation({
mutationFn: (workspaces: readonly Workspace[]) => {
return Promise.all(workspaces.map((w) => stopWorkspace(w.id)));
return Promise.all(workspaces.map((w) => client.api.stopWorkspace(w.id)));
},
onSuccess,
onError: () => {
@ -43,7 +36,9 @@ export function useBatchActions(options: UseBatchActionsProps) {
const deleteAllMutation = useMutation({
mutationFn: (workspaces: readonly Workspace[]) => {
return Promise.all(workspaces.map((w) => deleteWorkspace(w.id)));
return Promise.all(
workspaces.map((w) => client.api.deleteWorkspace(w.id)),
);
},
onSuccess,
onError: () => {
@ -56,7 +51,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => w.outdated && !w.dormant_at)
.map((w) => updateWorkspace(w)),
.map((w) => client.api.updateWorkspace(w)),
);
},
onSuccess,
@ -70,7 +65,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => !w.favorite)
.map((w) => putFavoriteWorkspace(w.id)),
.map((w) => client.api.putFavoriteWorkspace(w.id)),
);
},
onSuccess,
@ -84,7 +79,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => w.favorite)
.map((w) => deleteFavoriteWorkspace(w.id)),
.map((w) => client.api.deleteFavoriteWorkspace(w.id)),
);
},
onSuccess,

View File

@ -5,7 +5,7 @@ import {
useQuery,
useQueryClient,
} from "react-query";
import { getWorkspaces, updateWorkspaceVersion } from "api/api";
import { client } from "api/api";
import { getErrorMessage } from "api/errors";
import type {
Workspace,
@ -30,7 +30,7 @@ export const useWorkspacesData = ({
const result = useQuery({
queryKey,
queryFn: () =>
getWorkspaces({
client.api.getWorkspaces({
q: query,
limit: limit,
offset: page <= 0 ? 0 : (page - 1) * limit,
@ -54,7 +54,7 @@ export const useWorkspaceUpdate = (queryKey: QueryKey) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateWorkspaceVersion,
mutationFn: client.api.updateWorkspaceVersion,
onMutate: async (workspace) => {
await queryClient.cancelQueries({ queryKey });
queryClient.setQueryData<WorkspacesResponse>(queryKey, (oldResponse) => {

View File

@ -1,4 +1,4 @@
import { getTemplates } from "api/api";
import { client } from "api/api";
import type { WorkspaceStatus } from "api/typesGenerated";
import {
useFilterMenu,
@ -21,7 +21,7 @@ export const useTemplateFilterMenu = ({
id: "template",
getSelectedOption: async () => {
// Show all templates including deprecated
const templates = await getTemplates(organizationId);
const templates = await client.api.getTemplates(organizationId);
const template = templates.find((template) => template.name === value);
if (template) {
return {
@ -37,7 +37,7 @@ export const useTemplateFilterMenu = ({
},
getOptions: async (query) => {
// Show all templates including deprecated
const templates = await getTemplates(organizationId);
const templates = await client.api.getTemplates(organizationId);
const filteredTemplates = templates.filter(
(template) =>
template.name.toLowerCase().includes(query.toLowerCase()) ||

View File

@ -1,4 +1,4 @@
import * as API from "api/api";
import { client } from "api/api";
export const terminalWebsocketUrl = async (
baseUrl: string | undefined,
@ -30,7 +30,7 @@ export const terminalWebsocketUrl = async (
}
// Do ticket issuance and set the query parameter.
const tokenRes = await API.issueReconnectingPTYSignedToken({
const tokenRes = await client.api.issueReconnectingPTYSignedToken({
url: url.toString(),
agentID: agentId,
});