diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx index 243bd3cb9be2d..6d057a73d1a50 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePage.tsx @@ -65,7 +65,10 @@ const CreateWorkspacePage: FC = () => { }); const permissionsQuery = useQuery({ ...checkAuthorization({ - checks: createWorkspaceChecks(templateQuery.data?.organization_id ?? ""), + checks: createWorkspaceChecks( + templateQuery.data?.organization_id ?? "", + templateQuery.data?.id, + ), }), enabled: !!templateQuery.data, }); @@ -208,6 +211,7 @@ const CreateWorkspacePage: FC = () => { startPollingExternalAuth={startPollingExternalAuth} hasAllRequiredExternalAuth={hasAllRequiredExternalAuth} permissions={permissionsQuery.data as CreateWorkspacePermissions} + canUpdateTemplate={permissionsQuery.data?.canUpdateTemplate} parameters={realizedParameters as TemplateVersionParameter[]} presets={templateVersionPresetsQuery.data ?? []} creatingWorkspace={createWorkspaceMutation.isPending} diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx index 2e39c5625a6cb..b69ef084a77f7 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageExperimental.tsx @@ -79,7 +79,10 @@ const CreateWorkspacePageExperimental: FC = () => { }); const permissionsQuery = useQuery({ ...checkAuthorization({ - checks: createWorkspaceChecks(templateQuery.data?.organization_id ?? ""), + checks: createWorkspaceChecks( + templateQuery.data?.organization_id ?? "", + templateQuery.data?.id, + ), }), enabled: !!templateQuery.data, }); @@ -292,6 +295,7 @@ const CreateWorkspacePageExperimental: FC = () => { owner={owner} setOwner={setOwner} autofillParameters={autofillParameters} + canUpdateTemplate={permissionsQuery.data?.canUpdateTemplate} error={ wsError || createWorkspaceMutation.error || diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index f085c74c57073..d061b604f6b42 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -28,6 +28,7 @@ const meta: Meta = { mode: "form", permissions: { createWorkspaceForAny: true, + canUpdateTemplate: false, }, onCancel: action("onCancel"), }, @@ -382,3 +383,23 @@ export const ExternalAuthAllConnected: Story = { ], }, }; + +export const WithViewSourceButton: Story = { + args: { + canUpdateTemplate: true, + versionId: "template-version-123", + template: { + ...MockTemplate, + organization_name: "default", + name: "docker-template", + }, + }, + parameters: { + docs: { + description: { + story: + "This story shows the View Source button that appears for template administrators. The button allows quick navigation to the template editor from the workspace creation page.", + }, + }, + }, +}; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx index 75c382f807b1b..ceac49988c0a5 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.tsx @@ -27,8 +27,10 @@ import { Switch } from "components/Switch/Switch"; import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete"; import { type FormikContextType, useFormik } from "formik"; import type { ExternalAuthPollingState } from "hooks/useExternalAuth"; +import { ExternalLinkIcon } from "lucide-react"; import { generateWorkspaceName } from "modules/workspaces/generateWorkspaceName"; import { type FC, useCallback, useEffect, useMemo, useState } from "react"; +import { Link } from "react-router-dom"; import { getFormHelpers, nameValidator, @@ -67,6 +69,7 @@ interface CreateWorkspacePageViewProps { presets: TypesGen.Preset[]; permissions: CreateWorkspacePermissions; creatingWorkspace: boolean; + canUpdateTemplate?: boolean; onCancel: () => void; onSubmit: ( req: TypesGen.CreateWorkspaceRequest, @@ -92,6 +95,7 @@ export const CreateWorkspacePageView: FC = ({ presets = [], permissions, creatingWorkspace, + canUpdateTemplate, onSubmit, onCancel, }) => { @@ -218,9 +222,21 @@ export const CreateWorkspacePageView: FC = ({ - Cancel - + + {canUpdateTemplate && ( + + )} + + } > diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx index e00b04fd6bf50..0fcf5d7fbb854 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.stories.tsx @@ -20,6 +20,7 @@ const meta: Meta = { parameters: [], permissions: { createWorkspaceForAny: true, + canUpdateTemplate: false, }, presets: [], sendMessage: () => {}, @@ -38,3 +39,23 @@ export const WebsocketError: Story = { ), }, }; + +export const WithViewSourceButton: Story = { + args: { + canUpdateTemplate: true, + versionId: "template-version-123", + 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.", + }, + }, + }, +}; diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx index 8cb6c4acb6e49..49c4f8a4d5465 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageViewExperimental.tsx @@ -27,7 +27,7 @@ import { import { UserAutocomplete } from "components/UserAutocomplete/UserAutocomplete"; import { type FormikContextType, useFormik } from "formik"; import type { ExternalAuthPollingState } from "hooks/useExternalAuth"; -import { ArrowLeft, CircleHelp } from "lucide-react"; +import { ArrowLeft, CircleHelp, ExternalLinkIcon } from "lucide-react"; import { useSyncFormParameters } from "modules/hooks/useSyncFormParameters"; import { Diagnostics, @@ -44,6 +44,7 @@ import { useRef, useState, } from "react"; +import { Link as RouterLink } from "react-router-dom"; import { docs } from "utils/docs"; import { nameValidator } from "utils/formUtils"; import type { AutofillBuildParameter } from "utils/richParameters"; @@ -54,6 +55,7 @@ import type { CreateWorkspacePermissions } from "./permissions"; interface CreateWorkspacePageViewExperimentalProps { autofillParameters: AutofillBuildParameter[]; + canUpdateTemplate?: boolean; creatingWorkspace: boolean; defaultName?: string | null; defaultOwner: TypesGen.User; @@ -85,6 +87,7 @@ export const CreateWorkspacePageViewExperimental: FC< CreateWorkspacePageViewExperimentalProps > = ({ autofillParameters, + canUpdateTemplate, creatingWorkspace, defaultName, defaultOwner, @@ -379,6 +382,16 @@ export const CreateWorkspacePageViewExperimental: FC< )} + {canUpdateTemplate && ( + + )}

New workspace

diff --git a/site/src/pages/CreateWorkspacePage/permissions.ts b/site/src/pages/CreateWorkspacePage/permissions.ts index 1d933432a6e7c..a5ca3a469f623 100644 --- a/site/src/pages/CreateWorkspacePage/permissions.ts +++ b/site/src/pages/CreateWorkspacePage/permissions.ts @@ -1,13 +1,25 @@ -export const createWorkspaceChecks = (organizationId: string) => +export const createWorkspaceChecks = ( + organizationId: string, + templateId?: string, +) => ({ createWorkspaceForAny: { object: { - resource_type: "workspace", + resource_type: "workspace" as const, organization_id: organizationId, owner_id: "*", }, - action: "create", + action: "create" as const, }, + ...(templateId && { + canUpdateTemplate: { + object: { + resource_type: "template" as const, + resource_id: templateId, + }, + action: "update" as const, + }, + }), }) as const; export type CreateWorkspacePermissions = Record< pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy