From 90cf4809ec1edaf1d22313514e3c72c136e5912f Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 30 Jan 2026 12:43:09 +0100 Subject: [PATCH] fix(site): use version name instead of ID in View source button URL (#21784) Fixes #19921 The "View source" button was using `versionId` (UUID) instead of version name in the URL, causing broken links. --- .../CreateWorkspacePage.tsx | 7 +++++ .../CreateWorkspacePageView.stories.tsx | 30 ++++++++++++++----- .../CreateWorkspacePageView.tsx | 6 ++-- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index 153920d080..38149416bb 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -3,6 +3,7 @@ import { type ApiErrorResponse, DetailedError } from "api/errors"; import { checkAuthorization } from "api/queries/authCheck"; import { templateByName, + templateVersion, templateVersionExternalAuth, templateVersionPresets, } from "api/queries/templates"; @@ -88,6 +89,11 @@ const CreateWorkspacePage: FC = () => { const realizedVersionId = customVersionId ?? templateQuery.data?.active_version_id; + const templateVersionQuery = useQuery({ + ...templateVersion(realizedVersionId ?? ""), + enabled: realizedVersionId !== undefined, + }); + const autofillParameters = getAutofillParameters(searchParams); const sendMessage = useEffectEvent( @@ -308,6 +314,7 @@ const CreateWorkspacePage: FC = () => { resetMutation={createWorkspaceMutation.reset} template={templateQuery.data} versionId={realizedVersionId} + versionName={templateVersionQuery.data?.name} externalAuth={externalAuth ?? []} externalAuthPollingState={externalAuthPollingState} startPollingExternalAuth={startPollingExternalAuth} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index 1a7dfd9439..92d0522828 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -2,6 +2,7 @@ import { chromatic } from "testHelpers/chromatic"; import { MockTemplate, MockUserOwner } from "testHelpers/entities"; import type { Meta, StoryObj } from "@storybook/react-vite"; import { DetailedError } from "api/errors"; +import { expect, screen, within } from "storybook/test"; import { CreateWorkspacePageView } from "./CreateWorkspacePageView"; const meta: Meta = { @@ -43,19 +44,32 @@ export const WebsocketError: Story = { export const WithViewSourceButton: Story = { args: { canUpdateTemplate: true, - versionId: "template-version-123", + versionName: "foobar-template-version", template: { ...MockTemplate, organization_name: "default", name: "docker-template", }, }, - parameters: { - docs: { - description: { - story: - "This story shows the View Source button that appears for template administrators in the experimental workspace creation page. The button allows quick navigation to the template editor.", - }, - }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const viewSourceLink = canvas.getByRole("link", { name: /view source/i }); + expect(viewSourceLink).toBeInTheDocument(); + expect(viewSourceLink).toHaveAttribute( + "href", + "/templates/default/docker-template/versions/foobar-template-version/edit", + ); + }, +}; + +export const ViewSourceButtonHiddenWithoutPermission: Story = { + args: { + canUpdateTemplate: false, + versionName: "foobar-template-version", + }, + play: async () => { + expect( + screen.queryByRole("link", { name: /view source/i }), + ).not.toBeInTheDocument(); }, }; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index ec5eadcefd..cda5f14959 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -64,6 +64,7 @@ interface CreateWorkspacePageViewProps { presets: TypesGen.Preset[]; template: TypesGen.Template; versionId?: string; + versionName?: string; onCancel: () => void; onSubmit: ( req: TypesGen.CreateWorkspaceRequest, @@ -94,6 +95,7 @@ export const CreateWorkspacePageView: FC = ({ presets = [], template, versionId, + versionName, onSubmit, onCancel, resetMutation, @@ -380,10 +382,10 @@ export const CreateWorkspacePageView: FC = ({ )} - {canUpdateTemplate && ( + {canUpdateTemplate && versionName && (