mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add minimal frontend for creating workspaces from specific template versions (#9475)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"templateLabel": "Template",
|
||||
"versionLabel": "Version ID",
|
||||
"nameLabel": "Workspace Name",
|
||||
"ownerLabel": "Owner",
|
||||
"createWorkspace": "Create Workspace",
|
||||
|
||||
@@ -42,6 +42,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
defaultBuildParameters,
|
||||
defaultName:
|
||||
mode === "auto" ? generateUniqueName() : searchParams.get("name") ?? "",
|
||||
versionId: searchParams.get("version") ?? undefined,
|
||||
},
|
||||
actions: {
|
||||
onCreateWorkspace: (_, event) => {
|
||||
@@ -49,8 +50,15 @@ const CreateWorkspacePage: FC = () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
const { template, error, parameters, permissions, gitAuth, defaultName } =
|
||||
createWorkspaceState.context;
|
||||
const {
|
||||
template,
|
||||
error,
|
||||
parameters,
|
||||
permissions,
|
||||
gitAuth,
|
||||
defaultName,
|
||||
versionId,
|
||||
} = createWorkspaceState.context;
|
||||
const title = createWorkspaceState.matches("autoCreating")
|
||||
? "Creating workspace..."
|
||||
: "Create Workspace";
|
||||
@@ -74,6 +82,7 @@ const CreateWorkspacePage: FC = () => {
|
||||
defaultBuildParameters={defaultBuildParameters}
|
||||
error={error}
|
||||
template={template as Template}
|
||||
versionId={versionId}
|
||||
gitAuth={gitAuth as TemplateVersionGitAuth[]}
|
||||
permissions={permissions as CreateWSPermissions}
|
||||
parameters={parameters as TemplateVersionParameter[]}
|
||||
|
||||
@@ -30,12 +30,14 @@ import {
|
||||
import { CreateWSPermissions } from "xServices/createWorkspace/createWorkspaceXService";
|
||||
import { GitAuth } from "./GitAuth";
|
||||
import { ErrorAlert } from "components/Alert/ErrorAlert";
|
||||
import { Stack } from "components/Stack/Stack";
|
||||
|
||||
export interface CreateWorkspacePageViewProps {
|
||||
error: unknown;
|
||||
defaultName: string;
|
||||
defaultOwner: TypesGen.User;
|
||||
template: TypesGen.Template;
|
||||
versionId?: string;
|
||||
gitAuth: TypesGen.TemplateVersionGitAuth[];
|
||||
parameters: TypesGen.TemplateVersionParameter[];
|
||||
defaultBuildParameters: TypesGen.WorkspaceBuildParameter[];
|
||||
@@ -53,6 +55,7 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
defaultName,
|
||||
defaultOwner,
|
||||
template,
|
||||
versionId,
|
||||
gitAuth,
|
||||
parameters,
|
||||
defaultBuildParameters,
|
||||
@@ -115,6 +118,19 @@ export const CreateWorkspacePageView: FC<CreateWorkspacePageViewProps> = ({
|
||||
>
|
||||
<FormFields>
|
||||
<SelectedTemplate template={template} />
|
||||
{versionId && (
|
||||
<Stack spacing={1} className={styles.hasDescription}>
|
||||
<TextField
|
||||
disabled
|
||||
fullWidth
|
||||
value={versionId}
|
||||
label={t("versionLabel")}
|
||||
/>
|
||||
<span className={styles.description}>
|
||||
This parameter has been preset, and cannot be modified.
|
||||
</span>
|
||||
</Stack>
|
||||
)}
|
||||
<TextField
|
||||
{...getFieldHelpers("name")}
|
||||
disabled={form.isSubmitting}
|
||||
@@ -252,6 +268,13 @@ const useGitAuthVerification = (gitAuth: TypesGen.TemplateVersionGitAuth[]) => {
|
||||
};
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
hasDescription: {
|
||||
paddingBottom: theme.spacing(2),
|
||||
},
|
||||
description: {
|
||||
fontSize: 13,
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
warningText: {
|
||||
color: theme.palette.warning.light,
|
||||
},
|
||||
|
||||
+3
-14
@@ -65,7 +65,6 @@ export interface TemplateVersionEditorProps {
|
||||
onCancelPublish: () => void;
|
||||
publishingError: unknown;
|
||||
publishedVersion?: TemplateVersion;
|
||||
publishedVersionIsDefault?: boolean;
|
||||
onCreateWorkspace: () => void;
|
||||
isAskingPublishParameters: boolean;
|
||||
isPromptingMissingVariables: boolean;
|
||||
@@ -104,7 +103,6 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
isPublishing,
|
||||
publishingError,
|
||||
publishedVersion,
|
||||
publishedVersionIsDefault,
|
||||
onCreateWorkspace,
|
||||
buildLogs,
|
||||
resources,
|
||||
@@ -213,18 +211,9 @@ export const TemplateVersionEditor: FC<TemplateVersionEditorProps> = ({
|
||||
severity="success"
|
||||
dismissible
|
||||
actions={
|
||||
// TODO: Only show this button when the version we just published is the
|
||||
// new primary version. We should remove this condition soon, when we can
|
||||
// create workspaces using any version, not just the primary.
|
||||
publishedVersionIsDefault && (
|
||||
<Button
|
||||
variant="text"
|
||||
size="small"
|
||||
onClick={onCreateWorkspace}
|
||||
>
|
||||
Create a workspace
|
||||
</Button>
|
||||
)
|
||||
<Button variant="text" size="small" onClick={onCreateWorkspace}>
|
||||
Create a workspace
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
Successfully published {publishedVersion.name}!
|
||||
|
||||
@@ -77,11 +77,16 @@ export const TemplateVersionEditorPage: FC = () => {
|
||||
isPublishing={editorState.matches("publishingVersion")}
|
||||
publishingError={editorState.context.publishingError}
|
||||
publishedVersion={editorState.context.lastSuccessfulPublishedVersion}
|
||||
publishedVersionIsDefault={
|
||||
editorState.context.lastSuccessfulPublishIsDefault
|
||||
}
|
||||
onCreateWorkspace={() => {
|
||||
navigate(`/templates/${templateName}/workspace`);
|
||||
const params = new URLSearchParams();
|
||||
const publishedVersion =
|
||||
editorState.context.lastSuccessfulPublishedVersion;
|
||||
if (publishedVersion) {
|
||||
params.set("version", publishedVersion.id);
|
||||
}
|
||||
navigate(
|
||||
`/templates/${templateName}/workspace?${params.toString()}`,
|
||||
);
|
||||
}}
|
||||
disablePreview={editorState.hasTag("loading")}
|
||||
disableUpdate={
|
||||
|
||||
@@ -25,6 +25,9 @@ type CreateWorkspaceContext = {
|
||||
templateName: string;
|
||||
mode: CreateWorkspaceMode;
|
||||
defaultName: string;
|
||||
// Not exposed in the form yet, but can be set as a search param to
|
||||
// create a workspace with a specific version of a template
|
||||
versionId?: string;
|
||||
error?: unknown;
|
||||
// Form
|
||||
template?: Template;
|
||||
@@ -149,21 +152,39 @@ export const createWorkspaceMachine =
|
||||
},
|
||||
{
|
||||
services: {
|
||||
createWorkspace: ({ organizationId }, { request, owner }) => {
|
||||
createWorkspace: (
|
||||
{ organizationId, versionId },
|
||||
{ request, owner },
|
||||
) => {
|
||||
if (versionId) {
|
||||
request = {
|
||||
...request,
|
||||
template_id: undefined,
|
||||
template_version_id: versionId,
|
||||
};
|
||||
}
|
||||
|
||||
return createWorkspace(organizationId, owner.id, request);
|
||||
},
|
||||
autoCreateWorkspace: async ({
|
||||
templateName,
|
||||
versionId,
|
||||
organizationId,
|
||||
defaultBuildParameters,
|
||||
defaultName,
|
||||
}) => {
|
||||
const template = await getTemplateByName(
|
||||
organizationId,
|
||||
templateName,
|
||||
);
|
||||
let templateVersionParameters;
|
||||
if (versionId) {
|
||||
templateVersionParameters = { template_version_id: versionId };
|
||||
} else {
|
||||
const template = await getTemplateByName(
|
||||
organizationId,
|
||||
templateName,
|
||||
);
|
||||
templateVersionParameters = { template_id: template.id };
|
||||
}
|
||||
return createWorkspace(organizationId, "me", {
|
||||
template_id: template.id,
|
||||
...templateVersionParameters,
|
||||
name: defaultName,
|
||||
rich_parameter_values: defaultBuildParameters,
|
||||
});
|
||||
|
||||
@@ -25,7 +25,6 @@ export interface TemplateVersionEditorMachineContext {
|
||||
tarReader?: TarReader;
|
||||
publishingError?: unknown;
|
||||
lastSuccessfulPublishedVersion?: TemplateVersion;
|
||||
lastSuccessfulPublishIsDefault?: boolean;
|
||||
missingVariables?: TemplateVersionVariable[];
|
||||
missingVariableValues?: VariableValue[];
|
||||
}
|
||||
@@ -70,7 +69,7 @@ export const templateVersionEditorMachine = createMachine(
|
||||
data: WorkspaceResource[];
|
||||
};
|
||||
publishingVersion: {
|
||||
data: { isActiveVersion: boolean };
|
||||
data: void;
|
||||
};
|
||||
loadMissingVariables: {
|
||||
data: TemplateVersionVariable[];
|
||||
@@ -261,8 +260,6 @@ export const templateVersionEditorMachine = createMachine(
|
||||
}),
|
||||
assignLastSuccessfulPublishedVersion: assign({
|
||||
lastSuccessfulPublishedVersion: (ctx) => ctx.version,
|
||||
lastSuccessfulPublishIsDefault: (_, event) =>
|
||||
event.data.isActiveVersion,
|
||||
version: () => undefined,
|
||||
}),
|
||||
addBuildLog: assign({
|
||||
@@ -433,8 +430,6 @@ export const templateVersionEditorMachine = createMachine(
|
||||
})
|
||||
: Promise.resolve(),
|
||||
]);
|
||||
|
||||
return { isActiveVersion };
|
||||
},
|
||||
loadMissingVariables: ({ version }) => {
|
||||
if (!version) {
|
||||
|
||||
Reference in New Issue
Block a user