Skip to content
Next Next commit
Show display_name field in the template settings
  • Loading branch information
mtojek committed Nov 14, 2022
commit 31177429ee41c445ea028b2b5be60d9a3fc5002d
11 changes: 5 additions & 6 deletions coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,19 +478,18 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
return nil
}

// Update template metadata -- empty fields are not overwritten.
// Update template metadata -- empty fields are not overwritten,
// except for display_name, icon, and default_ttl.
// The exception is required to clear content of these fields with UI.
name := req.Name
displayName := req.DisplayName
desc := req.Description
icon := req.Icon
maxTTL := time.Duration(req.DefaultTTLMillis) * time.Millisecond
defaultTTLMillis := time.Duration(req.DefaultTTLMillis) * time.Millisecond

if name == "" {
name = template.Name
}
if displayName == "" {
displayName = template.DisplayName
}
if desc == "" {
desc = template.Description
}
Expand All @@ -502,7 +501,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
DisplayName: displayName,
Description: desc,
Icon: icon,
DefaultTtl: int64(maxTTL),
DefaultTtl: int64(defaultTTLMillis),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought this had to be a bug but I was surprised to notice we're storing nanoseconds in the database... 😅

})
if err != nil {
return err
Expand Down
14 changes: 13 additions & 1 deletion site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import { Stack } from "components/Stack/Stack"
import { FormikContextType, FormikTouched, useFormik } from "formik"
import { FC, useRef, useState } from "react"
import { colors } from "theme/colors"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "util/formUtils"
import { getFormHelpers, nameValidator, templateDisplayNameValidator, onChangeTrimmed } from "util/formUtils"
import * as Yup from "yup"

export const Language = {
nameLabel: "Name",
displayNameLabel: "Display name",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're actually moving away from these Language blocks and instead using react-i18next for translations because it's a cleaner solution. We try to knock them out whenever we come across them in legacy code. Would you mind adding a new translation for your label in templatePage.json? There's an example PR here that should walk you through how to do it. Let me know if you need any help!

Copy link
Member Author

@mtojek mtojek Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion, @Kira-Pilot! 6396671 . I guess that I can polish the entire page, but would rather do this in a follow-up PR :)

descriptionLabel: "Description",
defaultTtlLabel: "Auto-stop default",
iconLabel: "Icon",
Expand All @@ -36,6 +37,7 @@ const MS_HOUR_CONVERSION = 3600000

export const validationSchema = Yup.object({
name: nameValidator(Language.nameLabel),
display_name: templateDisplayNameValidator(Language.displayNameLabel),
description: Yup.string().max(
MAX_DESCRIPTION_CHAR_LIMIT,
Language.descriptionMaxError,
Expand Down Expand Up @@ -105,6 +107,16 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
variant="outlined"
/>

<TextField
{...getFieldHelpers("display_name")}
disabled={isSubmitting}
onChange={onChangeTrimmed(form)}
autoFocus
fullWidth
label={Language.displayNameLabel}
variant="outlined"
/>

<TextField
{...getFieldHelpers("description")}
multiline
Expand Down
2 changes: 1 addition & 1 deletion site/src/pages/TemplatesPage/TemplatesPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const TemplatesPageView: FC<
>
<TableCellLink to={templatePageLink}>
<AvatarData
title={template.name}
title={template.display_name.length > 0 ? template.display_name : template.name}
subtitle={template.description}
highlightTitle
avatar={
Expand Down
20 changes: 14 additions & 6 deletions site/src/util/formUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ export const Language = {
nameInvalidChars: (name: string): string => {
return `${name} must start with a-Z or 0-9 and can contain a-Z, 0-9 or -`
},
nameTooLong: (name: string): string => {
return `${name} cannot be longer than 32 characters`
nameTooLong: (name: string, len: number): string => {
return `${name} cannot be longer than ${len} characters`
},
templateDisplayNameInvalidChars: (name: string): string => {
return `${name} must start with a-Z or 0-9 and can contain a-Z, 0-9 or -`
},
}

Expand Down Expand Up @@ -74,15 +77,20 @@ export const onChangeTrimmed =
form.handleChange(event)
}

// REMARK: Keep in sync with coderd/httpapi/httpapi.go#L40
// REMARK: Keep these consts in sync with coderd/httpapi/httpapi.go
const maxLenName = 32

// REMARK: Keep in sync with coderd/httpapi/httpapi.go#L18
const templateDisplayNameMaxLength = 64
const usernameRE = /^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*$/
const templateDisplayNameRE = /^[^\s](.*[^\s])?$/

// REMARK: see #1756 for name/username semantics
export const nameValidator = (name: string): Yup.StringSchema =>
Yup.string()
.required(Language.nameRequired(name))
.matches(usernameRE, Language.nameInvalidChars(name))
.max(maxLenName, Language.nameTooLong(name))
.max(maxLenName, Language.nameTooLong(name, maxLenName))

export const templateDisplayNameValidator = (displayName: string): Yup.StringSchema =>
Yup.string()
.matches(templateDisplayNameRE, Language.templateDisplayNameInvalidChars(displayName))
.max(templateDisplayNameMaxLength, Language.nameTooLong(displayName, templateDisplayNameMaxLength))