UNPKG

@coder/backstage-plugin-coder

Version:

Create and manage Coder workspaces from Backstage

1,349 lines (1,339 loc) 111 kB
import { createRouteRef, createApiRef, useApi, errorApiRef, createPlugin, createApiFactory, discoveryApiRef, configApiRef, identityApiRef, createComponentExtension } from '@backstage/core-plugin-api'; import globalAxios, { isAxiosError, AxiosError } from 'axios'; import 'ua-parser-js'; import React, { useState, useEffect, createContext, useContext, useCallback, useRef, useLayoutEffect, Component, useMemo, forwardRef } from 'react'; import { ValiError, optional, union, literal, undefined_, object, string, record, parse } from 'valibot'; import { scmIntegrationsApiRef } from '@backstage/integration-react'; import { useEntity, getEntitySourceLocation } from '@backstage/plugin-catalog-react'; import { createPortal } from 'react-dom'; import { useQuery, useQueryClient, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { makeStyles } from '@material-ui/core'; import { LinkButton, Link } from '@backstage/core-components'; import Dialog from '@material-ui/core/Dialog'; import DialogContent from '@material-ui/core/DialogContent'; import DialogTitle from '@material-ui/core/DialogTitle'; import DialogActions from '@material-ui/core/DialogActions'; import TextField from '@material-ui/core/TextField'; import ErrorIcon from '@material-ui/icons/ErrorOutline'; import SyncIcon from '@material-ui/icons/Sync'; const rootRouteRef = createRouteRef({ id: "coder" }); const CODER_API_REF_ID_PREFIX = "backstage-plugin-coder"; const DEFAULT_TANSTACK_QUERY_RETRY_COUNT = 3; var __defProp$3 = Object.defineProperty; var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$3 = (obj, key, value) => { __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; function areSameByReference(v1, v2) { return Object.is(v1, v2) || v1 === 0 && v2 === 0; } function defaultDidSnapshotsChange(oldSnapshot, newSnapshot) { if (areSameByReference(oldSnapshot, newSnapshot)) { return false; } const oldIsPrimitive = typeof oldSnapshot !== "object" || oldSnapshot === null; const newIsPrimitive = typeof newSnapshot !== "object" || newSnapshot === null; if (oldIsPrimitive && newIsPrimitive) { const numbersAreWithinTolerance = typeof oldSnapshot === "number" && typeof newSnapshot === "number" && Math.abs(oldSnapshot - newSnapshot) < 5e-5; if (numbersAreWithinTolerance) { return false; } return oldSnapshot !== newSnapshot; } const changedFromObjectToPrimitive = !oldIsPrimitive && newIsPrimitive; const changedFromPrimitiveToObject = oldIsPrimitive && !newIsPrimitive; if (changedFromObjectToPrimitive || changedFromPrimitiveToObject) { return true; } if (Array.isArray(oldSnapshot) && Array.isArray(newSnapshot)) { const sameByShallowComparison = oldSnapshot.length === newSnapshot.length && oldSnapshot.every( (element, index) => areSameByReference(element, newSnapshot[index]) ); return !sameByShallowComparison; } const oldInnerValues = Object.values(oldSnapshot); const newInnerValues = Object.values(newSnapshot); if (oldInnerValues.length !== newInnerValues.length) { return true; } for (const [index, value] of oldInnerValues.entries()) { if (value !== newInnerValues[index]) { return true; } } return false; } class StateSnapshotManager { constructor(options) { __publicField$3(this, "subscriptions"); __publicField$3(this, "didSnapshotsChange"); __publicField$3(this, "activeSnapshot"); __publicField$3(this, "unsubscribe", (callback) => { this.subscriptions.delete(callback); }); __publicField$3(this, "subscribe", (callback) => { this.subscriptions.add(callback); return () => this.unsubscribe(callback); }); __publicField$3(this, "getSnapshot", () => { return this.activeSnapshot; }); __publicField$3(this, "updateSnapshot", (newSnapshot) => { const snapshotsChanged = this.didSnapshotsChange( this.activeSnapshot, newSnapshot ); if (!snapshotsChanged) { return; } this.activeSnapshot = newSnapshot; this.notifySubscriptions(); }); const { initialSnapshot, didSnapshotsChange } = options; this.subscriptions = /* @__PURE__ */ new Set(); this.activeSnapshot = initialSnapshot; this.didSnapshotsChange = didSnapshotsChange != null ? didSnapshotsChange : defaultDidSnapshotsChange; } notifySubscriptions() { const snapshotBinding = this.activeSnapshot; this.subscriptions.forEach((cb) => cb(snapshotBinding)); } } var __defProp$2 = Object.defineProperty; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$2 = (obj, key, value) => { __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; const CODER_PROXY_PREFIX = "/coder"; const BASE_URL_KEY_FOR_CONFIG_API = "backend.baseUrl"; const PROXY_URL_KEY_FOR_DISCOVERY_API = "proxy"; const defaultUrlPrefixes = { proxyPrefix: `/api/proxy` }; const proxyRouteReplacer = /\/api\/proxy.*?$/; class UrlSync { constructor(setup) { __publicField$2(this, "discoveryApi"); __publicField$2(this, "urlCache"); __publicField$2(this, "urlPrefixes"); /* *************************************************************************** * All public functions should be defined as arrow functions to ensure they * can be passed around React without risk of losing their `this` context ****************************************************************************/ __publicField$2(this, "getApiEndpoint", async () => { const proxyRoot = await this.discoveryApi.getBaseUrl( PROXY_URL_KEY_FOR_DISCOVERY_API ); const newSnapshot = this.prepareNewSnapshot(proxyRoot); this.urlCache.updateSnapshot(newSnapshot); return newSnapshot.apiRoute; }); __publicField$2(this, "getAssetsEndpoint", async () => { const proxyRoot = await this.discoveryApi.getBaseUrl( PROXY_URL_KEY_FOR_DISCOVERY_API ); const newSnapshot = this.prepareNewSnapshot(proxyRoot); this.urlCache.updateSnapshot(newSnapshot); return newSnapshot.assetsRoute; }); __publicField$2(this, "getCachedUrls", () => { return this.urlCache.getSnapshot(); }); __publicField$2(this, "unsubscribe", (callback) => { this.urlCache.unsubscribe(callback); }); __publicField$2(this, "subscribe", (callback) => { this.urlCache.subscribe(callback); return () => this.unsubscribe(callback); }); const { apis, urlPrefixes = {} } = setup; const { discoveryApi, configApi } = apis; this.discoveryApi = discoveryApi; this.urlPrefixes = { ...defaultUrlPrefixes, ...urlPrefixes }; const proxyRoot = this.getProxyRootFromConfigApi(configApi); this.urlCache = new StateSnapshotManager({ initialSnapshot: this.prepareNewSnapshot(proxyRoot) }); } // ConfigApi is literally only used because it offers a synchronous way to // get an initial URL to use from inside the constructor. Should not be used // beyond initial constructor call, so it's not being embedded in the class getProxyRootFromConfigApi(configApi) { const baseUrl = configApi.getString(BASE_URL_KEY_FOR_CONFIG_API); return `${baseUrl}${this.urlPrefixes.proxyPrefix}`; } prepareNewSnapshot(newProxyUrl) { return { baseUrl: newProxyUrl.replace(proxyRouteReplacer, ""), assetsRoute: `${newProxyUrl}${CODER_PROXY_PREFIX}`, apiRoute: `${newProxyUrl}${CODER_PROXY_PREFIX}` }; } } const urlSyncApiRef = createApiRef({ id: `${CODER_API_REF_ID_PREFIX}.url-sync` }); const delay = (ms) => new Promise((res) => { setTimeout(res, ms); }); const FeatureNames = [ "access_control", "advanced_template_scheduling", "appearance", "audit_log", "browser_only", "control_shared_ports", "custom_roles", "external_provisioner_daemons", "external_token_encryption", "high_availability", "multiple_external_auth", "scim", "template_rbac", "user_limit", "user_role_management", "workspace_batch_actions", "workspace_proxy" ]; var __defProp$1 = Object.defineProperty; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField$1 = (obj, key, value) => { __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; const getMissingParameters = (oldBuildParameters, newBuildParameters, templateParameters) => { const missingParameters = []; const requiredParameters = []; templateParameters.forEach((p) => { const isMutableAndRequired = p.mutable && p.required; const isImmutable = !p.mutable; if (isMutableAndRequired || isImmutable) { requiredParameters.push(p); } }); for (const parameter of requiredParameters) { let buildParameter = newBuildParameters.find( (p) => p.name === parameter.name ); if (!buildParameter) { buildParameter = oldBuildParameters.find((p) => p.name === parameter.name); } if (buildParameter) { continue; } missingParameters.push(parameter); } templateParameters.forEach((templateParameter) => { if (templateParameter.options.length === 0) { return; } let buildParameter = newBuildParameters.find( (p) => p.name === templateParameter.name ); if (!buildParameter) { buildParameter = oldBuildParameters.find( (p) => p.name === templateParameter.name ); } if (!buildParameter) { return; } const matchingOption = templateParameter.options.find( (option) => option.value === (buildParameter == null ? void 0 : buildParameter.value) ); if (!matchingOption) { missingParameters.push(templateParameter); } }); return missingParameters; }; const getURLWithSearchParams = (basePath, options) => { if (!options) { return basePath; } const searchParams = new URLSearchParams(); const keys = Object.keys(options); keys.forEach((key) => { const value = options[key]; if (value !== void 0 && value !== "") { searchParams.append(key, value.toString()); } }); const searchString = searchParams.toString(); return searchString ? `${basePath}?${searchString}` : basePath; }; const withDefaultFeatures = (fs) => { for (const feature of FeatureNames) { if (fs[feature] !== void 0) { continue; } fs[feature] = { enabled: false, entitlement: "not_entitled" }; } return fs; }; const BASE_CONTENT_TYPE_JSON = { "Content-Type": "application/json" }; class MissingBuildParameters extends Error { constructor(parameters, versionId) { super("Missing build parameters."); __publicField$1(this, "parameters", []); __publicField$1(this, "versionId"); this.parameters = parameters; this.versionId = versionId; } } class ApiMethods { constructor(axios) { this.axios = axios; __publicField$1(this, "login", async (email, password) => { const payload = JSON.stringify({ email, password }); const response = await this.axios.post( "/api/v2/users/login", payload, { headers: { ...BASE_CONTENT_TYPE_JSON } } ); return response.data; }); __publicField$1(this, "convertToOAUTH", async (request) => { const response = await this.axios.post( "/api/v2/users/me/convert-login", request ); return response.data; }); __publicField$1(this, "logout", async () => { return this.axios.post("/api/v2/users/logout"); }); __publicField$1(this, "getAuthenticatedUser", async () => { const response = await this.axios.get("/api/v2/users/me"); return response.data; }); __publicField$1(this, "getUserParameters", async (templateID) => { const response = await this.axios.get( `/api/v2/users/me/autofill-parameters?template_id=${templateID}` ); return response.data; }); __publicField$1(this, "getAuthMethods", async () => { const response = await this.axios.get( "/api/v2/users/authmethods" ); return response.data; }); __publicField$1(this, "getUserLoginType", async () => { const response = await this.axios.get( "/api/v2/users/me/login-type" ); return response.data; }); __publicField$1(this, "checkAuthorization", async (params) => { const response = await this.axios.post( `/api/v2/authcheck`, params ); return response.data; }); __publicField$1(this, "getApiKey", async () => { const response = await this.axios.post( "/api/v2/users/me/keys" ); return response.data; }); __publicField$1(this, "getTokens", async (params) => { const response = await this.axios.get( `/api/v2/users/me/keys/tokens`, { params } ); return response.data; }); __publicField$1(this, "deleteToken", async (keyId) => { await this.axios.delete(`/api/v2/users/me/keys/${keyId}`); }); __publicField$1(this, "createToken", async (params) => { const response = await this.axios.post( `/api/v2/users/me/keys/tokens`, params ); return response.data; }); __publicField$1(this, "getTokenConfig", async () => { const response = await this.axios.get( "/api/v2/users/me/keys/tokens/tokenconfig" ); return response.data; }); __publicField$1(this, "getUsers", async (options, signal) => { const url = getURLWithSearchParams("/api/v2/users", options); const response = await this.axios.get( url.toString(), { signal } ); return response.data; }); __publicField$1(this, "getOrganization", async (organizationId) => { const response = await this.axios.get( `/api/v2/organizations/${organizationId}` ); return response.data; }); __publicField$1(this, "getOrganizations", async () => { const response = await this.axios.get( "/api/v2/users/me/organizations" ); return response.data; }); __publicField$1(this, "getTemplate", async (templateId) => { const response = await this.axios.get( `/api/v2/templates/${templateId}` ); return response.data; }); __publicField$1(this, "getTemplates", async (organizationId, options) => { const params = {}; if ((options == null ? void 0 : options.deprecated) !== void 0) { params.deprecated = String(options.deprecated); } const response = await this.axios.get( `/api/v2/organizations/${organizationId}/templates`, { params } ); return response.data; }); __publicField$1(this, "getTemplateByName", async (organizationId, name) => { const response = await this.axios.get( `/api/v2/organizations/${organizationId}/templates/${name}` ); return response.data; }); __publicField$1(this, "getTemplateVersion", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}` ); return response.data; }); __publicField$1(this, "getTemplateVersionResources", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}/resources` ); return response.data; }); __publicField$1(this, "getTemplateVersionVariables", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}/variables` ); return response.data; }); __publicField$1(this, "getTemplateVersions", async (templateId) => { const response = await this.axios.get( `/api/v2/templates/${templateId}/versions` ); return response.data; }); __publicField$1(this, "getTemplateVersionByName", async (organizationId, templateName, versionName) => { const response = await this.axios.get( `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}` ); return response.data; }); __publicField$1(this, "getPreviousTemplateVersionByName", async (organizationId, templateName, versionName) => { try { const response = await this.axios.get( `/api/v2/organizations/${organizationId}/templates/${templateName}/versions/${versionName}/previous` ); return response.data; } catch (error) { const is404 = isAxiosError(error) && error.response && error.response.status === 404; if (is404) { return void 0; } throw error; } }); __publicField$1(this, "createTemplateVersion", async (organizationId, data) => { const response = await this.axios.post( `/api/v2/organizations/${organizationId}/templateversions`, data ); return response.data; }); __publicField$1(this, "getTemplateVersionExternalAuth", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}/external-auth` ); return response.data; }); __publicField$1(this, "getTemplateVersionRichParameters", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}/rich-parameters` ); return response.data; }); __publicField$1(this, "createTemplate", async (organizationId, data) => { const response = await this.axios.post( `/api/v2/organizations/${organizationId}/templates`, data ); return response.data; }); __publicField$1(this, "updateActiveTemplateVersion", async (templateId, data) => { const response = await this.axios.patch( `/api/v2/templates/${templateId}/versions`, data ); return response.data; }); __publicField$1(this, "patchTemplateVersion", async (templateVersionId, data) => { const response = await this.axios.patch( `/api/v2/templateversions/${templateVersionId}`, data ); return response.data; }); __publicField$1(this, "archiveTemplateVersion", async (templateVersionId) => { const response = await this.axios.post( `/api/v2/templateversions/${templateVersionId}/archive` ); return response.data; }); __publicField$1(this, "unarchiveTemplateVersion", async (templateVersionId) => { const response = await this.axios.post( `/api/v2/templateversions/${templateVersionId}/unarchive` ); return response.data; }); __publicField$1(this, "updateTemplateMeta", async (templateId, data) => { const response = await this.axios.patch( `/api/v2/templates/${templateId}`, data ); if (response.status === 304) { return null; } return response.data; }); __publicField$1(this, "deleteTemplate", async (templateId) => { const response = await this.axios.delete( `/api/v2/templates/${templateId}` ); return response.data; }); __publicField$1(this, "getWorkspace", async (workspaceId, params) => { const response = await this.axios.get( `/api/v2/workspaces/${workspaceId}`, { params } ); return response.data; }); __publicField$1(this, "getWorkspaces", async (options) => { const url = getURLWithSearchParams("/api/v2/workspaces", options); const response = await this.axios.get(url); return response.data; }); __publicField$1(this, "getWorkspaceByOwnerAndName", async (username = "me", workspaceName, params) => { const response = await this.axios.get( `/api/v2/users/${username}/workspace/${workspaceName}`, { params } ); return response.data; }); __publicField$1(this, "getWorkspaceBuildByNumber", async (username = "me", workspaceName, buildNumber) => { const response = await this.axios.get( `/api/v2/users/${username}/workspace/${workspaceName}/builds/${buildNumber}` ); return response.data; }); __publicField$1(this, "waitForBuild", (build) => { return new Promise((res, reject) => { void (async () => { let latestJobInfo = void 0; while ( // eslint-disable-next-line no-loop-func -- Not great, but should be harmless !["succeeded", "canceled"].some( (status) => latestJobInfo == null ? void 0 : latestJobInfo.status.includes(status) ) ) { const { job } = await this.getWorkspaceBuildByNumber( build.workspace_owner_name, build.workspace_name, build.build_number ); latestJobInfo = job; if (latestJobInfo.status === "failed") { return reject(latestJobInfo); } await delay(1e3); } return res(latestJobInfo); })(); }); }); __publicField$1(this, "postWorkspaceBuild", async (workspaceId, data) => { const response = await this.axios.post( `/api/v2/workspaces/${workspaceId}/builds`, data ); return response.data; }); __publicField$1(this, "startWorkspace", (workspaceId, templateVersionId, logLevel, buildParameters) => { return this.postWorkspaceBuild(workspaceId, { transition: "start", template_version_id: templateVersionId, log_level: logLevel, rich_parameter_values: buildParameters }); }); __publicField$1(this, "stopWorkspace", (workspaceId, logLevel) => { return this.postWorkspaceBuild(workspaceId, { transition: "stop", log_level: logLevel }); }); __publicField$1(this, "deleteWorkspace", (workspaceId, options) => { return this.postWorkspaceBuild(workspaceId, { transition: "delete", ...options }); }); __publicField$1(this, "cancelWorkspaceBuild", async (workspaceBuildId) => { const response = await this.axios.patch( `/api/v2/workspacebuilds/${workspaceBuildId}/cancel` ); return response.data; }); __publicField$1(this, "updateWorkspaceDormancy", async (workspaceId, dormant) => { const data = { dormant }; const response = await this.axios.put( `/api/v2/workspaces/${workspaceId}/dormant`, data ); return response.data; }); __publicField$1(this, "updateWorkspaceAutomaticUpdates", async (workspaceId, automaticUpdates) => { const req = { automatic_updates: automaticUpdates }; const response = await this.axios.put( `/api/v2/workspaces/${workspaceId}/autoupdates`, req ); return response.data; }); __publicField$1(this, "restartWorkspace", async ({ workspace, buildParameters }) => { const stopBuild = await this.stopWorkspace(workspace.id); const awaitedStopBuild = await this.waitForBuild(stopBuild); if ((awaitedStopBuild == null ? void 0 : awaitedStopBuild.status) === "canceled") { return; } const startBuild = await this.startWorkspace( workspace.id, workspace.latest_build.template_version_id, void 0, buildParameters ); await this.waitForBuild(startBuild); }); __publicField$1(this, "cancelTemplateVersionBuild", async (templateVersionId) => { const response = await this.axios.patch( `/api/v2/templateversions/${templateVersionId}/cancel` ); return response.data; }); __publicField$1(this, "createUser", async (user) => { const response = await this.axios.post( "/api/v2/users", user ); return response.data; }); __publicField$1(this, "createWorkspace", async (organizationId, userId = "me", workspace) => { const response = await this.axios.post( `/api/v2/organizations/${organizationId}/members/${userId}/workspaces`, workspace ); return response.data; }); __publicField$1(this, "patchWorkspace", async (workspaceId, data) => { await this.axios.patch(`/api/v2/workspaces/${workspaceId}`, data); }); __publicField$1(this, "getBuildInfo", async () => { const response = await this.axios.get("/api/v2/buildinfo"); return response.data; }); __publicField$1(this, "getUpdateCheck", async () => { const response = await this.axios.get("/api/v2/updatecheck"); return response.data; }); __publicField$1(this, "putWorkspaceAutostart", async (workspaceID, autostart) => { const payload = JSON.stringify(autostart); await this.axios.put( `/api/v2/workspaces/${workspaceID}/autostart`, payload, { headers: { ...BASE_CONTENT_TYPE_JSON } } ); }); __publicField$1(this, "putWorkspaceAutostop", async (workspaceID, ttl) => { const payload = JSON.stringify(ttl); await this.axios.put(`/api/v2/workspaces/${workspaceID}/ttl`, payload, { headers: { ...BASE_CONTENT_TYPE_JSON } }); }); __publicField$1(this, "updateProfile", async (userId, data) => { const response = await this.axios.put( `/api/v2/users/${userId}/profile`, data ); return response.data; }); __publicField$1(this, "updateAppearanceSettings", async (userId, data) => { const response = await this.axios.put( `/api/v2/users/${userId}/appearance`, data ); return response.data; }); __publicField$1(this, "getUserQuietHoursSchedule", async (userId) => { const response = await this.axios.get( `/api/v2/users/${userId}/quiet-hours` ); return response.data; }); __publicField$1(this, "updateUserQuietHoursSchedule", async (userId, data) => { const response = await this.axios.put( `/api/v2/users/${userId}/quiet-hours`, data ); return response.data; }); __publicField$1(this, "activateUser", async (userId) => { const response = await this.axios.put( `/api/v2/users/${userId}/status/activate` ); return response.data; }); __publicField$1(this, "suspendUser", async (userId) => { const response = await this.axios.put( `/api/v2/users/${userId}/status/suspend` ); return response.data; }); __publicField$1(this, "deleteUser", async (userId) => { await this.axios.delete(`/api/v2/users/${userId}`); }); // API definition: // https://github.com/coder/coder/blob/db665e7261f3c24a272ccec48233a3e276878239/coderd/users.go#L33-L53 __publicField$1(this, "hasFirstUser", async () => { var _a; try { await this.axios.get("/api/v2/users/first"); return true; } catch (error) { if (isAxiosError(error) && ((_a = error.response) == null ? void 0 : _a.status) === 404) { return false; } throw error; } }); __publicField$1(this, "createFirstUser", async (req) => { const response = await this.axios.post(`/api/v2/users/first`, req); return response.data; }); __publicField$1(this, "updateUserPassword", async (userId, updatePassword) => { await this.axios.put(`/api/v2/users/${userId}/password`, updatePassword); }); __publicField$1(this, "getRoles", async () => { const response = await this.axios.get( `/api/v2/users/roles` ); return response.data; }); __publicField$1(this, "updateUserRoles", async (roles, userId) => { const response = await this.axios.put( `/api/v2/users/${userId}/roles`, { roles } ); return response.data; }); __publicField$1(this, "getUserSSHKey", async (userId = "me") => { const response = await this.axios.get( `/api/v2/users/${userId}/gitsshkey` ); return response.data; }); __publicField$1(this, "regenerateUserSSHKey", async (userId = "me") => { const response = await this.axios.put( `/api/v2/users/${userId}/gitsshkey` ); return response.data; }); __publicField$1(this, "getWorkspaceBuilds", async (workspaceId, req) => { const response = await this.axios.get( getURLWithSearchParams(`/api/v2/workspaces/${workspaceId}/builds`, req) ); return response.data; }); __publicField$1(this, "getWorkspaceBuildLogs", async (buildId, before) => { const response = await this.axios.get( `/api/v2/workspacebuilds/${buildId}/logs?before=${before.getTime()}` ); return response.data; }); __publicField$1(this, "getWorkspaceAgentLogs", async (agentID) => { const response = await this.axios.get( `/api/v2/workspaceagents/${agentID}/logs` ); return response.data; }); __publicField$1(this, "putWorkspaceExtension", async (workspaceId, newDeadline) => { await this.axios.put(`/api/v2/workspaces/${workspaceId}/extend`, { deadline: newDeadline }); }); __publicField$1(this, "refreshEntitlements", async () => { await this.axios.post("/api/v2/licenses/refresh-entitlements"); }); __publicField$1(this, "getEntitlements", async () => { var _a; try { const response = await this.axios.get( "/api/v2/entitlements" ); return response.data; } catch (ex) { if (isAxiosError(ex) && ((_a = ex.response) == null ? void 0 : _a.status) === 404) { return { errors: [], features: withDefaultFeatures({}), has_license: false, require_telemetry: false, trial: false, warnings: [], refreshed_at: "" }; } throw ex; } }); __publicField$1(this, "getExperiments", async () => { var _a; try { const response = await this.axios.get( "/api/v2/experiments" ); return response.data; } catch (error) { if (isAxiosError(error) && ((_a = error.response) == null ? void 0 : _a.status) === 404) { return []; } throw error; } }); __publicField$1(this, "getAvailableExperiments", async () => { var _a; try { const response = await this.axios.get("/api/v2/experiments/available"); return response.data; } catch (error) { if (isAxiosError(error) && ((_a = error.response) == null ? void 0 : _a.status) === 404) { return { safe: [] }; } throw error; } }); __publicField$1(this, "getExternalAuthProvider", async (provider) => { const res = await this.axios.get(`/api/v2/external-auth/${provider}`); return res.data; }); __publicField$1(this, "getExternalAuthDevice", async (provider) => { const resp = await this.axios.get( `/api/v2/external-auth/${provider}/device` ); return resp.data; }); __publicField$1(this, "exchangeExternalAuthDevice", async (provider, req) => { const resp = await this.axios.post( `/api/v2/external-auth/${provider}/device`, req ); return resp.data; }); __publicField$1(this, "getUserExternalAuthProviders", async () => { const resp = await this.axios.get(`/api/v2/external-auth`); return resp.data; }); __publicField$1(this, "unlinkExternalAuthProvider", async (provider) => { const resp = await this.axios.delete(`/api/v2/external-auth/${provider}`); return resp.data; }); __publicField$1(this, "getOAuth2ProviderApps", async (filter) => { const params = (filter == null ? void 0 : filter.user_id) ? new URLSearchParams({ user_id: filter.user_id }).toString() : ""; const resp = await this.axios.get(`/api/v2/oauth2-provider/apps?${params}`); return resp.data; }); __publicField$1(this, "getOAuth2ProviderApp", async (id) => { const resp = await this.axios.get(`/api/v2/oauth2-provider/apps/${id}`); return resp.data; }); __publicField$1(this, "postOAuth2ProviderApp", async (data) => { const response = await this.axios.post( `/api/v2/oauth2-provider/apps`, data ); return response.data; }); __publicField$1(this, "putOAuth2ProviderApp", async (id, data) => { const response = await this.axios.put( `/api/v2/oauth2-provider/apps/${id}`, data ); return response.data; }); __publicField$1(this, "deleteOAuth2ProviderApp", async (id) => { await this.axios.delete(`/api/v2/oauth2-provider/apps/${id}`); }); __publicField$1(this, "getOAuth2ProviderAppSecrets", async (id) => { const resp = await this.axios.get( `/api/v2/oauth2-provider/apps/${id}/secrets` ); return resp.data; }); __publicField$1(this, "postOAuth2ProviderAppSecret", async (id) => { const resp = await this.axios.post( `/api/v2/oauth2-provider/apps/${id}/secrets` ); return resp.data; }); __publicField$1(this, "deleteOAuth2ProviderAppSecret", async (appId, secretId) => { await this.axios.delete( `/api/v2/oauth2-provider/apps/${appId}/secrets/${secretId}` ); }); __publicField$1(this, "revokeOAuth2ProviderApp", async (appId) => { await this.axios.delete(`/oauth2/tokens?client_id=${appId}`); }); __publicField$1(this, "getAuditLogs", async (options) => { const url = getURLWithSearchParams("/api/v2/audit", options); const response = await this.axios.get(url); return response.data; }); __publicField$1(this, "getTemplateDAUs", async (templateId) => { const response = await this.axios.get( `/api/v2/templates/${templateId}/daus` ); return response.data; }); __publicField$1(this, "getDeploymentDAUs", async (offset = Math.trunc((/* @__PURE__ */ new Date()).getTimezoneOffset() / 60)) => { const response = await this.axios.get( `/api/v2/insights/daus?tz_offset=${offset}` ); return response.data; }); __publicField$1(this, "getTemplateACLAvailable", async (templateId, options) => { const url = getURLWithSearchParams( `/api/v2/templates/${templateId}/acl/available`, options ).toString(); const response = await this.axios.get(url); return response.data; }); __publicField$1(this, "getTemplateACL", async (templateId) => { const response = await this.axios.get( `/api/v2/templates/${templateId}/acl` ); return response.data; }); __publicField$1(this, "updateTemplateACL", async (templateId, data) => { const response = await this.axios.patch( `/api/v2/templates/${templateId}/acl`, data ); return response.data; }); __publicField$1(this, "getApplicationsHost", async () => { const response = await this.axios.get(`/api/v2/applications/host`); return response.data; }); __publicField$1(this, "getGroups", async (organizationId) => { const response = await this.axios.get( `/api/v2/organizations/${organizationId}/groups` ); return response.data; }); __publicField$1(this, "createGroup", async (organizationId, data) => { const response = await this.axios.post( `/api/v2/organizations/${organizationId}/groups`, data ); return response.data; }); __publicField$1(this, "getGroup", async (groupId) => { const response = await this.axios.get(`/api/v2/groups/${groupId}`); return response.data; }); __publicField$1(this, "patchGroup", async (groupId, data) => { const response = await this.axios.patch(`/api/v2/groups/${groupId}`, data); return response.data; }); __publicField$1(this, "addMember", async (groupId, userId) => { return this.patchGroup(groupId, { name: "", add_users: [userId], remove_users: [] }); }); __publicField$1(this, "removeMember", async (groupId, userId) => { return this.patchGroup(groupId, { name: "", display_name: "", add_users: [], remove_users: [userId] }); }); __publicField$1(this, "deleteGroup", async (groupId) => { await this.axios.delete(`/api/v2/groups/${groupId}`); }); __publicField$1(this, "getWorkspaceQuota", async (username) => { const response = await this.axios.get( `/api/v2/workspace-quota/${encodeURIComponent(username)}` ); return response.data; }); __publicField$1(this, "getAgentListeningPorts", async (agentID) => { const response = await this.axios.get( `/api/v2/workspaceagents/${agentID}/listening-ports` ); return response.data; }); __publicField$1(this, "getWorkspaceAgentSharedPorts", async (workspaceID) => { const response = await this.axios.get( `/api/v2/workspaces/${workspaceID}/port-share` ); return response.data; }); __publicField$1(this, "upsertWorkspaceAgentSharedPort", async (workspaceID, req) => { const response = await this.axios.post( `/api/v2/workspaces/${workspaceID}/port-share`, req ); return response.data; }); __publicField$1(this, "deleteWorkspaceAgentSharedPort", async (workspaceID, req) => { const response = await this.axios.delete( `/api/v2/workspaces/${workspaceID}/port-share`, { data: req } ); return response.data; }); // getDeploymentSSHConfig is used by the VSCode-Extension. __publicField$1(this, "getDeploymentSSHConfig", async () => { const response = await this.axios.get(`/api/v2/deployment/ssh`); return response.data; }); __publicField$1(this, "getDeploymentConfig", async () => { const response = await this.axios.get(`/api/v2/deployment/config`); return response.data; }); __publicField$1(this, "getDeploymentStats", async () => { const response = await this.axios.get(`/api/v2/deployment/stats`); return response.data; }); __publicField$1(this, "getReplicas", async () => { const response = await this.axios.get(`/api/v2/replicas`); return response.data; }); __publicField$1(this, "getFile", async (fileId) => { const response = await this.axios.get( `/api/v2/files/${fileId}`, { responseType: "arraybuffer" } ); return response.data; }); __publicField$1(this, "getWorkspaceProxyRegions", async () => { const response = await this.axios.get(`/api/v2/regions`); return response.data; }); __publicField$1(this, "getWorkspaceProxies", async () => { const response = await this.axios.get(`/api/v2/workspaceproxies`); return response.data; }); __publicField$1(this, "createWorkspaceProxy", async (b) => { const response = await this.axios.post(`/api/v2/workspaceproxies`, b); return response.data; }); __publicField$1(this, "getAppearance", async () => { var _a; try { const response = await this.axios.get(`/api/v2/appearance`); return response.data || {}; } catch (ex) { if (isAxiosError(ex) && ((_a = ex.response) == null ? void 0 : _a.status) === 404) { return { application_name: "", logo_url: "", notification_banners: [], service_banner: { enabled: false } }; } throw ex; } }); __publicField$1(this, "updateAppearance", async (b) => { const response = await this.axios.put(`/api/v2/appearance`, b); return response.data; }); __publicField$1(this, "getTemplateExamples", async (organizationId) => { const response = await this.axios.get( `/api/v2/organizations/${organizationId}/templates/examples` ); return response.data; }); __publicField$1(this, "uploadFile", async (file) => { const response = await this.axios.post("/api/v2/files", file, { headers: { "Content-Type": "application/x-tar" } }); return response.data; }); __publicField$1(this, "getTemplateVersionLogs", async (versionId) => { const response = await this.axios.get( `/api/v2/templateversions/${versionId}/logs` ); return response.data; }); __publicField$1(this, "updateWorkspaceVersion", async (workspace) => { const template = await this.getTemplate(workspace.template_id); return this.startWorkspace(workspace.id, template.active_version_id); }); __publicField$1(this, "getWorkspaceBuildParameters", async (workspaceBuildId) => { const response = await this.axios.get( `/api/v2/workspacebuilds/${workspaceBuildId}/parameters` ); return response.data; }); __publicField$1(this, "getLicenses", async () => { const response = await this.axios.get(`/api/v2/licenses`); return response.data; }); __publicField$1(this, "createLicense", async (data) => { const response = await this.axios.post(`/api/v2/licenses`, data); return response.data; }); __publicField$1(this, "removeLicense", async (licenseId) => { await this.axios.delete(`/api/v2/licenses/${licenseId}`); }); /** Steps to change the workspace version * - Get the latest template to access the latest active version * - Get the current build parameters * - Get the template parameters * - Update the build parameters and check if there are missed parameters for * the new version * - If there are missing parameters raise an error * - Create a build with the version and updated build parameters */ __publicField$1(this, "changeWorkspaceVersion", async (workspace, templateVersionId, newBuildParameters = []) => { const [currentBuildParameters, templateParameters] = await Promise.all([ this.getWorkspaceBuildParameters(workspace.latest_build.id), this.getTemplateVersionRichParameters(templateVersionId) ]); const missingParameters = getMissingParameters( currentBuildParameters, newBuildParameters, templateParameters ); if (missingParameters.length > 0) { throw new MissingBuildParameters(missingParameters, templateVersionId); } return this.postWorkspaceBuild(workspace.id, { transition: "start", template_version_id: templateVersionId, rich_parameter_values: newBuildParameters }); }); /** Steps to update the workspace * - Get the latest template to access the latest active version * - Get the current build parameters * - Get the template parameters * - Update the build parameters and check if there are missed parameters for * the newest version * - If there are missing parameters raise an error * - Create a build with the latest version and updated build parameters */ __publicField$1(this, "updateWorkspace", async (workspace, newBuildParameters = []) => { const [template, oldBuildParameters] = await Promise.all([ this.getTemplate(workspace.template_id), this.getWorkspaceBuildParameters(workspace.latest_build.id) ]); const activeVersionId = template.active_version_id; const templateParameters = await this.getTemplateVersionRichParameters( activeVersionId ); const missingParameters = getMissingParameters( oldBuildParameters, newBuildParameters, templateParameters ); if (missingParameters.length > 0) { throw new MissingBuildParameters(missingParameters, activeVersionId); } return this.postWorkspaceBuild(workspace.id, { transition: "start", template_version_id: activeVersionId, rich_parameter_values: newBuildParameters }); }); __publicField$1(this, "getWorkspaceResolveAutostart", async (workspaceId) => { const response = await this.axios.get( `/api/v2/workspaces/${workspaceId}/resolve-autostart` ); return response.data; }); __publicField$1(this, "issueReconnectingPTYSignedToken", async (params) => { const response = await this.axios.post( "/api/v2/applications/reconnecting-pty-signed-token", params ); return response.data; }); __publicField$1(this, "getWorkspaceParameters", async (workspace) => { const latestBuild = workspace.latest_build; const [templateVersionRichParameters, buildParameters] = await Promise.all([ this.getTemplateVersionRichParameters(latestBuild.template_version_id), this.getWorkspaceBuildParameters(latestBuild.id) ]); return { templateVersionRichParameters, buildParameters }; }); __publicField$1(this, "getInsightsUserLatency", async (filters) => { const params = new URLSearchParams(filters); const response = await this.axios.get( `/api/v2/insights/user-latency?${params}` ); return response.data; }); __publicField$1(this, "getInsightsUserActivity", async (filters) => { const params = new URLSearchParams(filters); const response = await this.axios.get( `/api/v2/insights/user-activity?${params}` ); return response.data; }); __publicField$1(this, "getInsightsTemplate", async (params) => { const searchParams = new URLSearchParams(params); const response = await this.axios.get( `/api/v2/insights/templates?${searchParams}` ); return response.data; }); __publicField$1(this, "getHealth", async (force = false) => { const params = new URLSearchParams({ force: force.toString() }); const response = await this.axios.get( `/api/v2/debug/health?${params}` ); return response.data; }); __publicField$1(this, "getHealthSettings", async () => { const res = await this.axios.get( `/api/v2/debug/health/settings` ); return res.data; }); __publicField$1(this, "updateHealthSettings", async (data) => { const response = await this.axios.put( `/api/v2/debug/health/settings`, data ); return response.data; }); __publicField$1(this, "putFavoriteWorkspace", async (workspaceID) => { await this.axios.put(`/api/v2/workspaces/${workspaceID}/favorite`); }); __publicField$1(this, "deleteFavoriteWorkspace", async (workspaceID) => { await this.axios.delete(`/api/v2/workspaces/${workspaceID}/favorite`); }); __publicField$1(this, "getJFrogXRayScan", async (options) => { var _a; const searchParams = new URLSearchParams({ workspace_id: options.workspaceId, agent_id: options.agentId }); try { const res = await this.axios.get( `/api/v2/integrations/jfrog/xray-scan?${searchParams}` ); return res.data; } catch (error) { if (isAxiosError(error) && ((_a = error.response) == null ? void 0 : _a.status) === 404) { return null; } throw error; } }); } } const csrfToken = "KNKvagCBEHZK7ihe2t7fj6VeJ0UyTDco1yVUJE8N06oNqxLu5Zx1vRxZbgfC0mJJgeGkVjgs08mgPbcWPBkZ1A=="; const tokenMetadataElement = typeof document !== "undefined" ? document.head.querySelector('meta[property="csrf-token"]') : null; function getConfiguredAxiosInstance() { var _a; const instance = globalAxios.create(); instance.defaults.validateStatus = (status) => { return status >= 200 && status < 300 || status === 304; }; const metadataIsAvailable = tokenMetadataElement !== null && tokenMetadataElement.getAttribute("content") !== null; if (metadataIsAvailable) { if (process.env.NODE_ENV === "development") { instance.defaults.headers.common["X-CSRF-TOKEN"] = csrfToken; instance.defaults.headers.common["X-CSRF-TOKEN"] = csrfToken; tokenMetadataElement.setAttribute("content", csrfToken); } else { instance.defaults.headers.common["X-CSRF-TOKEN"] = (_a = tokenMetadataElement.getAttribute("content")) != null ? _a : ""; } } else { if (process.env.JEST_WORKER_ID === void 0) { console.error("CSRF token not found"); } } return instance; } class Api extends ApiMethods { constructor() { const scopedAxiosInstance = getConfiguredAxiosInstance(); super(scopedAxiosInstance); // As with ApiMethods, all public methods should be defined with arrow // function syntax to ensure they can be passed around the React UI without // losing/detaching their `this` context! __publicField$1(this, "getCsrfToken", () => { return csrfToken; }); __publicField$1(this, "setSessionToken", (token) => { this.axios.defaults.headers.common["Coder-Session-Token"] = token; }); __publicField$1(this, "setHost", (host) => { this.axios.defaults.baseURL = host; }); __publicField$1(this, "getAxiosInstance", () => { return this.axios; }); } } new Api(); function createCoderApi() { const api = new Api(); return api; } var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);