From 6b6066e0de975f41a6ea8b9c39dfdcd3292f3d32 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Wed, 7 May 2025 12:23:02 +0000 Subject: [PATCH] chore: fix workspace apps response --- codersdk/workspaceapps.go | 6 ++--- site/src/api/typesGenerated.ts | 6 ++--- site/src/modules/resources/AgentRow.test.tsx | 4 ++-- .../resources/AgentRowPreview.test.tsx | 6 +++-- .../src/modules/resources/AgentRowPreview.tsx | 2 +- .../src/modules/resources/AppLink/AppLink.tsx | 23 +++++-------------- .../WorkspaceAppStatus/WorkspaceAppStatus.tsx | 3 +-- site/src/pages/WorkspacePage/AppStatuses.tsx | 3 +-- site/src/utils/apps.ts | 2 +- 9 files changed, 22 insertions(+), 33 deletions(-) diff --git a/codersdk/workspaceapps.go b/codersdk/workspaceapps.go index a55db1911101e..3b3200616a0f3 100644 --- a/codersdk/workspaceapps.go +++ b/codersdk/workspaceapps.go @@ -60,14 +60,14 @@ type WorkspaceApp struct { ID uuid.UUID `json:"id" format:"uuid"` // URL is the address being proxied to inside the workspace. // If external is specified, this will be opened on the client. - URL string `json:"url"` + URL string `json:"url,omitempty"` // External specifies whether the URL should be opened externally on // the client or not. External bool `json:"external"` // Slug is a unique identifier within the agent. Slug string `json:"slug"` // DisplayName is a friendly name for the app. - DisplayName string `json:"display_name"` + DisplayName string `json:"display_name,omitempty"` Command string `json:"command,omitempty"` // Icon is a relative path or external URL that specifies // an icon to be displayed in the dashboard. @@ -81,7 +81,7 @@ type WorkspaceApp struct { SubdomainName string `json:"subdomain_name,omitempty"` SharingLevel WorkspaceAppSharingLevel `json:"sharing_level" enums:"owner,authenticated,public"` // Healthcheck specifies the configuration for checking app health. - Healthcheck Healthcheck `json:"healthcheck"` + Healthcheck Healthcheck `json:"healthcheck,omitempty"` Health WorkspaceAppHealth `json:"health"` Hidden bool `json:"hidden"` OpenIn WorkspaceAppOpenIn `json:"open_in"` diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b1fcb296de4e8..d195432f019c4 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -3474,16 +3474,16 @@ export const WorkspaceAgentStatuses: WorkspaceAgentStatus[] = [ // From codersdk/workspaceapps.go export interface WorkspaceApp { readonly id: string; - readonly url: string; + readonly url?: string; readonly external: boolean; readonly slug: string; - readonly display_name: string; + readonly display_name?: string; readonly command?: string; readonly icon?: string; readonly subdomain: boolean; readonly subdomain_name?: string; readonly sharing_level: WorkspaceAppSharingLevel; - readonly healthcheck: Healthcheck; + readonly healthcheck?: Healthcheck; readonly health: WorkspaceAppHealth; readonly hidden: boolean; readonly open_in: WorkspaceAppOpenIn; diff --git a/site/src/modules/resources/AgentRow.test.tsx b/site/src/modules/resources/AgentRow.test.tsx index a0a2d37d2bab0..55be57bbc2c2b 100644 --- a/site/src/modules/resources/AgentRow.test.tsx +++ b/site/src/modules/resources/AgentRow.test.tsx @@ -150,9 +150,9 @@ describe.each<{ for (const app of props.agent.apps) { if (app.hidden) { - expect(screen.queryByText(app.display_name)).toBeNull(); + expect(screen.queryByText(app.display_name as string)).toBeNull(); } else { - expect(screen.getByText(app.display_name)).toBeVisible(); + expect(screen.getByText(app.display_name as string)).toBeVisible(); } } }); diff --git a/site/src/modules/resources/AgentRowPreview.test.tsx b/site/src/modules/resources/AgentRowPreview.test.tsx index 222e2b22ac9f8..c1b876b72ef3b 100644 --- a/site/src/modules/resources/AgentRowPreview.test.tsx +++ b/site/src/modules/resources/AgentRowPreview.test.tsx @@ -91,8 +91,10 @@ describe("AgentRowPreviewApps", () => { " displays appropriately", ({ workspaceAgent }) => { renderComponent(); - for (const module of workspaceAgent.apps) { - expect(screen.getByText(module.display_name)).toBeInTheDocument(); + for (const app of workspaceAgent.apps) { + expect( + screen.getByText(app.display_name as string), + ).toBeInTheDocument(); } for (const app of workspaceAgent.display_apps) { diff --git a/site/src/modules/resources/AgentRowPreview.tsx b/site/src/modules/resources/AgentRowPreview.tsx index cace23e31b34c..eaccb5adca4fb 100644 --- a/site/src/modules/resources/AgentRowPreview.tsx +++ b/site/src/modules/resources/AgentRowPreview.tsx @@ -31,7 +31,7 @@ export const AgentRowPreview: FC = ({ >
-
+
= ({ app, workspace, agent }) => { const appsHost = proxy.preferredWildcardHostname; const [fetchingSessionToken, setFetchingSessionToken] = useState(false); const [iconError, setIconError] = useState(false); - const theme = useTheme(); const username = workspace.owner_name; - - let appSlug = app.slug; - let appDisplayName = app.display_name; - if (!appSlug) { - appSlug = appDisplayName; - } - if (!appDisplayName) { - appDisplayName = appSlug; - } + const displayName = app.display_name || app.slug; const href = createAppLinkHref( window.location.protocol, preferredPathBase, appsHost, - appSlug, + app.slug, username, workspace, agent, @@ -118,7 +109,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { // This is an external URI like "vscode://", so // it needs to be opened with the browser protocol handler. const shouldOpenAppExternally = - app.external && !app.url.startsWith("http"); + app.external && app.url?.startsWith("http"); if (shouldOpenAppExternally) { // This is a magic undocumented string that is replaced @@ -140,9 +131,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { // an error message will be displayed. const openAppExternallyFailedTimeout = 500; const openAppExternallyFailed = setTimeout(() => { - displayError( - `${app.display_name !== "" ? app.display_name : app.slug} must be installed first.`, - ); + displayError(`${displayName} must be installed first.`); }, openAppExternallyFailedTimeout); window.addEventListener("blur", () => { clearTimeout(openAppExternallyFailed); @@ -156,7 +145,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { case "slim-window": { window.open( href, - Language.appTitle(appDisplayName, generateRandomString(12)), + Language.appTitle(displayName, generateRandomString(12)), "width=900,height=600", ); return; @@ -169,7 +158,7 @@ export const AppLink: FC = ({ app, workspace, agent }) => { }} > {icon} - {appDisplayName} + {displayName} {canShare && } diff --git a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx index a8c06b711f514..0b9512d939ae7 100644 --- a/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx +++ b/site/src/modules/workspaces/WorkspaceAppStatus/WorkspaceAppStatus.tsx @@ -124,12 +124,11 @@ export const WorkspaceAppStatus = ({ let appHref: string | undefined; if (app && agent) { - const appSlug = app.slug || app.display_name; appHref = createAppLinkHref( window.location.protocol, preferredPathBase, appsHost, - appSlug, + app.slug, workspace.owner_name, workspace, agent, diff --git a/site/src/pages/WorkspacePage/AppStatuses.tsx b/site/src/pages/WorkspacePage/AppStatuses.tsx index 95afb422de30b..6399e7ef40e65 100644 --- a/site/src/pages/WorkspacePage/AppStatuses.tsx +++ b/site/src/pages/WorkspacePage/AppStatuses.tsx @@ -198,12 +198,11 @@ export const AppStatuses: FC = ({ const agent = agents.find((agent) => agent.id === status.agent_id); if (currentApp && agent) { - const appSlug = currentApp.slug || currentApp.display_name; appHref = createAppLinkHref( window.location.protocol, preferredPathBase, appsHost, - appSlug, + currentApp.slug, workspace.owner_name, workspace, agent, diff --git a/site/src/utils/apps.ts b/site/src/utils/apps.ts index 9b1a50a76ce4c..90aa6566d08e3 100644 --- a/site/src/utils/apps.ts +++ b/site/src/utils/apps.ts @@ -11,7 +11,7 @@ export const createAppLinkHref = ( app: TypesGen.WorkspaceApp, ): string => { if (app.external) { - return app.url; + return app.url as string; } // The backend redirects if the trailing slash isn't included, so we add it