mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore: add form_type parameter argument to db (#17920)
`form_type` is a new parameter field in the terraform provider. Bring that field into coder/coder. Validation for `multi-select` has also been added.
This commit is contained in:
Generated
+17
@@ -16095,6 +16095,23 @@ const docTemplate = `{
|
||||
"ephemeral": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"form_type": {
|
||||
"description": "FormType has an enum value of empty string, ` + "`" + `\"\"` + "`" + `.\nKeep the leading comma in the enums struct tag.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"",
|
||||
"radio",
|
||||
"dropdown",
|
||||
"input",
|
||||
"textarea",
|
||||
"slider",
|
||||
"checkbox",
|
||||
"switch",
|
||||
"tag-select",
|
||||
"multi-select",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
Generated
+17
@@ -14662,6 +14662,23 @@
|
||||
"ephemeral": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"form_type": {
|
||||
"description": "FormType has an enum value of empty string, `\"\"`.\nKeep the leading comma in the enums struct tag.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"",
|
||||
"radio",
|
||||
"dropdown",
|
||||
"input",
|
||||
"textarea",
|
||||
"slider",
|
||||
"checkbox",
|
||||
"switch",
|
||||
"tag-select",
|
||||
"multi-select",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -92,13 +92,13 @@ func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []coder
|
||||
}
|
||||
|
||||
func TemplateVersionParameters(params []database.TemplateVersionParameter) ([]codersdk.TemplateVersionParameter, error) {
|
||||
out := make([]codersdk.TemplateVersionParameter, len(params))
|
||||
var err error
|
||||
for i, p := range params {
|
||||
out[i], err = TemplateVersionParameter(p)
|
||||
out := make([]codersdk.TemplateVersionParameter, 0, len(params))
|
||||
for _, p := range params {
|
||||
np, err := TemplateVersionParameter(p)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("convert template version parameter %q: %w", p.Name, err)
|
||||
}
|
||||
out = append(out, np)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
@@ -131,6 +131,7 @@ func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk
|
||||
Description: param.Description,
|
||||
DescriptionPlaintext: descriptionPlaintext,
|
||||
Type: param.Type,
|
||||
FormType: string(param.FormType),
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.DefaultValue,
|
||||
Icon: param.Icon,
|
||||
@@ -293,7 +294,8 @@ func templateVersionParameterOptions(rawOptions json.RawMessage) ([]codersdk.Tem
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var options []codersdk.TemplateVersionParameterOption
|
||||
|
||||
options := make([]codersdk.TemplateVersionParameterOption, 0)
|
||||
for _, option := range protoOptions {
|
||||
options = append(options, codersdk.TemplateVersionParameterOption{
|
||||
Name: option.Name,
|
||||
|
||||
@@ -992,6 +992,7 @@ func TemplateVersionParameter(t testing.TB, db database.Store, orig database.Tem
|
||||
Name: takeFirst(orig.Name, testutil.GetRandomName(t)),
|
||||
Description: takeFirst(orig.Description, testutil.GetRandomName(t)),
|
||||
Type: takeFirst(orig.Type, "string"),
|
||||
FormType: orig.FormType, // empty string is ok!
|
||||
Mutable: takeFirst(orig.Mutable, false),
|
||||
DefaultValue: takeFirst(orig.DefaultValue, testutil.GetRandomName(t)),
|
||||
Icon: takeFirst(orig.Icon, testutil.GetRandomName(t)),
|
||||
|
||||
@@ -9393,6 +9393,7 @@ func (q *FakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg data
|
||||
DisplayName: arg.DisplayName,
|
||||
Description: arg.Description,
|
||||
Type: arg.Type,
|
||||
FormType: arg.FormType,
|
||||
Mutable: arg.Mutable,
|
||||
DefaultValue: arg.DefaultValue,
|
||||
Icon: arg.Icon,
|
||||
|
||||
Generated
+19
@@ -132,6 +132,22 @@ CREATE TYPE parameter_destination_scheme AS ENUM (
|
||||
'provisioner_variable'
|
||||
);
|
||||
|
||||
CREATE TYPE parameter_form_type AS ENUM (
|
||||
'',
|
||||
'error',
|
||||
'radio',
|
||||
'dropdown',
|
||||
'input',
|
||||
'textarea',
|
||||
'slider',
|
||||
'checkbox',
|
||||
'switch',
|
||||
'tag-select',
|
||||
'multi-select'
|
||||
);
|
||||
|
||||
COMMENT ON TYPE parameter_form_type IS 'Enum set should match the terraform provider set. This is defined as future form_types are not supported, and should be rejected. Always include the empty string for using the default form type.';
|
||||
|
||||
CREATE TYPE parameter_scope AS ENUM (
|
||||
'template',
|
||||
'import_job',
|
||||
@@ -1434,6 +1450,7 @@ CREATE TABLE template_version_parameters (
|
||||
display_name text DEFAULT ''::text NOT NULL,
|
||||
display_order integer DEFAULT 0 NOT NULL,
|
||||
ephemeral boolean DEFAULT false NOT NULL,
|
||||
form_type parameter_form_type DEFAULT ''::parameter_form_type NOT NULL,
|
||||
CONSTRAINT validation_monotonic_order CHECK ((validation_monotonic = ANY (ARRAY['increasing'::text, 'decreasing'::text, ''::text])))
|
||||
);
|
||||
|
||||
@@ -1469,6 +1486,8 @@ COMMENT ON COLUMN template_version_parameters.display_order IS 'Specifies the or
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.ephemeral IS 'The value of an ephemeral parameter will not be preserved between consecutive workspace builds.';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.form_type IS 'Specify what form_type should be used to render the parameter in the UI. Unsupported values are rejected.';
|
||||
|
||||
CREATE TABLE template_version_preset_parameters (
|
||||
id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||||
template_version_preset_id uuid NOT NULL,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE template_version_parameters DROP COLUMN form_type;
|
||||
DROP TYPE parameter_form_type;
|
||||
@@ -0,0 +1,11 @@
|
||||
CREATE TYPE parameter_form_type AS ENUM ('', 'error', 'radio', 'dropdown', 'input', 'textarea', 'slider', 'checkbox', 'switch', 'tag-select', 'multi-select');
|
||||
COMMENT ON TYPE parameter_form_type
|
||||
IS 'Enum set should match the terraform provider set. This is defined as future form_types are not supported, and should be rejected. '
|
||||
'Always include the empty string for using the default form type.';
|
||||
|
||||
-- Intentionally leaving the default blank. The provisioner will not re-run any
|
||||
-- imports to backfill these values. Missing values just have to be handled.
|
||||
ALTER TABLE template_version_parameters ADD COLUMN form_type parameter_form_type NOT NULL DEFAULT '';
|
||||
|
||||
COMMENT ON COLUMN template_version_parameters.form_type
|
||||
IS 'Specify what form_type should be used to render the parameter in the UI. Unsupported values are rejected.';
|
||||
@@ -1108,6 +1108,92 @@ func AllParameterDestinationSchemeValues() []ParameterDestinationScheme {
|
||||
}
|
||||
}
|
||||
|
||||
// Enum set should match the terraform provider set. This is defined as future form_types are not supported, and should be rejected. Always include the empty string for using the default form type.
|
||||
type ParameterFormType string
|
||||
|
||||
const (
|
||||
ParameterFormTypeValue0 ParameterFormType = ""
|
||||
ParameterFormTypeError ParameterFormType = "error"
|
||||
ParameterFormTypeRadio ParameterFormType = "radio"
|
||||
ParameterFormTypeDropdown ParameterFormType = "dropdown"
|
||||
ParameterFormTypeInput ParameterFormType = "input"
|
||||
ParameterFormTypeTextarea ParameterFormType = "textarea"
|
||||
ParameterFormTypeSlider ParameterFormType = "slider"
|
||||
ParameterFormTypeCheckbox ParameterFormType = "checkbox"
|
||||
ParameterFormTypeSwitch ParameterFormType = "switch"
|
||||
ParameterFormTypeTagSelect ParameterFormType = "tag-select"
|
||||
ParameterFormTypeMultiSelect ParameterFormType = "multi-select"
|
||||
)
|
||||
|
||||
func (e *ParameterFormType) Scan(src interface{}) error {
|
||||
switch s := src.(type) {
|
||||
case []byte:
|
||||
*e = ParameterFormType(s)
|
||||
case string:
|
||||
*e = ParameterFormType(s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for ParameterFormType: %T", src)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NullParameterFormType struct {
|
||||
ParameterFormType ParameterFormType `json:"parameter_form_type"`
|
||||
Valid bool `json:"valid"` // Valid is true if ParameterFormType is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (ns *NullParameterFormType) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
ns.ParameterFormType, ns.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
ns.Valid = true
|
||||
return ns.ParameterFormType.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (ns NullParameterFormType) Value() (driver.Value, error) {
|
||||
if !ns.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return string(ns.ParameterFormType), nil
|
||||
}
|
||||
|
||||
func (e ParameterFormType) Valid() bool {
|
||||
switch e {
|
||||
case ParameterFormTypeValue0,
|
||||
ParameterFormTypeError,
|
||||
ParameterFormTypeRadio,
|
||||
ParameterFormTypeDropdown,
|
||||
ParameterFormTypeInput,
|
||||
ParameterFormTypeTextarea,
|
||||
ParameterFormTypeSlider,
|
||||
ParameterFormTypeCheckbox,
|
||||
ParameterFormTypeSwitch,
|
||||
ParameterFormTypeTagSelect,
|
||||
ParameterFormTypeMultiSelect:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AllParameterFormTypeValues() []ParameterFormType {
|
||||
return []ParameterFormType{
|
||||
ParameterFormTypeValue0,
|
||||
ParameterFormTypeError,
|
||||
ParameterFormTypeRadio,
|
||||
ParameterFormTypeDropdown,
|
||||
ParameterFormTypeInput,
|
||||
ParameterFormTypeTextarea,
|
||||
ParameterFormTypeSlider,
|
||||
ParameterFormTypeCheckbox,
|
||||
ParameterFormTypeSwitch,
|
||||
ParameterFormTypeTagSelect,
|
||||
ParameterFormTypeMultiSelect,
|
||||
}
|
||||
}
|
||||
|
||||
type ParameterScope string
|
||||
|
||||
const (
|
||||
@@ -3308,6 +3394,8 @@ type TemplateVersionParameter struct {
|
||||
DisplayOrder int32 `db:"display_order" json:"display_order"`
|
||||
// The value of an ephemeral parameter will not be preserved between consecutive workspace builds.
|
||||
Ephemeral bool `db:"ephemeral" json:"ephemeral"`
|
||||
// Specify what form_type should be used to render the parameter in the UI. Unsupported values are rejected.
|
||||
FormType ParameterFormType `db:"form_type" json:"form_type"`
|
||||
}
|
||||
|
||||
type TemplateVersionPreset struct {
|
||||
|
||||
@@ -11178,7 +11178,7 @@ func (q *sqlQuerier) UpdateTemplateScheduleByID(ctx context.Context, arg UpdateT
|
||||
}
|
||||
|
||||
const getTemplateVersionParameters = `-- name: GetTemplateVersionParameters :many
|
||||
SELECT template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error, validation_monotonic, required, display_name, display_order, ephemeral FROM template_version_parameters WHERE template_version_id = $1 ORDER BY display_order ASC, LOWER(name) ASC
|
||||
SELECT template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error, validation_monotonic, required, display_name, display_order, ephemeral, form_type FROM template_version_parameters WHERE template_version_id = $1 ORDER BY display_order ASC, LOWER(name) ASC
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error) {
|
||||
@@ -11208,6 +11208,7 @@ func (q *sqlQuerier) GetTemplateVersionParameters(ctx context.Context, templateV
|
||||
&i.DisplayName,
|
||||
&i.DisplayOrder,
|
||||
&i.Ephemeral,
|
||||
&i.FormType,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -11229,6 +11230,7 @@ INSERT INTO
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
form_type,
|
||||
mutable,
|
||||
default_value,
|
||||
icon,
|
||||
@@ -11261,28 +11263,30 @@ VALUES
|
||||
$14,
|
||||
$15,
|
||||
$16,
|
||||
$17
|
||||
) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error, validation_monotonic, required, display_name, display_order, ephemeral
|
||||
$17,
|
||||
$18
|
||||
) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error, validation_monotonic, required, display_name, display_order, ephemeral, form_type
|
||||
`
|
||||
|
||||
type InsertTemplateVersionParameterParams struct {
|
||||
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Type string `db:"type" json:"type"`
|
||||
Mutable bool `db:"mutable" json:"mutable"`
|
||||
DefaultValue string `db:"default_value" json:"default_value"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Options json.RawMessage `db:"options" json:"options"`
|
||||
ValidationRegex string `db:"validation_regex" json:"validation_regex"`
|
||||
ValidationMin sql.NullInt32 `db:"validation_min" json:"validation_min"`
|
||||
ValidationMax sql.NullInt32 `db:"validation_max" json:"validation_max"`
|
||||
ValidationError string `db:"validation_error" json:"validation_error"`
|
||||
ValidationMonotonic string `db:"validation_monotonic" json:"validation_monotonic"`
|
||||
Required bool `db:"required" json:"required"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
DisplayOrder int32 `db:"display_order" json:"display_order"`
|
||||
Ephemeral bool `db:"ephemeral" json:"ephemeral"`
|
||||
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Type string `db:"type" json:"type"`
|
||||
FormType ParameterFormType `db:"form_type" json:"form_type"`
|
||||
Mutable bool `db:"mutable" json:"mutable"`
|
||||
DefaultValue string `db:"default_value" json:"default_value"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
Options json.RawMessage `db:"options" json:"options"`
|
||||
ValidationRegex string `db:"validation_regex" json:"validation_regex"`
|
||||
ValidationMin sql.NullInt32 `db:"validation_min" json:"validation_min"`
|
||||
ValidationMax sql.NullInt32 `db:"validation_max" json:"validation_max"`
|
||||
ValidationError string `db:"validation_error" json:"validation_error"`
|
||||
ValidationMonotonic string `db:"validation_monotonic" json:"validation_monotonic"`
|
||||
Required bool `db:"required" json:"required"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
DisplayOrder int32 `db:"display_order" json:"display_order"`
|
||||
Ephemeral bool `db:"ephemeral" json:"ephemeral"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error) {
|
||||
@@ -11291,6 +11295,7 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins
|
||||
arg.Name,
|
||||
arg.Description,
|
||||
arg.Type,
|
||||
arg.FormType,
|
||||
arg.Mutable,
|
||||
arg.DefaultValue,
|
||||
arg.Icon,
|
||||
@@ -11324,6 +11329,7 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins
|
||||
&i.DisplayName,
|
||||
&i.DisplayOrder,
|
||||
&i.Ephemeral,
|
||||
&i.FormType,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ INSERT INTO
|
||||
name,
|
||||
description,
|
||||
type,
|
||||
form_type,
|
||||
mutable,
|
||||
default_value,
|
||||
icon,
|
||||
@@ -37,7 +38,8 @@ VALUES
|
||||
$14,
|
||||
$15,
|
||||
$16,
|
||||
$17
|
||||
$17,
|
||||
$18
|
||||
) RETURNING *;
|
||||
|
||||
-- name: GetTemplateVersionParameters :many
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
protobuf "google.golang.org/protobuf/proto"
|
||||
|
||||
"cdr.dev/slog"
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
|
||||
"github.com/coder/coder/v2/codersdk/drpcsdk"
|
||||
|
||||
@@ -1453,12 +1454,24 @@ func (s *server) completeTemplateImportJob(ctx context.Context, job database.Pro
|
||||
}
|
||||
}
|
||||
|
||||
pft, err := sdkproto.ProviderFormType(richParameter.FormType)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parameter %q: %w", richParameter.Name, err)
|
||||
}
|
||||
|
||||
dft := database.ParameterFormType(pft)
|
||||
if !dft.Valid() {
|
||||
list := strings.Join(slice.ToStrings(database.AllParameterFormTypeValues()), ", ")
|
||||
return xerrors.Errorf("parameter %q field 'form_type' not valid, currently supported: %s", richParameter.Name, list)
|
||||
}
|
||||
|
||||
_, err = db.InsertTemplateVersionParameter(ctx, database.InsertTemplateVersionParameterParams{
|
||||
TemplateVersionID: input.TemplateVersionID,
|
||||
Name: richParameter.Name,
|
||||
DisplayName: richParameter.DisplayName,
|
||||
Description: richParameter.Description,
|
||||
Type: richParameter.Type,
|
||||
FormType: dft,
|
||||
Mutable: richParameter.Mutable,
|
||||
DefaultValue: richParameter.DefaultValue,
|
||||
Icon: richParameter.Icon,
|
||||
|
||||
@@ -1384,6 +1384,60 @@ func TestCompleteJob(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("WorkspaceBuild_BadFormType", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv, db, _, pd := setup(t, false, &overrides{})
|
||||
jobID := uuid.New()
|
||||
versionID := uuid.New()
|
||||
err := db.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{
|
||||
ID: versionID,
|
||||
JobID: jobID,
|
||||
OrganizationID: pd.OrganizationID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
job, err := db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
|
||||
ID: jobID,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
Input: []byte(`{"template_version_id": "` + versionID.String() + `"}`),
|
||||
StorageMethod: database.ProvisionerStorageMethodFile,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
OrganizationID: pd.OrganizationID,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.AcquireProvisionerJob(ctx, database.AcquireProvisionerJobParams{
|
||||
OrganizationID: pd.OrganizationID,
|
||||
WorkerID: uuid.NullUUID{
|
||||
UUID: pd.ID,
|
||||
Valid: true,
|
||||
},
|
||||
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = srv.CompleteJob(ctx, &proto.CompletedJob{
|
||||
JobId: job.ID.String(),
|
||||
Type: &proto.CompletedJob_TemplateImport_{
|
||||
TemplateImport: &proto.CompletedJob_TemplateImport{
|
||||
StartResources: []*sdkproto.Resource{{
|
||||
Name: "hello",
|
||||
Type: "aws_instance",
|
||||
}},
|
||||
StopResources: []*sdkproto.Resource{},
|
||||
RichParameters: []*sdkproto.RichParameter{
|
||||
{
|
||||
Name: "parameter",
|
||||
Type: "string",
|
||||
FormType: -1,
|
||||
},
|
||||
},
|
||||
Plan: []byte("{}"),
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "unsupported form type")
|
||||
})
|
||||
|
||||
t.Run("TemplateImport_MissingGitAuth", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
srv, db, _, pd := setup(t, false, &overrides{})
|
||||
|
||||
@@ -31,14 +31,12 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/provisionerdserver"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/coderd/rbac/policy"
|
||||
"github.com/coder/coder/v2/coderd/render"
|
||||
"github.com/coder/coder/v2/coderd/tracing"
|
||||
"github.com/coder/coder/v2/coderd/util/ptr"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/examples"
|
||||
"github.com/coder/coder/v2/provisioner/terraform/tfparse"
|
||||
"github.com/coder/coder/v2/provisionersdk"
|
||||
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
|
||||
)
|
||||
|
||||
// @Summary Get template version by ID
|
||||
@@ -307,7 +305,7 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re
|
||||
return
|
||||
}
|
||||
|
||||
templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters)
|
||||
templateVersionParameters, err := db2sdk.TemplateVersionParameters(dbTemplateVersionParameters)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Internal error converting template version parameter.",
|
||||
@@ -1869,67 +1867,6 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi
|
||||
}
|
||||
}
|
||||
|
||||
func convertTemplateVersionParameters(dbParams []database.TemplateVersionParameter) ([]codersdk.TemplateVersionParameter, error) {
|
||||
params := make([]codersdk.TemplateVersionParameter, 0)
|
||||
for _, dbParameter := range dbParams {
|
||||
param, err := convertTemplateVersionParameter(dbParameter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params = append(params, param)
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func convertTemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) {
|
||||
var protoOptions []*sdkproto.RichParameterOption
|
||||
err := json.Unmarshal(param.Options, &protoOptions)
|
||||
if err != nil {
|
||||
return codersdk.TemplateVersionParameter{}, err
|
||||
}
|
||||
options := make([]codersdk.TemplateVersionParameterOption, 0)
|
||||
for _, option := range protoOptions {
|
||||
options = append(options, codersdk.TemplateVersionParameterOption{
|
||||
Name: option.Name,
|
||||
Description: option.Description,
|
||||
Value: option.Value,
|
||||
Icon: option.Icon,
|
||||
})
|
||||
}
|
||||
|
||||
descriptionPlaintext, err := render.PlaintextFromMarkdown(param.Description)
|
||||
if err != nil {
|
||||
return codersdk.TemplateVersionParameter{}, err
|
||||
}
|
||||
|
||||
var validationMin, validationMax *int32
|
||||
if param.ValidationMin.Valid {
|
||||
validationMin = ¶m.ValidationMin.Int32
|
||||
}
|
||||
if param.ValidationMax.Valid {
|
||||
validationMax = ¶m.ValidationMax.Int32
|
||||
}
|
||||
|
||||
return codersdk.TemplateVersionParameter{
|
||||
Name: param.Name,
|
||||
DisplayName: param.DisplayName,
|
||||
Description: param.Description,
|
||||
DescriptionPlaintext: descriptionPlaintext,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: param.DefaultValue,
|
||||
Icon: param.Icon,
|
||||
Options: options,
|
||||
ValidationRegex: param.ValidationRegex,
|
||||
ValidationMin: validationMin,
|
||||
ValidationMax: validationMax,
|
||||
ValidationError: param.ValidationError,
|
||||
ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic),
|
||||
Required: param.Required,
|
||||
Ephemeral: param.Ephemeral,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertTemplateVersionVariables(dbVariables []database.TemplateVersionVariable) []codersdk.TemplateVersionVariable {
|
||||
variables := make([]codersdk.TemplateVersionVariable, 0)
|
||||
for _, dbVariable := range dbVariables {
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/coder/coder/v2/provisioner/echo"
|
||||
"github.com/coder/coder/v2/provisionersdk/proto"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
"github.com/coder/terraform-provider-coder/v2/provider"
|
||||
)
|
||||
|
||||
func TestWorkspace(t *testing.T) {
|
||||
@@ -3527,6 +3528,12 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
secondParameterDescription = "_This_ is second *parameter*"
|
||||
secondParameterValue = "2"
|
||||
secondParameterValidationMonotonic = codersdk.MonotonicOrderIncreasing
|
||||
|
||||
thirdParameterName = "third_parameter"
|
||||
thirdParameterType = "list(string)"
|
||||
thirdParameterFormType = proto.ParameterFormType_MULTISELECT
|
||||
thirdParameterDefault = `["red"]`
|
||||
thirdParameterOption = "red"
|
||||
)
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
@@ -3542,6 +3549,7 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
Name: firstParameterName,
|
||||
Type: firstParameterType,
|
||||
Description: firstParameterDescription,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
},
|
||||
{
|
||||
Name: secondParameterName,
|
||||
@@ -3551,6 +3559,19 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
ValidationMin: ptr.Ref(int32(1)),
|
||||
ValidationMax: ptr.Ref(int32(3)),
|
||||
ValidationMonotonic: string(secondParameterValidationMonotonic),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
},
|
||||
{
|
||||
Name: thirdParameterName,
|
||||
Type: thirdParameterType,
|
||||
DefaultValue: thirdParameterDefault,
|
||||
Options: []*proto.RichParameterOption{
|
||||
{
|
||||
Name: thirdParameterOption,
|
||||
Value: thirdParameterOption,
|
||||
},
|
||||
},
|
||||
FormType: thirdParameterFormType,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3575,12 +3596,13 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
|
||||
templateRichParameters, err := client.TemplateVersionRichParameters(ctx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, templateRichParameters, 2)
|
||||
require.Len(t, templateRichParameters, 3)
|
||||
require.Equal(t, firstParameterName, templateRichParameters[0].Name)
|
||||
require.Equal(t, firstParameterType, templateRichParameters[0].Type)
|
||||
require.Equal(t, firstParameterDescription, templateRichParameters[0].Description)
|
||||
require.Equal(t, firstParameterDescriptionPlaintext, templateRichParameters[0].DescriptionPlaintext)
|
||||
require.Equal(t, codersdk.ValidationMonotonicOrder(""), templateRichParameters[0].ValidationMonotonic) // no validation for string
|
||||
|
||||
require.Equal(t, secondParameterName, templateRichParameters[1].Name)
|
||||
require.Equal(t, secondParameterDisplayName, templateRichParameters[1].DisplayName)
|
||||
require.Equal(t, secondParameterType, templateRichParameters[1].Type)
|
||||
@@ -3588,9 +3610,18 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
require.Equal(t, secondParameterDescriptionPlaintext, templateRichParameters[1].DescriptionPlaintext)
|
||||
require.Equal(t, secondParameterValidationMonotonic, templateRichParameters[1].ValidationMonotonic)
|
||||
|
||||
third := templateRichParameters[2]
|
||||
require.Equal(t, thirdParameterName, third.Name)
|
||||
require.Equal(t, thirdParameterType, third.Type)
|
||||
require.Equal(t, string(database.ParameterFormTypeMultiSelect), third.FormType)
|
||||
require.Equal(t, thirdParameterDefault, third.DefaultValue)
|
||||
require.Equal(t, thirdParameterOption, third.Options[0].Name)
|
||||
require.Equal(t, thirdParameterOption, third.Options[0].Value)
|
||||
|
||||
expectedBuildParameters := []codersdk.WorkspaceBuildParameter{
|
||||
{Name: firstParameterName, Value: firstParameterValue},
|
||||
{Name: secondParameterName, Value: secondParameterValue},
|
||||
{Name: thirdParameterName, Value: thirdParameterDefault},
|
||||
}
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
@@ -3606,6 +3637,72 @@ func TestWorkspaceWithRichParameters(t *testing.T) {
|
||||
require.ElementsMatch(t, expectedBuildParameters, workspaceBuildParameters)
|
||||
}
|
||||
|
||||
func TestWorkspaceWithMultiSelectFailure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
|
||||
user := coderdtest.CreateFirstUser(t, client)
|
||||
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
|
||||
Parse: echo.ParseComplete,
|
||||
ProvisionPlan: []*proto.Response{
|
||||
{
|
||||
Type: &proto.Response_Plan{
|
||||
Plan: &proto.PlanComplete{
|
||||
Parameters: []*proto.RichParameter{
|
||||
{
|
||||
Name: "param",
|
||||
Type: provider.OptionTypeListString,
|
||||
DefaultValue: `["red"]`,
|
||||
Options: []*proto.RichParameterOption{
|
||||
{
|
||||
Name: "red",
|
||||
Value: "red",
|
||||
},
|
||||
},
|
||||
FormType: proto.ParameterFormType_MULTISELECT,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ProvisionApply: []*proto.Response{{
|
||||
Type: &proto.Response_Apply{
|
||||
Apply: &proto.ApplyComplete{},
|
||||
},
|
||||
}},
|
||||
})
|
||||
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
|
||||
templateRichParameters, err := client.TemplateVersionRichParameters(ctx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, templateRichParameters, 1)
|
||||
|
||||
expectedBuildParameters := []codersdk.WorkspaceBuildParameter{
|
||||
// purple is not in the response set
|
||||
{Name: "param", Value: `["red", "purple"]`},
|
||||
}
|
||||
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
req := codersdk.CreateWorkspaceRequest{
|
||||
TemplateID: template.ID,
|
||||
Name: coderdtest.RandomUsername(t),
|
||||
AutostartSchedule: ptr.Ref("CRON_TZ=US/Central 30 9 * * 1-5"),
|
||||
TTLMillis: ptr.Ref((8 * time.Hour).Milliseconds()),
|
||||
AutomaticUpdates: codersdk.AutomaticUpdatesNever,
|
||||
RichParameterValues: expectedBuildParameters,
|
||||
}
|
||||
|
||||
_, err = client.CreateUserWorkspace(context.Background(), codersdk.Me, req)
|
||||
require.Error(t, err)
|
||||
var apiError *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiError)
|
||||
require.Equal(t, http.StatusBadRequest, apiError.StatusCode())
|
||||
}
|
||||
|
||||
func TestWorkspaceWithOptionalRichParameters(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
+36
-12
@@ -1,9 +1,12 @@
|
||||
package codersdk
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
"tailscale.com/types/ptr"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/util/slice"
|
||||
"github.com/coder/terraform-provider-coder/v2/provider"
|
||||
)
|
||||
|
||||
@@ -66,18 +69,8 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
|
||||
current = richParameter.DefaultValue
|
||||
}
|
||||
|
||||
if len(richParameter.Options) > 0 {
|
||||
var matched bool
|
||||
for _, opt := range richParameter.Options {
|
||||
if opt.Value == current {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options))
|
||||
}
|
||||
if len(richParameter.Options) > 0 && !inOptionSet(richParameter, current) {
|
||||
return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options))
|
||||
}
|
||||
|
||||
if !validationEnabled(richParameter) {
|
||||
@@ -104,6 +97,37 @@ func validateBuildParameter(richParameter TemplateVersionParameter, buildParamet
|
||||
return validation.Valid(richParameter.Type, current, previous)
|
||||
}
|
||||
|
||||
// inOptionSet returns if the value given is in the set of options for a parameter.
|
||||
func inOptionSet(richParameter TemplateVersionParameter, value string) bool {
|
||||
optionValues := make([]string, 0, len(richParameter.Options))
|
||||
for _, option := range richParameter.Options {
|
||||
optionValues = append(optionValues, option.Value)
|
||||
}
|
||||
|
||||
// If the type is `list(string)` and the form_type is `multi-select`, then we check each individual
|
||||
// value in the list against the option set.
|
||||
isMultiSelect := richParameter.Type == provider.OptionTypeListString && richParameter.FormType == string(provider.ParameterFormTypeMultiSelect)
|
||||
|
||||
if !isMultiSelect {
|
||||
// This is the simple case. Just checking if the value is in the option set.
|
||||
return slice.Contains(optionValues, value)
|
||||
}
|
||||
|
||||
var checks []string
|
||||
err := json.Unmarshal([]byte(value), &checks)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, check := range checks {
|
||||
if !slice.Contains(optionValues, check) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func findBuildParameter(params []WorkspaceBuildParameter, parameterName string) (*WorkspaceBuildParameter, bool) {
|
||||
if params == nil {
|
||||
return nil, false
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package codersdk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/terraform-provider-coder/v2/provider"
|
||||
)
|
||||
|
||||
func Test_inOptionSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
options := func(vals ...string) []TemplateVersionParameterOption {
|
||||
opts := make([]TemplateVersionParameterOption, 0, len(vals))
|
||||
for _, val := range vals {
|
||||
opts = append(opts, TemplateVersionParameterOption{
|
||||
Name: val,
|
||||
Value: val,
|
||||
})
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
param TemplateVersionParameter
|
||||
value string
|
||||
want bool
|
||||
}{
|
||||
// The function should never be called with 0 options, but if it is,
|
||||
// it should always return false.
|
||||
{
|
||||
name: "empty",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no-options",
|
||||
param: TemplateVersionParameter{
|
||||
Options: make([]TemplateVersionParameterOption, 0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no-options-multi",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: string(provider.ParameterFormTypeMultiSelect),
|
||||
Options: make([]TemplateVersionParameterOption, 0),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "no-options-list(string)",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: "",
|
||||
Options: make([]TemplateVersionParameterOption, 0),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "list(string)-no-form",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: "",
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: false,
|
||||
value: `["red", "blue", "green"]`,
|
||||
},
|
||||
// now for some reasonable values
|
||||
{
|
||||
name: "list(string)-multi",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: string(provider.ParameterFormTypeMultiSelect),
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: true,
|
||||
value: `["red", "blue", "green"]`,
|
||||
},
|
||||
{
|
||||
name: "string with json",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeString,
|
||||
Options: options(`["red","blue","green"]`, `["red","orange"]`),
|
||||
},
|
||||
want: true,
|
||||
value: `["red","blue","green"]`,
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeString,
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: true,
|
||||
value: "red",
|
||||
},
|
||||
// False values
|
||||
{
|
||||
name: "list(string)-multi",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: string(provider.ParameterFormTypeMultiSelect),
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: false,
|
||||
value: `["red", "blue", "purple"]`,
|
||||
},
|
||||
{
|
||||
name: "string with json",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeString,
|
||||
Options: options(`["red","blue"]`, `["red","orange"]`),
|
||||
},
|
||||
want: false,
|
||||
value: `["red","blue","green"]`,
|
||||
},
|
||||
{
|
||||
name: "string",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeString,
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: false,
|
||||
value: "purple",
|
||||
},
|
||||
{
|
||||
name: "list(string)-multi-scalar-value",
|
||||
param: TemplateVersionParameter{
|
||||
Type: provider.OptionTypeListString,
|
||||
FormType: string(provider.ParameterFormTypeMultiSelect),
|
||||
Options: options("red", "green", "blue"),
|
||||
},
|
||||
want: false,
|
||||
value: "green",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got := inOptionSet(tt.param, tt.value)
|
||||
require.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -54,22 +54,25 @@ const (
|
||||
|
||||
// TemplateVersionParameter represents a parameter for a template version.
|
||||
type TemplateVersionParameter struct {
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
Description string `json:"description"`
|
||||
DescriptionPlaintext string `json:"description_plaintext"`
|
||||
Type string `json:"type" enums:"string,number,bool,list(string)"`
|
||||
Mutable bool `json:"mutable"`
|
||||
DefaultValue string `json:"default_value"`
|
||||
Icon string `json:"icon"`
|
||||
Options []TemplateVersionParameterOption `json:"options"`
|
||||
ValidationError string `json:"validation_error,omitempty"`
|
||||
ValidationRegex string `json:"validation_regex,omitempty"`
|
||||
ValidationMin *int32 `json:"validation_min,omitempty"`
|
||||
ValidationMax *int32 `json:"validation_max,omitempty"`
|
||||
ValidationMonotonic ValidationMonotonicOrder `json:"validation_monotonic,omitempty" enums:"increasing,decreasing"`
|
||||
Required bool `json:"required"`
|
||||
Ephemeral bool `json:"ephemeral"`
|
||||
Name string `json:"name"`
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
Description string `json:"description"`
|
||||
DescriptionPlaintext string `json:"description_plaintext"`
|
||||
Type string `json:"type" enums:"string,number,bool,list(string)"`
|
||||
// FormType has an enum value of empty string, `""`.
|
||||
// Keep the leading comma in the enums struct tag.
|
||||
FormType string `json:"form_type" enums:",radio,dropdown,input,textarea,slider,checkbox,switch,tag-select,multi-select,error"`
|
||||
Mutable bool `json:"mutable"`
|
||||
DefaultValue string `json:"default_value"`
|
||||
Icon string `json:"icon"`
|
||||
Options []TemplateVersionParameterOption `json:"options"`
|
||||
ValidationError string `json:"validation_error,omitempty"`
|
||||
ValidationRegex string `json:"validation_regex,omitempty"`
|
||||
ValidationMin *int32 `json:"validation_min,omitempty"`
|
||||
ValidationMax *int32 `json:"validation_max,omitempty"`
|
||||
ValidationMonotonic ValidationMonotonicOrder `json:"validation_monotonic,omitempty" enums:"increasing,decreasing"`
|
||||
Required bool `json:"required"`
|
||||
Ephemeral bool `json:"ephemeral"`
|
||||
}
|
||||
|
||||
// TemplateVersionParameterOption represents a selectable option for a template parameter.
|
||||
|
||||
Generated
+31
-18
@@ -7185,6 +7185,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
"description_plaintext": "string",
|
||||
"display_name": "string",
|
||||
"ephemeral": true,
|
||||
"form_type": "",
|
||||
"icon": "string",
|
||||
"mutable": true,
|
||||
"name": "string",
|
||||
@@ -7208,29 +7209,41 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|-------------------------|---------------------------------------------------------------------------------------------|----------|--------------|-------------|
|
||||
| `default_value` | string | false | | |
|
||||
| `description` | string | false | | |
|
||||
| `description_plaintext` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `ephemeral` | boolean | false | | |
|
||||
| `icon` | string | false | | |
|
||||
| `mutable` | boolean | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `options` | array of [codersdk.TemplateVersionParameterOption](#codersdktemplateversionparameteroption) | false | | |
|
||||
| `required` | boolean | false | | |
|
||||
| `type` | string | false | | |
|
||||
| `validation_error` | string | false | | |
|
||||
| `validation_max` | integer | false | | |
|
||||
| `validation_min` | integer | false | | |
|
||||
| `validation_monotonic` | [codersdk.ValidationMonotonicOrder](#codersdkvalidationmonotonicorder) | false | | |
|
||||
| `validation_regex` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|-------------------------|---------------------------------------------------------------------------------------------|----------|--------------|----------------------------------------------------------------------------------------------------|
|
||||
| `default_value` | string | false | | |
|
||||
| `description` | string | false | | |
|
||||
| `description_plaintext` | string | false | | |
|
||||
| `display_name` | string | false | | |
|
||||
| `ephemeral` | boolean | false | | |
|
||||
| `form_type` | string | false | | Form type has an enum value of empty string, `""`. Keep the leading comma in the enums struct tag. |
|
||||
| `icon` | string | false | | |
|
||||
| `mutable` | boolean | false | | |
|
||||
| `name` | string | false | | |
|
||||
| `options` | array of [codersdk.TemplateVersionParameterOption](#codersdktemplateversionparameteroption) | false | | |
|
||||
| `required` | boolean | false | | |
|
||||
| `type` | string | false | | |
|
||||
| `validation_error` | string | false | | |
|
||||
| `validation_max` | integer | false | | |
|
||||
| `validation_min` | integer | false | | |
|
||||
| `validation_monotonic` | [codersdk.ValidationMonotonicOrder](#codersdkvalidationmonotonicorder) | false | | |
|
||||
| `validation_regex` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Property | Value |
|
||||
|------------------------|----------------|
|
||||
| `form_type` | `` |
|
||||
| `form_type` | `radio` |
|
||||
| `form_type` | `dropdown` |
|
||||
| `form_type` | `input` |
|
||||
| `form_type` | `textarea` |
|
||||
| `form_type` | `slider` |
|
||||
| `form_type` | `checkbox` |
|
||||
| `form_type` | `switch` |
|
||||
| `form_type` | `tag-select` |
|
||||
| `form_type` | `multi-select` |
|
||||
| `form_type` | `error` |
|
||||
| `type` | `string` |
|
||||
| `type` | `number` |
|
||||
| `type` | `bool` |
|
||||
|
||||
Generated
+36
-23
@@ -3165,6 +3165,7 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r
|
||||
"description_plaintext": "string",
|
||||
"display_name": "string",
|
||||
"ephemeral": true,
|
||||
"form_type": "",
|
||||
"icon": "string",
|
||||
"mutable": true,
|
||||
"name": "string",
|
||||
@@ -3197,34 +3198,46 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/r
|
||||
|
||||
Status Code **200**
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|---------------------------|----------------------------------------------------------------------------------|----------|--------------|-------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» default_value` | string | false | | |
|
||||
| `» description` | string | false | | |
|
||||
| `» description_plaintext` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» ephemeral` | boolean | false | | |
|
||||
| `» icon` | string | false | | |
|
||||
| `» mutable` | boolean | false | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» options` | array | false | | |
|
||||
| `»» description` | string | false | | |
|
||||
| `»» icon` | string | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» value` | string | false | | |
|
||||
| `» required` | boolean | false | | |
|
||||
| `» type` | string | false | | |
|
||||
| `» validation_error` | string | false | | |
|
||||
| `» validation_max` | integer | false | | |
|
||||
| `» validation_min` | integer | false | | |
|
||||
| `» validation_monotonic` | [codersdk.ValidationMonotonicOrder](schemas.md#codersdkvalidationmonotonicorder) | false | | |
|
||||
| `» validation_regex` | string | false | | |
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|---------------------------|----------------------------------------------------------------------------------|----------|--------------|----------------------------------------------------------------------------------------------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» default_value` | string | false | | |
|
||||
| `» description` | string | false | | |
|
||||
| `» description_plaintext` | string | false | | |
|
||||
| `» display_name` | string | false | | |
|
||||
| `» ephemeral` | boolean | false | | |
|
||||
| `» form_type` | string | false | | Form type has an enum value of empty string, `""`. Keep the leading comma in the enums struct tag. |
|
||||
| `» icon` | string | false | | |
|
||||
| `» mutable` | boolean | false | | |
|
||||
| `» name` | string | false | | |
|
||||
| `» options` | array | false | | |
|
||||
| `»» description` | string | false | | |
|
||||
| `»» icon` | string | false | | |
|
||||
| `»» name` | string | false | | |
|
||||
| `»» value` | string | false | | |
|
||||
| `» required` | boolean | false | | |
|
||||
| `» type` | string | false | | |
|
||||
| `» validation_error` | string | false | | |
|
||||
| `» validation_max` | integer | false | | |
|
||||
| `» validation_min` | integer | false | | |
|
||||
| `» validation_monotonic` | [codersdk.ValidationMonotonicOrder](schemas.md#codersdkvalidationmonotonicorder) | false | | |
|
||||
| `» validation_regex` | string | false | | |
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Property | Value |
|
||||
|------------------------|----------------|
|
||||
| `form_type` | `` |
|
||||
| `form_type` | `radio` |
|
||||
| `form_type` | `dropdown` |
|
||||
| `form_type` | `input` |
|
||||
| `form_type` | `textarea` |
|
||||
| `form_type` | `slider` |
|
||||
| `form_type` | `checkbox` |
|
||||
| `form_type` | `switch` |
|
||||
| `form_type` | `tag-select` |
|
||||
| `form_type` | `multi-select` |
|
||||
| `form_type` | `error` |
|
||||
| `type` | `string` |
|
||||
| `type` | `number` |
|
||||
| `type` | `bool` |
|
||||
|
||||
@@ -757,10 +757,17 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
|
||||
if param.Default != nil {
|
||||
defaultVal = *param.Default
|
||||
}
|
||||
|
||||
pft, err := proto.FormType(param.FormType)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode form_type for coder_parameter.%s: %w", resource.Name, err)
|
||||
}
|
||||
|
||||
protoParam := &proto.RichParameter{
|
||||
Name: param.Name,
|
||||
DisplayName: param.DisplayName,
|
||||
Description: param.Description,
|
||||
FormType: pft,
|
||||
Type: param.Type,
|
||||
Mutable: param.Mutable,
|
||||
DefaultValue: defaultVal,
|
||||
|
||||
@@ -608,24 +608,28 @@ func TestConvertResources(t *testing.T) {
|
||||
Description: "First parameter from child module",
|
||||
Mutable: true,
|
||||
DefaultValue: "abcdef",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Second parameter from child module",
|
||||
Type: "string",
|
||||
Description: "Second parameter from child module",
|
||||
Mutable: true,
|
||||
DefaultValue: "ghijkl",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "First parameter from module",
|
||||
Type: "string",
|
||||
Description: "First parameter from module",
|
||||
Mutable: true,
|
||||
DefaultValue: "abcdef",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Second parameter from module",
|
||||
Type: "string",
|
||||
Description: "Second parameter from module",
|
||||
Mutable: true,
|
||||
DefaultValue: "ghijkl",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Example",
|
||||
Type: "string",
|
||||
@@ -637,35 +641,41 @@ func TestConvertResources(t *testing.T) {
|
||||
Value: "second",
|
||||
}},
|
||||
Required: true,
|
||||
FormType: proto.ParameterFormType_RADIO,
|
||||
}, {
|
||||
Name: "number_example",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: nil,
|
||||
ValidationMax: nil,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_max_zero",
|
||||
Type: "number",
|
||||
DefaultValue: "-2",
|
||||
ValidationMin: terraform.PtrInt32(-3),
|
||||
ValidationMax: terraform.PtrInt32(0),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_min_max",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: terraform.PtrInt32(3),
|
||||
ValidationMax: terraform.PtrInt32(6),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_min_zero",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: terraform.PtrInt32(0),
|
||||
ValidationMax: terraform.PtrInt32(6),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Sample",
|
||||
Type: "string",
|
||||
Description: "blah blah",
|
||||
DefaultValue: "ok",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}},
|
||||
},
|
||||
"rich-parameters-order": {
|
||||
@@ -688,12 +698,14 @@ func TestConvertResources(t *testing.T) {
|
||||
Type: "string",
|
||||
Required: true,
|
||||
Order: 55,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Sample",
|
||||
Type: "string",
|
||||
Description: "blah blah",
|
||||
DefaultValue: "ok",
|
||||
Order: 99,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}},
|
||||
},
|
||||
"rich-parameters-validation": {
|
||||
@@ -719,36 +731,42 @@ func TestConvertResources(t *testing.T) {
|
||||
Mutable: true,
|
||||
ValidationMin: nil,
|
||||
ValidationMax: nil,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_max",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: nil,
|
||||
ValidationMax: terraform.PtrInt32(6),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_max_zero",
|
||||
Type: "number",
|
||||
DefaultValue: "-3",
|
||||
ValidationMin: nil,
|
||||
ValidationMax: terraform.PtrInt32(0),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_min",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: terraform.PtrInt32(3),
|
||||
ValidationMax: nil,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_min_max",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: terraform.PtrInt32(3),
|
||||
ValidationMax: terraform.PtrInt32(6),
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "number_example_min_zero",
|
||||
Type: "number",
|
||||
DefaultValue: "4",
|
||||
ValidationMin: terraform.PtrInt32(0),
|
||||
ValidationMax: nil,
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}},
|
||||
},
|
||||
"external-auth-providers": {
|
||||
@@ -824,29 +842,34 @@ func TestConvertResources(t *testing.T) {
|
||||
Description: "First parameter from child module",
|
||||
Mutable: true,
|
||||
DefaultValue: "abcdef",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Second parameter from child module",
|
||||
Type: "string",
|
||||
Description: "Second parameter from child module",
|
||||
Mutable: true,
|
||||
DefaultValue: "ghijkl",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "First parameter from module",
|
||||
Type: "string",
|
||||
Description: "First parameter from module",
|
||||
Mutable: true,
|
||||
DefaultValue: "abcdef",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Second parameter from module",
|
||||
Type: "string",
|
||||
Description: "Second parameter from module",
|
||||
Mutable: true,
|
||||
DefaultValue: "ghijkl",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}, {
|
||||
Name: "Sample",
|
||||
Type: "string",
|
||||
Description: "blah blah",
|
||||
DefaultValue: "ok",
|
||||
FormType: proto.ParameterFormType_INPUT,
|
||||
}},
|
||||
Presets: []*proto.Preset{{
|
||||
Name: "My First Project",
|
||||
|
||||
@@ -28,6 +28,7 @@ import "github.com/coder/coder/v2/apiversion"
|
||||
// - Add new field named `expiration_policy` to `Prebuild`, with a field named
|
||||
// `ttl` to define TTL-based expiration for unclaimed prebuilds.
|
||||
// - Add `group` field to `App`
|
||||
// - Add `form_type` field to parameters
|
||||
const (
|
||||
CurrentMajor = 1
|
||||
CurrentMinor = 6
|
||||
|
||||
Generated
+63
@@ -0,0 +1,63 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/terraform-provider-coder/v2/provider"
|
||||
)
|
||||
|
||||
func ProviderFormType(ft ParameterFormType) (provider.ParameterFormType, error) {
|
||||
switch ft {
|
||||
case ParameterFormType_DEFAULT:
|
||||
return provider.ParameterFormTypeDefault, nil
|
||||
case ParameterFormType_FORM_ERROR:
|
||||
return provider.ParameterFormTypeError, nil
|
||||
case ParameterFormType_RADIO:
|
||||
return provider.ParameterFormTypeRadio, nil
|
||||
case ParameterFormType_DROPDOWN:
|
||||
return provider.ParameterFormTypeDropdown, nil
|
||||
case ParameterFormType_INPUT:
|
||||
return provider.ParameterFormTypeInput, nil
|
||||
case ParameterFormType_TEXTAREA:
|
||||
return provider.ParameterFormTypeTextArea, nil
|
||||
case ParameterFormType_SLIDER:
|
||||
return provider.ParameterFormTypeSlider, nil
|
||||
case ParameterFormType_CHECKBOX:
|
||||
return provider.ParameterFormTypeCheckbox, nil
|
||||
case ParameterFormType_SWITCH:
|
||||
return provider.ParameterFormTypeSwitch, nil
|
||||
case ParameterFormType_TAGSELECT:
|
||||
return provider.ParameterFormTypeTagSelect, nil
|
||||
case ParameterFormType_MULTISELECT:
|
||||
return provider.ParameterFormTypeMultiSelect, nil
|
||||
}
|
||||
return provider.ParameterFormTypeDefault, xerrors.Errorf("unsupported form type: %s", ft)
|
||||
}
|
||||
|
||||
func FormType(ft provider.ParameterFormType) (ParameterFormType, error) {
|
||||
switch ft {
|
||||
case provider.ParameterFormTypeDefault:
|
||||
return ParameterFormType_DEFAULT, nil
|
||||
case provider.ParameterFormTypeError:
|
||||
return ParameterFormType_FORM_ERROR, nil
|
||||
case provider.ParameterFormTypeRadio:
|
||||
return ParameterFormType_RADIO, nil
|
||||
case provider.ParameterFormTypeDropdown:
|
||||
return ParameterFormType_DROPDOWN, nil
|
||||
case provider.ParameterFormTypeInput:
|
||||
return ParameterFormType_INPUT, nil
|
||||
case provider.ParameterFormTypeTextArea:
|
||||
return ParameterFormType_TEXTAREA, nil
|
||||
case provider.ParameterFormTypeSlider:
|
||||
return ParameterFormType_SLIDER, nil
|
||||
case provider.ParameterFormTypeCheckbox:
|
||||
return ParameterFormType_CHECKBOX, nil
|
||||
case provider.ParameterFormTypeSwitch:
|
||||
return ParameterFormType_SWITCH, nil
|
||||
case provider.ParameterFormTypeTagSelect:
|
||||
return ParameterFormType_TAGSELECT, nil
|
||||
case provider.ParameterFormTypeMultiSelect:
|
||||
return ParameterFormType_MULTISELECT, nil
|
||||
}
|
||||
return ParameterFormType_DEFAULT, xerrors.Errorf("unsupported form type: %s", ft)
|
||||
}
|
||||
Generated
+26
@@ -0,0 +1,26 @@
|
||||
package proto_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/provisionersdk/proto"
|
||||
"github.com/coder/terraform-provider-coder/v2/provider"
|
||||
)
|
||||
|
||||
// TestProviderFormTypeEnum keeps the provider.ParameterFormTypes() enum in sync with the
|
||||
// proto.FormType enum. If a new form type is added to the provider, it should also be added
|
||||
// to the proto file.
|
||||
func TestProviderFormTypeEnum(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
all := provider.ParameterFormTypes()
|
||||
for _, p := range all {
|
||||
t.Run(string(p), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := proto.FormType(p)
|
||||
require.NoError(t, err, "proto form type should be valid, add it to the proto file")
|
||||
})
|
||||
}
|
||||
}
|
||||
Generated
+758
-661
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,20 @@ message RichParameterOption {
|
||||
string icon = 4;
|
||||
}
|
||||
|
||||
enum ParameterFormType {
|
||||
DEFAULT = 0;
|
||||
FORM_ERROR = 1;
|
||||
RADIO = 2;
|
||||
DROPDOWN = 3;
|
||||
INPUT = 4;
|
||||
TEXTAREA = 5;
|
||||
SLIDER = 6;
|
||||
CHECKBOX = 7;
|
||||
SWITCH = 8;
|
||||
TAGSELECT = 9;
|
||||
MULTISELECT = 10;
|
||||
}
|
||||
|
||||
// RichParameter represents a variable that is exposed.
|
||||
message RichParameter {
|
||||
reserved 14;
|
||||
@@ -49,6 +63,7 @@ message RichParameter {
|
||||
string display_name = 15;
|
||||
int32 order = 16;
|
||||
bool ephemeral = 17;
|
||||
ParameterFormType form_type = 18;
|
||||
}
|
||||
|
||||
// RichParameterValue holds the key/value mapping of a parameter.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { RichParameter } from "./provisionerGenerated";
|
||||
import { ParameterFormType, type RichParameter } from "./provisionerGenerated";
|
||||
|
||||
// Rich parameters
|
||||
|
||||
@@ -19,6 +19,7 @@ export const emptyParameter: RichParameter = {
|
||||
displayName: "",
|
||||
order: 0,
|
||||
ephemeral: false,
|
||||
formType: ParameterFormType.DEFAULT,
|
||||
};
|
||||
|
||||
// firstParameter is mutable string with a default value (parameter value not required).
|
||||
@@ -149,6 +150,7 @@ export const firstBuildOption: RichParameter = {
|
||||
defaultValue: "ABCDEF",
|
||||
mutable: true,
|
||||
ephemeral: true,
|
||||
options: [],
|
||||
};
|
||||
|
||||
export const secondBuildOption: RichParameter = {
|
||||
@@ -161,4 +163,5 @@ export const secondBuildOption: RichParameter = {
|
||||
defaultValue: "false",
|
||||
mutable: true,
|
||||
ephemeral: true,
|
||||
options: [],
|
||||
};
|
||||
|
||||
Generated
+19
@@ -5,6 +5,21 @@ import { Timestamp } from "./google/protobuf/timestampGenerated";
|
||||
|
||||
export const protobufPackage = "provisioner";
|
||||
|
||||
export enum ParameterFormType {
|
||||
DEFAULT = 0,
|
||||
FORM_ERROR = 1,
|
||||
RADIO = 2,
|
||||
DROPDOWN = 3,
|
||||
INPUT = 4,
|
||||
TEXTAREA = 5,
|
||||
SLIDER = 6,
|
||||
CHECKBOX = 7,
|
||||
SWITCH = 8,
|
||||
TAGSELECT = 9,
|
||||
MULTISELECT = 10,
|
||||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
/** LogLevel represents severity of the log. */
|
||||
export enum LogLevel {
|
||||
TRACE = 0,
|
||||
@@ -96,6 +111,7 @@ export interface RichParameter {
|
||||
displayName: string;
|
||||
order: number;
|
||||
ephemeral: boolean;
|
||||
formType: ParameterFormType;
|
||||
}
|
||||
|
||||
/** RichParameterValue holds the key/value mapping of a parameter. */
|
||||
@@ -539,6 +555,9 @@ export const RichParameter = {
|
||||
if (message.ephemeral === true) {
|
||||
writer.uint32(136).bool(message.ephemeral);
|
||||
}
|
||||
if (message.formType !== 0) {
|
||||
writer.uint32(144).int32(message.formType);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
};
|
||||
|
||||
Generated
+1
@@ -2819,6 +2819,7 @@ export interface TemplateVersionParameter {
|
||||
readonly description: string;
|
||||
readonly description_plaintext: string;
|
||||
readonly type: string;
|
||||
readonly form_type: string;
|
||||
readonly mutable: boolean;
|
||||
readonly default_value: string;
|
||||
readonly icon: string;
|
||||
|
||||
@@ -19,6 +19,7 @@ const createTemplateVersionParameter = (
|
||||
name: "first_parameter",
|
||||
description: "This is first parameter.",
|
||||
type: "string",
|
||||
form_type: "input",
|
||||
mutable: true,
|
||||
default_value: "default string",
|
||||
icon: "/icon/folder.svg",
|
||||
|
||||
@@ -94,6 +94,7 @@ export const TemplateVersionParameters: Story = {
|
||||
description: "Select the deployment region.",
|
||||
description_plaintext: "Select the deployment region.",
|
||||
type: "string",
|
||||
form_type: "radio",
|
||||
mutable: false,
|
||||
default_value: "us-west-1",
|
||||
icon: "",
|
||||
@@ -110,6 +111,7 @@ export const TemplateVersionParameters: Story = {
|
||||
description: "Number of CPU cores.",
|
||||
description_plaintext: "Number of CPU cores.",
|
||||
type: "number",
|
||||
form_type: "input",
|
||||
mutable: true,
|
||||
default_value: "4",
|
||||
icon: "",
|
||||
|
||||
@@ -77,6 +77,7 @@ export const Parameters: Story = {
|
||||
description: "",
|
||||
description_plaintext: "",
|
||||
type: "string",
|
||||
form_type: "radio",
|
||||
mutable: false,
|
||||
default_value: "",
|
||||
icon: "/emojis/1f30e.png",
|
||||
|
||||
@@ -1604,6 +1604,7 @@ export const MockTemplateVersionParameter1: TypesGen.TemplateVersionParameter =
|
||||
{
|
||||
name: "first_parameter",
|
||||
type: "string",
|
||||
form_type: "input",
|
||||
description: "This is first parameter",
|
||||
description_plaintext: "Markdown: This is first parameter",
|
||||
default_value: "abc",
|
||||
@@ -1618,6 +1619,7 @@ export const MockTemplateVersionParameter2: TypesGen.TemplateVersionParameter =
|
||||
{
|
||||
name: "second_parameter",
|
||||
type: "number",
|
||||
form_type: "input",
|
||||
description: "This is second parameter",
|
||||
description_plaintext: "Markdown: This is second parameter",
|
||||
default_value: "2",
|
||||
@@ -1635,6 +1637,7 @@ export const MockTemplateVersionParameter3: TypesGen.TemplateVersionParameter =
|
||||
{
|
||||
name: "third_parameter",
|
||||
type: "string",
|
||||
form_type: "input",
|
||||
description: "This is third parameter",
|
||||
description_plaintext: "Markdown: This is third parameter",
|
||||
default_value: "aaa",
|
||||
@@ -1651,6 +1654,7 @@ export const MockTemplateVersionParameter4: TypesGen.TemplateVersionParameter =
|
||||
{
|
||||
name: "fourth_parameter",
|
||||
type: "string",
|
||||
form_type: "input",
|
||||
description: "This is fourth parameter",
|
||||
description_plaintext: "Markdown: This is fourth parameter",
|
||||
default_value: "def",
|
||||
@@ -1664,6 +1668,7 @@ export const MockTemplateVersionParameter4: TypesGen.TemplateVersionParameter =
|
||||
const MockTemplateVersionParameter5: TypesGen.TemplateVersionParameter = {
|
||||
name: "fifth_parameter",
|
||||
type: "number",
|
||||
form_type: "input",
|
||||
description: "This is fifth parameter",
|
||||
description_plaintext: "Markdown: This is fifth parameter",
|
||||
default_value: "5",
|
||||
|
||||
@@ -9,6 +9,7 @@ test("getInitialRichParameterValues return default value when default build para
|
||||
description: "The number of CPU cores",
|
||||
description_plaintext: "The number of CPU cores",
|
||||
type: "string",
|
||||
form_type: "radio",
|
||||
mutable: true,
|
||||
default_value: "2",
|
||||
icon: "/icon/memory.svg",
|
||||
|
||||
Reference in New Issue
Block a user