refactor: improve test isolation for Axios API logic (#13125)

* wip: commit progress on code split-up

* wip: commit more progress

* wip: finish initial version of class implementation

* chore: update all import paths to go through client instance

* fix: remove temp comments

* refactor: smoooooooosh the API

* refactor: update import setup for tests
This commit is contained in:
Michael Smith
2024-05-12 19:05:22 +00:00
committed by GitHub
parent 5ddbeddf85
commit f13b1c9af6
95 changed files with 1964 additions and 1896 deletions
+9 -8
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, API } from "api/api";
import type { SerpentOption } from "api/typesGenerated";
import { coderPort } from "./constants";
import { findSessionToken, randomName } from "./helpers";
@@ -15,6 +15,7 @@ export const setupApiCalls = async (page: Page) => {
} catch {
// If this fails, we have an unauthenticated client.
}
API.setHost(`http://127.0.0.1:${coderPort}`);
};
@@ -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);
+2 -2
View File
@@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import { hasFirstUser } from "api/api";
import { API } 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 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) {
+2 -1
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 { API } from "api/api";
import type {
WorkspaceBuildParameter,
UpdateTemplateMeta,
@@ -423,6 +423,7 @@ export const waitUntilUrlIsNotResponding = async (url: string) => {
const retryIntervalMs = 1000;
let retries = 0;
const axiosInstance = API.getAxiosInstance();
while (retries < maxRetries) {
try {
await axiosInstance.get(url);
+2 -1
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 { API } from "api/api";
import { coderdPProfPort, enterpriseLicense } from "./constants";
class CoderReporter implements Reporter {
@@ -143,6 +143,7 @@ const logLines = (chunk: string | Buffer): string[] => {
};
const exportDebugPprof = async (outputFile: string) => {
const axiosInstance = API.getAxiosInstance();
const response = await axiosInstance.get(
`http://127.0.0.1:${coderdPProfPort}/debug/pprof/goroutine?debug=1`,
);
+1 -1
View File
@@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import * as API from "api/api";
import { API } from "api/api";
import { setupApiCalls } from "../../api";
import { e2eFakeExperiment1, e2eFakeExperiment2 } from "../../constants";
+2 -2
View File
@@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { API } 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 API.getDeploymentConfig();
await page.goto("/deployment/network", { waitUntil: "domcontentloaded" });
@@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { API } 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 API.getDeploymentConfig();
await page.goto("/deployment/observability", {
waitUntil: "domcontentloaded",
+3 -4
View File
@@ -1,7 +1,6 @@
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 { type DeploymentConfig, API } from "api/api";
import {
findConfigOption,
setupApiCalls,
@@ -12,7 +11,7 @@ import {
test("enabled security settings", async ({ page }) => {
await setupApiCalls(page);
const config = await getDeploymentConfig();
const config = await API.getDeploymentConfig();
await page.goto("/deployment/security", { waitUntil: "domcontentloaded" });
@@ -31,7 +30,7 @@ test("enabled security settings", async ({ page }) => {
async function verifyStrictTransportSecurity(
page: Page,
config: API.DeploymentConfig,
config: DeploymentConfig,
) {
const flag = "strict-transport-security";
const opt = findConfigOption(config, flag);
+2 -2
View File
@@ -1,5 +1,5 @@
import { test } from "@playwright/test";
import { getDeploymentConfig } from "api/api";
import { API } 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 API.getDeploymentConfig();
await page.goto("/deployment/userauth", { waitUntil: "domcontentloaded" });
@@ -1,5 +1,5 @@
import { test, expect, type Page } from "@playwright/test";
import { createWorkspaceProxy } from "api/api";
import { API } 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 API.createWorkspaceProxy({
name: proxyName,
display_name: "",
icon: "/emojis/1f1e7-1f1f7.png",
+1 -1
View File
@@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test";
import * as API from "api/api";
import { API } from "api/api";
import {
createGroup,
createUser,
@@ -1,5 +1,5 @@
import { expect, test } from "@playwright/test";
import { createTemplate, createTemplateVersion, getTemplate } from "api/api";
import { API } 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 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 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 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).
+28 -27
View File
@@ -6,10 +6,11 @@ import {
MockWorkspaceBuild,
MockWorkspaceBuildParameter1,
} from "testHelpers/entities";
import * as api from "./api";
import { axiosInstance } from "./api";
import { API, getURLWithSearchParams, MissingBuildParameters } from "./api";
import type * as TypesGen from "./typesGenerated";
const axiosInstance = API.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 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 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 API.logout();
// then
expect(axiosMockPost).toHaveBeenCalled();
@@ -80,7 +81,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
try {
await api.logout();
await 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 API.getApiKey();
// then
expect(axiosMockPost).toHaveBeenCalled();
@@ -121,7 +122,7 @@ describe("api.ts", () => {
axiosInstance.post = axiosMockPost;
try {
await api.getApiKey();
await 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,11 +173,11 @@ describe("api.ts", () => {
describe("update", () => {
it("creates a build with start and the latest template", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(API, "postWorkspaceBuild")
.mockResolvedValueOnce(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate);
await api.updateWorkspace(MockWorkspace);
expect(api.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id, {
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: [],
@@ -185,12 +186,12 @@ describe("api.ts", () => {
it("fails when having missing parameters", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(API, "postWorkspaceBuild")
.mockResolvedValue(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValue(MockTemplate);
jest.spyOn(api, "getWorkspaceBuildParameters").mockResolvedValue([]);
jest.spyOn(API, "getTemplate").mockResolvedValue(MockTemplate);
jest.spyOn(API, "getWorkspaceBuildParameters").mockResolvedValue([]);
jest
.spyOn(api, "getTemplateVersionRichParameters")
.spyOn(API, "getTemplateVersionRichParameters")
.mockResolvedValue([
MockTemplateVersionParameter1,
{ ...MockTemplateVersionParameter2, mutable: false },
@@ -198,14 +199,14 @@ describe("api.ts", () => {
let error = new Error();
try {
await api.updateWorkspace(MockWorkspace);
await 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,19 +214,19 @@ describe("api.ts", () => {
it("creates a build with the no parameters if it is already filled", async () => {
jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(API, "postWorkspaceBuild")
.mockResolvedValueOnce(MockWorkspaceBuild);
jest.spyOn(api, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest.spyOn(API, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest
.spyOn(api, "getWorkspaceBuildParameters")
.spyOn(API, "getWorkspaceBuildParameters")
.mockResolvedValue([MockWorkspaceBuildParameter1]);
jest
.spyOn(api, "getTemplateVersionRichParameters")
.spyOn(API, "getTemplateVersionRichParameters")
.mockResolvedValue([
{ ...MockTemplateVersionParameter1, required: true, mutable: false },
]);
await api.updateWorkspace(MockWorkspace);
expect(api.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id, {
await API.updateWorkspace(MockWorkspace);
expect(API.postWorkspaceBuild).toHaveBeenCalledWith(MockWorkspace.id, {
transition: "start",
template_version_id: MockTemplate.active_version_id,
rich_parameter_values: [],
+1700 -1620
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type { AppearanceConfig } from "api/typesGenerated";
import type { MetadataState } from "hooks/useEmbeddedMetadata";
import { cachedQuery } from "./util";
+2 -2
View File
@@ -1,4 +1,4 @@
import { getAuditLogs } from "api/api";
import { API } 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 API.getAuditLogs({
offset,
limit,
q: payload,
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
import type { AuthorizationRequest } from "api/typesGenerated";
export const AUTHORIZATION_KEY = "authorization";
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
import type { BuildInfoResponse } from "api/typesGenerated";
import type { MetadataState } from "hooks/useEmbeddedMetadata";
import { cachedQuery } from "./util";
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient, UseMutationOptions } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type { HealthSettings, UpdateHealthSettings } from "api/typesGenerated";
export const HEALTH_QUERY_KEY = ["health"];
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const deploymentConfig = () => {
return {
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type { Entitlements } from "api/typesGenerated";
import type { MetadataState } from "hooks/useEmbeddedMetadata";
import { cachedQuery } from "./util";
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
import type { Experiments } from "api/typesGenerated";
import type { MetadataState } from "hooks/useEmbeddedMetadata";
import { cachedQuery } from "./util";
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient, UseMutationOptions } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type { ExternalAuth } from "api/typesGenerated";
// Returns all configured external auths for a given user.
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const uploadFile = () => {
return {
+2 -3
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 { API } from "api/api";
import type {
CreateGroupRequest,
Group,
@@ -72,7 +71,7 @@ export const groupPermissions = (groupId: string) => {
return {
queryKey: [...getGroupQueryKey(groupId), "permissions"],
queryFn: () =>
checkAuthorization({
API.checkAuthorization({
checks: {
canUpdateGroup: {
object: {
+4 -4
View File
@@ -1,20 +1,20 @@
import * as API from "api/api";
import { type InsightsParams, type InsightsTemplateParams, API } 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),
};
};
export const insightsUserLatency = (params: API.InsightsParams) => {
export const insightsUserLatency = (params: InsightsParams) => {
return {
queryKey: ["insights", "userLatency", params.template_ids, params],
queryFn: () => 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),
+1 -1
View File
@@ -1,5 +1,5 @@
import type { GetJFrogXRayScanParams } from "api/api";
import * as API from "api/api";
import { API } from "api/api";
export const xrayScan = (params: GetJFrogXRayScanParams) => {
return {
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type * as TypesGen from "api/typesGenerated";
const appsKey = ["oauth2-provider", "apps"];
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const roles = () => {
return {
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient, QueryOptions } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type {
UpdateUserQuietHoursScheduleRequest,
UserQuietHoursScheduleResponse,
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryClient } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type { GitSSHKey } from "api/typesGenerated";
const getUserSSHKeyQueryKey = (userId: string) => [userId, "sshKey"];
+1 -1
View File
@@ -1,5 +1,5 @@
import type { MutationOptions, QueryClient, QueryOptions } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type {
CreateTemplateRequest,
CreateTemplateVersionRequest,
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const updateCheck = () => {
return {
+1 -1
View File
@@ -3,7 +3,7 @@ import type {
UseMutationOptions,
UseQueryOptions,
} from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type {
AuthorizationRequest,
GetUsersResponse,
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueryOptions, UseInfiniteQueryOptions } from "react-query";
import * as API from "api/api";
import { API } from "api/api";
import type {
WorkspaceBuild,
WorkspaceBuildParameter,
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const getWorkspaceQuotaQueryKey = (username: string) => [
username,
+4 -8
View File
@@ -1,8 +1,4 @@
import {
deleteWorkspaceAgentSharedPort,
getWorkspaceAgentSharedPorts,
upsertWorkspaceAgentSharedPort,
} from "api/api";
import { API } 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: () => API.getWorkspaceAgentSharedPorts(workspaceId),
};
};
export const upsertWorkspacePortShare = (workspaceId: string) => {
return {
mutationFn: async (options: UpsertWorkspaceAgentPortShareRequest) => {
await upsertWorkspaceAgentSharedPort(workspaceId, options);
await 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 API.deleteWorkspaceAgentSharedPort(workspaceId, options);
},
};
};
+6 -5
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, API } 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 }),
API.getWorkspaceByOwnerAndName(owner, name, {
include_deleted: true,
}),
};
};
@@ -111,7 +112,7 @@ export const updateDeadline = (
): UseMutationOptions<void, unknown, Dayjs> => {
return {
mutationFn: (deadline: Dayjs) => {
return putWorkspaceExtension(workspace.id, deadline);
return API.putWorkspaceExtension(workspace.id, deadline);
},
};
};
@@ -155,7 +156,7 @@ export const deleteWorkspace = (
queryClient: QueryClient,
) => {
return {
mutationFn: (options: API.DeleteWorkspaceOptions) => {
mutationFn: (options: DeleteWorkspaceOptions) => {
return API.deleteWorkspace(workspace.id, options);
},
onSuccess: async (build: WorkspaceBuild) => {
+3 -3
View File
@@ -1,5 +1,5 @@
import type { FC } from "react";
import { getUsers } from "api/api";
import { API } 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 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 API.getUsers({ q: query, limit: 25 });
let options: UserOption[] = usersRes.users.map((user) => ({
label: user.username,
value: user.username,
+6 -5
View File
@@ -8,7 +8,7 @@ import {
useState,
} from "react";
import { useQuery } from "react-query";
import { getWorkspaceProxies, getWorkspaceProxyRegions } from "api/api";
import { API } from "api/api";
import { cachedQuery } from "api/queries/util";
import type { Region, WorkspaceProxy } from "api/typesGenerated";
import { useAuthenticated } from "contexts/auth/RequireAuth";
@@ -108,10 +108,11 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
metadata: metadata.regions,
queryKey: ["get-proxies"],
queryFn: async (): Promise<readonly Region[]> => {
const endpoint = permissions.editWorkspaceProxies
? getWorkspaceProxies
: getWorkspaceProxyRegions;
const resp = await endpoint();
const apiCall = permissions.editWorkspaceProxies
? API.getWorkspaceProxies
: API.getWorkspaceProxyRegions;
const resp = await apiCall();
return resp.regions;
},
}),
+2 -1
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 { API } from "api/api";
import { isApiError } from "api/errors";
import { Loader } from "components/Loader/Loader";
import { ProxyProvider } from "contexts/ProxyContext";
@@ -18,6 +18,7 @@ export const RequireAuth: FC = () => {
return;
}
const axiosInstance = API.getAxiosInstance();
const interceptorHandle = axiosInstance.interceptors.response.use(
(okResponse) => okResponse,
(error: unknown) => {
+2 -1
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 { API } 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 = API.getAxiosInstance();
const proxyRequests = Object.keys(proxyChecks).map((latencyURL) => {
return axiosInstance.get(latencyURL, {
withCredentials: false,
@@ -8,7 +8,7 @@ import {
useState,
} from "react";
import { FixedSizeList as List } from "react-window";
import * as API from "api/api";
import { watchWorkspaceAgentLogs } from "api/api";
import type { WorkspaceAgentLogSource } from "api/typesGenerated";
import {
AGENT_LOG_LINE_HEIGHT,
@@ -193,7 +193,7 @@ export const useAgentLogs = (
return;
}
const socket = API.watchWorkspaceAgentLogs(agentId, {
const socket = watchWorkspaceAgentLogs(agentId, {
// Get all logs
after: 0,
onMessage: (logs) => {
@@ -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 { API } 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 API.getApiKey();
url = href.replaceAll(magicTokenString, key.key);
setFetchingSessionToken(false);
}
@@ -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 { API } 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: () => API.getAgentListeningPorts(agent.id),
enabled: agent.status === "connected",
refetchInterval: 5_000,
});
@@ -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 { API } from "api/api";
import type { DisplayApp } from "api/typesGenerated";
import { VSCodeIcon } from "components/Icons/VSCodeIcon";
import { VSCodeInsidersIcon } from "components/Icons/VSCodeInsidersIcon";
@@ -119,7 +119,7 @@ const VSCodeButton: FC<VSCodeDesktopButtonProps> = ({
disabled={loading}
onClick={() => {
setLoading(true);
getApiKey()
API.getApiKey()
.then(({ key }) => {
const query = new URLSearchParams({
owner: userName,
@@ -163,7 +163,7 @@ const VSCodeInsidersButton: FC<VSCodeDesktopButtonProps> = ({
disabled={loading}
onClick={() => {
setLoading(true);
getApiKey()
API.getApiKey()
.then(({ key }) => {
const query = new URLSearchParams({
owner: userName,
+1 -1
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 { API } from "api/api";
import { DEFAULT_RECORDS_PER_PAGE } from "components/PaginationWidget/utils";
import {
MockAuditLog,
@@ -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 { API } from "api/api";
import {
MockTemplateExample,
MockTemplateVersion,
@@ -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 { API } from "api/api";
import {
renderWithAuth,
waitForLoaderToBeRemoved,
@@ -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 { API } 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(API.createToken);
const {
data: tokenConfig,
isLoading: fetchingTokenConfig,
@@ -36,7 +36,7 @@ export const CreateTokenPage: FC = () => {
error: tokenFetchError,
} = useQuery({
queryKey: ["tokenconfig"],
queryFn: getTokenConfig,
queryFn: API.getTokenConfig,
});
const [formError, setFormError] = useState<unknown>(undefined);
@@ -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 { API } from "api/api";
import {
MockTemplate,
MockUser,
@@ -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 { API } 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: () => API.getUserParameters(templateQuery.data!.id),
enabled: autofillEnabled && templateQuery.isSuccess,
});
const autofillParameters = getAutofillParameters(
@@ -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 { API } 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(API.createLicense, {
onSuccess: () => {
displaySuccess("You have successfully added a license");
navigate("/deployment/licenses?success=true");
@@ -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 { API } from "api/api";
import { getErrorMessage } from "api/errors";
import { entitlements, refreshEntitlements } from "api/queries/entitlements";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
@@ -36,7 +36,7 @@ const LicensesSettingsPage: FC = () => {
}, [entitlementsQuery.error]);
const { mutate: removeLicenseApi, isLoading: isRemovingLicense } =
useMutation(removeLicense, {
useMutation(API.removeLicense, {
onSuccess: () => {
displaySuccess("Successfully removed license");
void queryClient.invalidateQueries(["licenses"]);
@@ -48,7 +48,7 @@ const LicensesSettingsPage: FC = () => {
const { data: licenses, isLoading } = useQuery({
queryKey: ["licenses"],
queryFn: () => getLicenses(),
queryFn: () => API.getLicenses(),
});
useEffect(() => {
@@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { API } from "api/api";
import { TemplateLayout } from "pages/TemplatePage/TemplateLayout";
import {
MockTemplate,
@@ -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 { API } 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: () =>
API.getTemplateVersionRichParameters(template.active_version_id),
});
return (
@@ -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 { API } from "api/api";
import type { AuthorizationRequest } from "api/typesGenerated";
import { ErrorAlert } from "components/Alert/ErrorAlert";
import { Loader } from "components/Loader/Loader";
@@ -39,10 +35,11 @@ const templatePermissions = (
});
const fetchTemplate = async (organizationId: string, templateName: string) => {
const template = await getTemplateByName(organizationId, templateName);
const template = await API.getTemplateByName(organizationId, templateName);
const [activeVersion, permissions] = await Promise.all([
getTemplateVersion(template.active_version_id),
checkAuthorization({
API.getTemplateVersion(template.active_version_id),
API.checkAuthorization({
checks: templatePermissions(template.id),
}),
]);
@@ -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 { API } 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: () => API.getTemplateVersionResources(activeVersion.id),
});
return (
@@ -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 { API } 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: () => 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 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 API.archiveTemplateVersion(templateVersionId);
},
onSuccess: async () => {
// The reload is unfortunate. When a version is archived, we should hide
@@ -1,5 +1,5 @@
import { act, renderHook, waitFor } from "@testing-library/react";
import * as API from "api/api";
import { API } from "api/api";
import { MockTemplate } from "testHelpers/entities";
import { useDeletionDialogState } from "./useDeletionDialogState";
@@ -1,5 +1,5 @@
import { useState } from "react";
import { deleteTemplate } from "api/api";
import { API } 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 API.deleteTemplate(templateId);
onDelete();
} catch (e) {
setState({ status: "confirming" });
@@ -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 { API, 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";
@@ -138,7 +138,7 @@ describe("TemplateSettingsPage", () => {
http.get("/api/v2/entitlements", () => {
return HttpResponse.json({
...MockEntitlements,
features: API.withDefaultFeatures({
features: withDefaultFeatures({
access_control: { enabled: true, entitlement: "entitled" },
}),
});
@@ -163,7 +163,7 @@ describe("TemplateSettingsPage", () => {
http.get("/api/v2/entitlements", () => {
return HttpResponse.json({
...MockEntitlements,
features: API.withDefaultFeatures({
features: withDefaultFeatures({
access_control: { enabled: false, entitlement: "not_entitled" },
}),
});
@@ -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 { API } from "api/api";
import { templateByNameKey } from "api/queries/templates";
import type { UpdateTemplateMeta } from "api/typesGenerated";
import { displaySuccess } from "components/GlobalSnackbar/utils";
@@ -30,7 +30,9 @@ export const TemplateSettingsPage: FC = () => {
isLoading: isSubmitting,
error: submitError,
} = useMutation(
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
(data: UpdateTemplateMeta) => {
return API.updateTemplateMeta(template.id, data);
},
{
onSuccess: async (data) => {
// This update has a chance to return a 304 which means nothing was updated.
@@ -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 { API } from "api/api";
import { Language as FooterFormLanguage } from "components/FormFooter/FormFooter";
import {
MockEntitlementsWithScheduling,
@@ -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 { API } from "api/api";
import { templateByNameKey } from "api/queries/templates";
import type { UpdateTemplateMeta } from "api/typesGenerated";
import { displaySuccess } from "components/GlobalSnackbar/utils";
@@ -27,7 +27,7 @@ const TemplateSchedulePage: FC = () => {
isLoading: isSubmitting,
error: submitError,
} = useMutation(
(data: UpdateTemplateMeta) => updateTemplateMeta(template.id, data),
(data: UpdateTemplateMeta) => API.updateTemplateMeta(template.id, data),
{
onSuccess: async () => {
await queryClient.invalidateQueries(
@@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { API } from "api/api";
import { Language as FooterFormLanguage } from "components/FormFooter/FormFooter";
import {
MockTemplate,
@@ -4,7 +4,7 @@ import WS from "jest-websocket-mock";
import { HttpResponse, http } from "msw";
import { QueryClient } from "react-query";
import { RouterProvider, createMemoryRouter } from "react-router-dom";
import * as api from "api/api";
import * as apiModule from "api/api";
import { templateVersionVariablesKey } from "api/queries/templates";
import type { TemplateVersion } from "api/typesGenerated";
import { AppProviders } from "App";
@@ -26,6 +26,8 @@ import type { MonacoEditorProps } from "./MonacoEditor";
import { Language } from "./PublishTemplateVersionDialog";
import TemplateVersionEditorPage from "./TemplateVersionEditorPage";
const { API } = apiModule;
// 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(API, "uploadFile").mockResolvedValueOnce({ hash: "hash" });
jest.spyOn(API, "createTemplateVersion").mockResolvedValue({
...templateVersion,
job: {
...templateVersion.job,
@@ -81,10 +83,10 @@ const buildTemplateVersion = async (
},
});
jest
.spyOn(api, "getTemplateVersionByName")
.spyOn(API, "getTemplateVersionByName")
.mockResolvedValue(templateVersion);
jest
.spyOn(api, "watchBuildLogsByTemplateVersionId")
.spyOn(apiModule, "watchBuildLogsByTemplateVersionId")
.mockImplementation((_, options) => {
options.onMessage(MockWorkspaceBuildLogs[0]);
options.onDone?.();
@@ -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(API, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const updateActiveTemplateVersion = jest
.spyOn(api, "updateActiveTemplateVersion")
.spyOn(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(API, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const updateActiveTemplateVersion = jest
.spyOn(api, "updateActiveTemplateVersion")
.spyOn(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(API, "patchTemplateVersion")
.mockResolvedValue(newTemplateVersion);
const publishButton = within(topbar).getByRole("button", {
name: "Publish",
@@ -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 { API } 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(API.patchTemplateVersion(version.id, data));
}
if (isActiveVersion) {
publishActions.push(
updateActiveTemplateVersion(version.template_id!, {
API.updateActiveTemplateVersion(version.template_id!, {
id: version.id,
}),
);
@@ -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 { API } from "api/api";
import {
MockUser,
MockWorkspace,
@@ -1,5 +1,5 @@
import { fireEvent, screen, waitFor } from "@testing-library/react";
import * as API from "api/api";
import { API } from "api/api";
import { mockApiError } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import * as AccountForm from "./AccountForm";
@@ -1,6 +1,6 @@
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import * as API from "api/api";
import { API } from "api/api";
import { MockUser } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import { AppearancePage } from "./AppearancePage";
@@ -1,5 +1,5 @@
import { fireEvent, screen, within } from "@testing-library/react";
import * as API from "api/api";
import { API } from "api/api";
import { MockGitSSHKey, mockApiError } from "testHelpers/entities";
import { renderWithAuth } from "testHelpers/renderHelpers";
import { Language as SSHKeysPageLanguage, SSHKeysPage } from "./SSHKeysPage";
@@ -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 { API } from "api/api";
import type { OAuthConversionResponse } from "api/typesGenerated";
import { MockAuthMethodsAll, mockApiError } from "testHelpers/entities";
import {
@@ -1,6 +1,6 @@
import type { ComponentProps, FC } from "react";
import { useMutation, useQuery } from "react-query";
import { getUserLoginType } from "api/api";
import { API } 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: API.getUserLoginType,
});
const singleSignOnSection = useSingleSignOnSection();
@@ -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 { API } 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(API.convertToOAUTH, {
onSuccess: (data) => {
const loginTypeMsg =
data.to_type === "github" ? "Github" : "OpenID Connect";
@@ -4,7 +4,7 @@ import {
useQuery,
useQueryClient,
} from "react-query";
import { getTokens, deleteToken } from "api/api";
import { API } from "api/api";
import type { TokensFilter } from "api/typesGenerated";
// Load all tokens
@@ -12,10 +12,7 @@ export const useTokensData = ({ include_all }: TokensFilter) => {
const queryKey = ["tokens", include_all];
const result = useQuery({
queryKey,
queryFn: () =>
getTokens({
include_all,
}),
queryFn: () => API.getTokens({ include_all }),
});
return {
@@ -29,7 +26,7 @@ export const useDeleteToken = (queryKey: QueryKey) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteToken,
mutationFn: API.deleteToken,
onSuccess: () => {
// Invalidate and refetch
void queryClient.invalidateQueries(queryKey);
+1 -1
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 { API } from "api/api";
import type { Role } from "api/typesGenerated";
import {
MockUser,
@@ -1,6 +1,6 @@
import { screen, waitFor } from "@testing-library/react";
import WS from "jest-websocket-mock";
import * as API from "api/api";
import { API } from "api/api";
import {
MockWorkspace,
MockWorkspaceAgent,
@@ -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 { API } 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 API.getWorkspaceBuilds(build?.workspace_id ?? "", {
since: dayjs().add(-30, "day").toISOString(),
});
},
@@ -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 { API } 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: () => API.getWorkspaceParameters(workspace),
});
const ephemeralParameters = parameters
? parameters.templateVersionRichParameters.filter((p) => p.ephemeral)
@@ -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 apiModule from "api/api";
import type { TemplateVersionParameter, Workspace } from "api/typesGenerated";
import EventSourceMock from "eventsourcemock";
import {
@@ -22,16 +22,18 @@ import { renderWithAuth } from "testHelpers/renderHelpers";
import { server } from "testHelpers/server";
import { WorkspacePage } from "./WorkspacePage";
const { API, MissingBuildParameters } = apiModule;
// 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, "getWorkspaceByOwnerAndName").mockResolvedValue(workspace);
jest.spyOn(API, "getTemplate").mockResolvedValueOnce(MockTemplate);
jest.spyOn(API, "getTemplateVersionRichParameters").mockResolvedValueOnce([]);
jest
.spyOn(api, "getDeploymentConfig")
.spyOn(API, "getDeploymentConfig")
.mockResolvedValueOnce(MockDeploymentConfig);
jest
.spyOn(api, "watchWorkspaceAgentLogs")
.spyOn(apiModule, "watchWorkspaceAgentLogs")
.mockImplementation((_, options) => {
options.onDone?.();
return new WebSocket("");
@@ -87,7 +89,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(API, "deleteWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
await renderWorkspacePage(MockWorkspace);
@@ -127,7 +129,7 @@ describe("WorkspacePage", () => {
);
const deleteWorkspaceMock = jest
.spyOn(api, "deleteWorkspace")
.spyOn(API, "deleteWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuildDelete);
await renderWorkspacePage(MockFailedWorkspace);
@@ -173,7 +175,7 @@ describe("WorkspacePage", () => {
);
const startWorkspaceMock = jest
.spyOn(api, "startWorkspace")
.spyOn(API, "startWorkspace")
.mockImplementation(() => Promise.resolve(MockWorkspaceBuild));
await testButton(MockStoppedWorkspace, "Start", startWorkspaceMock);
@@ -181,7 +183,7 @@ describe("WorkspacePage", () => {
it("requests a stop job when the user presses Stop", async () => {
const stopWorkspaceMock = jest
.spyOn(api, "stopWorkspace")
.spyOn(API, "stopWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
await testButton(MockWorkspace, "Stop", stopWorkspaceMock);
@@ -189,7 +191,7 @@ describe("WorkspacePage", () => {
it("requests a stop when the user presses Restart", async () => {
const stopWorkspaceMock = jest
.spyOn(api, "stopWorkspace")
.spyOn(API, "stopWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
// Render
@@ -215,7 +217,7 @@ describe("WorkspacePage", () => {
);
const cancelWorkspaceMock = jest
.spyOn(api, "cancelWorkspaceBuild")
.spyOn(API, "cancelWorkspaceBuild")
.mockImplementation(() => Promise.resolve({ message: "job canceled" }));
await testButton(MockStartingWorkspace, "Cancel", cancelWorkspaceMock);
@@ -224,11 +226,11 @@ describe("WorkspacePage", () => {
it("requests an update when the user presses Update", async () => {
// Mocks
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(API, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockOutdatedWorkspace);
const updateWorkspaceMock = jest
.spyOn(api, "updateWorkspace")
.spyOn(API, "updateWorkspace")
.mockResolvedValueOnce(MockWorkspaceBuild);
// Render
@@ -249,12 +251,12 @@ describe("WorkspacePage", () => {
it("updates the parameters when they are missing during update", async () => {
// Mocks
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(API, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockOutdatedWorkspace);
const updateWorkspaceSpy = jest
.spyOn(api, "updateWorkspace")
.spyOn(API, "updateWorkspace")
.mockRejectedValueOnce(
new api.MissingBuildParameters(
new MissingBuildParameters(
[MockTemplateVersionParameter1, MockTemplateVersionParameter2],
MockOutdatedWorkspace.template_active_version_id,
),
@@ -271,7 +273,7 @@ describe("WorkspacePage", () => {
// The update was called
await waitFor(() => {
expect(api.updateWorkspace).toBeCalled();
expect(API.updateWorkspace).toBeCalled();
updateWorkspaceSpy.mockClear();
});
@@ -294,7 +296,7 @@ describe("WorkspacePage", () => {
// Check if the update was called using the values from the form
await waitFor(() => {
expect(api.updateWorkspace).toBeCalledWith(MockOutdatedWorkspace, [
expect(API.updateWorkspace).toBeCalledWith(MockOutdatedWorkspace, [
{
name: MockTemplateVersionParameter1.name,
value: "some-value",
@@ -309,7 +311,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(API, "getWorkspaceParameters").mockResolvedValue({
templateVersionRichParameters: [
{
...MockTemplateVersionParameter1,
@@ -321,7 +323,7 @@ describe("WorkspacePage", () => {
],
buildParameters: [{ name: "rebuild", value: "false" }],
});
const restartWorkspaceSpy = jest.spyOn(api, "restartWorkspace");
const restartWorkspaceSpy = jest.spyOn(API, "restartWorkspace");
const user = userEvent.setup();
await renderWorkspacePage(MockWorkspace);
await user.click(screen.getByTestId("build-parameters-button"));
@@ -351,7 +353,7 @@ describe("WorkspacePage", () => {
const retryDebugButtonRe = /^Debug$/i;
describe("Retries a failed 'Start' transition", () => {
const mockStart = jest.spyOn(api, "startWorkspace");
const mockStart = jest.spyOn(API, "startWorkspace");
const failedStart: Workspace = {
...MockFailedWorkspace,
latest_build: {
@@ -384,7 +386,7 @@ describe("WorkspacePage", () => {
});
describe("Retries a failed 'Stop' transition", () => {
const mockStop = jest.spyOn(api, "stopWorkspace");
const mockStop = jest.spyOn(API, "stopWorkspace");
const failedStop: Workspace = {
...MockFailedWorkspace,
latest_build: {
@@ -405,7 +407,7 @@ describe("WorkspacePage", () => {
});
describe("Retries a failed 'Delete' transition", () => {
const mockDelete = jest.spyOn(api, "deleteWorkspace");
const mockDelete = jest.spyOn(API, "deleteWorkspace");
const failedDelete: Workspace = {
...MockFailedWorkspace,
latest_build: {
@@ -450,7 +452,7 @@ describe("WorkspacePage", () => {
return HttpResponse.json([parameter]);
}),
);
const startWorkspaceSpy = jest.spyOn(api, "startWorkspace");
const startWorkspaceSpy = jest.spyOn(API, "startWorkspace");
await renderWorkspacePage(workspace);
const retryWithBuildParametersButton = await screen.findByRole("button", {
@@ -496,7 +498,7 @@ describe("WorkspacePage", () => {
return HttpResponse.json([parameter]);
}),
);
const startWorkspaceSpy = jest.spyOn(api, "startWorkspace");
const startWorkspaceSpy = jest.spyOn(API, "startWorkspace");
await renderWorkspacePage(workspace);
const retryWithBuildParametersButton = await screen.findByRole("button", {
@@ -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, API } from "api/api";
import { getErrorMessage } from "api/errors";
import { buildInfo } from "api/queries/buildInfo";
import { deploymentConfig, deploymentSSHConfig } from "api/queries/deployment";
@@ -83,7 +83,7 @@ export const WorkspaceReadyPage: FC<WorkspaceReadyPageProps> = ({
}>({ open: false });
const { mutate: mutateRestartWorkspace, isLoading: isRestarting } =
useMutation({
mutationFn: restartWorkspace,
mutationFn: API.restartWorkspace,
});
// SSH Prefix
@@ -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 { API } from "api/api";
import { workspaceByOwnerAndName } from "api/queries/workspaces";
import { GlobalSnackbar } from "components/GlobalSnackbar/GlobalSnackbar";
import { ThemeProvider } from "contexts/ThemeProvider";
@@ -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 { API } from "api/api";
import {
MockWorkspace,
MockTemplateVersionParameter1,
@@ -20,15 +20,15 @@ import WorkspaceParametersPage from "./WorkspaceParametersPage";
test("Submit the workspace settings page successfully", async () => {
// Mock the API calls that loads data
jest
.spyOn(api, "getWorkspaceByOwnerAndName")
.spyOn(API, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce(MockWorkspace);
jest.spyOn(api, "getTemplateVersionRichParameters").mockResolvedValueOnce([
jest.spyOn(API, "getTemplateVersionRichParameters").mockResolvedValueOnce([
MockTemplateVersionParameter1,
MockTemplateVersionParameter2,
// Immutable parameters
MockTemplateVersionParameter4,
]);
jest.spyOn(api, "getWorkspaceBuildParameters").mockResolvedValueOnce([
jest.spyOn(API, "getWorkspaceBuildParameters").mockResolvedValueOnce([
MockWorkspaceBuildParameter1,
MockWorkspaceBuildParameter2,
// Immutable value
@@ -36,7 +36,7 @@ test("Submit the workspace settings page successfully", async () => {
]);
// Mock the API calls that submit data
const postWorkspaceBuildSpy = jest
.spyOn(api, "postWorkspaceBuild")
.spyOn(API, "postWorkspaceBuild")
.mockResolvedValue(MockWorkspaceBuild);
// Setup event and rendering
const user = userEvent.setup();
@@ -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 { API } 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: () => API.getWorkspaceParameters(workspace),
});
const navigate = useNavigate();
const updateParameters = useMutation({
mutationFn: (buildParameters: WorkspaceBuildParameter[]) =>
postWorkspaceBuild(workspace.id, {
API.postWorkspaceBuild(workspace.id, {
transition: "start",
rich_parameter_values: buildParameters,
}),
@@ -93,7 +93,7 @@ const WorkspaceParametersPage: FC = () => {
export type WorkspaceParametersPageViewProps = {
workspace: Workspace;
canChangeVersions: boolean;
data: Awaited<ReturnType<typeof getWorkspaceParameters>> | undefined;
data: Awaited<ReturnType<typeof API.getWorkspaceParameters>> | undefined;
submitError: unknown;
isSubmitting: boolean;
onSubmit: (formValues: WorkspaceParametersFormValues) => void;
@@ -1,5 +1,5 @@
import { screen } from "@testing-library/react";
import * as API from "api/api";
import { API } from "api/api";
import { defaultSchedule } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule";
import { MockTemplate } from "testHelpers/entities";
import { render } from "testHelpers/renderHelpers";
@@ -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 { API } from "api/api";
import { checkAuthorization } from "api/queries/authCheck";
import { templateByName } from "api/queries/templates";
import { workspaceByOwnerAndNameKey } from "api/queries/workspaces";
@@ -72,7 +68,7 @@ export const WorkspaceSchedulePage: FC = () => {
const [isConfirmingApply, setIsConfirmingApply] = useState(false);
const { mutate: updateWorkspace } = useMutation({
mutationFn: () =>
startWorkspace(workspace.id, workspace.template_active_version_id),
API.startWorkspace(workspace.id, workspace.template_active_version_id),
});
return (
@@ -167,11 +163,11 @@ const submitSchedule = async (data: SubmitScheduleData) => {
const actions: Promise<void>[] = [];
if (autostartChanged) {
actions.push(putWorkspaceAutostart(workspace.id, autostart));
actions.push(API.putWorkspaceAutostart(workspace.id, autostart));
}
if (autostopChanged) {
actions.push(putWorkspaceAutostop(workspace.id, ttl));
actions.push(API.putWorkspaceAutostop(workspace.id, ttl));
}
return Promise.all(actions);
@@ -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 { API } 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(API, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce({ ...MockWorkspace });
// Mock the API calls that submit data
const patchWorkspaceSpy = jest
.spyOn(api, "patchWorkspace")
.spyOn(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(API, "getWorkspaceByOwnerAndName")
.mockResolvedValueOnce({ ...MockWorkspace, allow_renames: false });
renderWithWorkspaceSettingsLayout(<WorkspaceSettingsPage />, {
route: "/@test-user/test-workspace/settings",
@@ -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 { API } 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(
API.patchWorkspace(workspace.id, { name: formValues.name }),
API.updateWorkspaceAutomaticUpdates(
workspace.id,
formValues.automatic_updates,
),
@@ -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 { API } 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 API.getTemplateVersion(version.id)),
}),
})),
});
@@ -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 { API } from "api/api";
import type { Workspace } from "api/typesGenerated";
import {
MockStoppedWorkspace,
+7 -14
View File
@@ -1,12 +1,5 @@
import { useMutation } from "react-query";
import {
deleteWorkspace,
deleteFavoriteWorkspace,
putFavoriteWorkspace,
startWorkspace,
stopWorkspace,
updateWorkspace,
} from "api/api";
import { API } 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),
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) => API.stopWorkspace(w.id)));
},
onSuccess,
onError: () => {
@@ -43,7 +36,7 @@ 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) => API.deleteWorkspace(w.id)));
},
onSuccess,
onError: () => {
@@ -56,7 +49,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => w.outdated && !w.dormant_at)
.map((w) => updateWorkspace(w)),
.map((w) => API.updateWorkspace(w)),
);
},
onSuccess,
@@ -70,7 +63,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => !w.favorite)
.map((w) => putFavoriteWorkspace(w.id)),
.map((w) => API.putFavoriteWorkspace(w.id)),
);
},
onSuccess,
@@ -84,7 +77,7 @@ export function useBatchActions(options: UseBatchActionsProps) {
return Promise.all(
workspaces
.filter((w) => w.favorite)
.map((w) => deleteFavoriteWorkspace(w.id)),
.map((w) => API.deleteFavoriteWorkspace(w.id)),
);
},
onSuccess,
+3 -3
View File
@@ -5,7 +5,7 @@ import {
useQuery,
useQueryClient,
} from "react-query";
import { getWorkspaces, updateWorkspaceVersion } from "api/api";
import { API } from "api/api";
import { getErrorMessage } from "api/errors";
import type {
Workspace,
@@ -30,7 +30,7 @@ export const useWorkspacesData = ({
const result = useQuery({
queryKey,
queryFn: () =>
getWorkspaces({
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: API.updateWorkspaceVersion,
onMutate: async (workspace) => {
await queryClient.cancelQueries({ queryKey });
queryClient.setQueryData<WorkspacesResponse>(queryKey, (oldResponse) => {
@@ -1,4 +1,4 @@
import { getTemplates } from "api/api";
import { API } 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 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 API.getTemplates(organizationId);
const filteredTemplates = templates.filter(
(template) =>
template.name.toLowerCase().includes(query.toLowerCase()) ||
+1 -1
View File
@@ -1,4 +1,4 @@
import * as API from "api/api";
import { API } from "api/api";
export const terminalWebsocketUrl = async (
baseUrl: string | undefined,