diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 16a51d187a486..07a0407c0014d 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5897,10 +5897,37 @@ const docTemplate = `{ "type": "string", "format": "uuid", "description": "Template version ID", - "name": "user", + "name": "templateversion", "in": "path", "required": true - }, + } + ], + "responses": { + "101": { + "description": "Switching Protocols" + } + } + } + }, + "/templateversions/{templateversion}/dynamic-parameters/evaluate": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Templates" + ], + "summary": "Evaluate dynamic parameters for template version", + "operationId": "evaluate-dynamic-parameters-for-template-version", + "parameters": [ { "type": "string", "format": "uuid", @@ -5908,11 +5935,23 @@ const docTemplate = `{ "name": "templateversion", "in": "path", "required": true + }, + { + "description": "Initial parameter values", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.DynamicParametersRequest" + } } ], "responses": { - "101": { - "description": "Switching Protocols" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.DynamicParametersResponse" + } } } } @@ -12573,6 +12612,25 @@ const docTemplate = `{ } } }, + "codersdk.DiagnosticExtra": { + "type": "object", + "properties": { + "code": { + "type": "string" + } + } + }, + "codersdk.DiagnosticSeverityString": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "x-enum-varnames": [ + "DiagnosticSeverityError", + "DiagnosticSeverityWarning" + ] + }, "codersdk.DisplayApp": { "type": "string", "enum": [ @@ -12590,6 +12648,46 @@ const docTemplate = `{ "DisplayAppSSH" ] }, + "codersdk.DynamicParametersRequest": { + "type": "object", + "properties": { + "id": { + "description": "ID identifies the request. The response contains the same\nID so that the client can match it to the request.", + "type": "integer" + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "owner_id": { + "description": "OwnerID if uuid.Nil, it defaults to ` + "`" + `codersdk.Me` + "`" + `", + "type": "string", + "format": "uuid" + } + } + }, + "codersdk.DynamicParametersResponse": { + "type": "object", + "properties": { + "diagnostics": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.FriendlyDiagnostic" + } + }, + "id": { + "type": "integer" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameter" + } + } + } + }, "codersdk.Entitlement": { "type": "string", "enum": [ @@ -12870,6 +12968,23 @@ const docTemplate = `{ } } }, + "codersdk.FriendlyDiagnostic": { + "type": "object", + "properties": { + "detail": { + "type": "string" + }, + "extra": { + "$ref": "#/definitions/codersdk.DiagnosticExtra" + }, + "severity": { + "$ref": "#/definitions/codersdk.DiagnosticSeverityString" + }, + "summary": { + "type": "string" + } + } + }, "codersdk.GenerateAPIKeyResponse": { "type": "object", "properties": { @@ -13661,6 +13776,17 @@ const docTemplate = `{ } } }, + "codersdk.NullHCLString": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "string" + } + } + }, "codersdk.OAuth2AppEndpoints": { "type": "object", "properties": { @@ -13918,6 +14044,21 @@ const docTemplate = `{ } } }, + "codersdk.OptionType": { + "type": "string", + "enum": [ + "string", + "number", + "bool", + "list(string)" + ], + "x-enum-varnames": [ + "OptionTypeString", + "OptionTypeNumber", + "OptionTypeBoolean", + "OptionTypeListString" + ] + }, "codersdk.Organization": { "type": "object", "required": [ @@ -14065,6 +14206,35 @@ const docTemplate = `{ } } }, + "codersdk.ParameterFormType": { + "type": "string", + "enum": [ + "", + "radio", + "slider", + "input", + "dropdown", + "checkbox", + "switch", + "multi-select", + "tag-select", + "textarea", + "error" + ], + "x-enum-varnames": [ + "ParameterFormTypeDefault", + "ParameterFormTypeRadio", + "ParameterFormTypeSlider", + "ParameterFormTypeInput", + "ParameterFormTypeDropdown", + "ParameterFormTypeCheckbox", + "ParameterFormTypeSwitch", + "ParameterFormTypeMultiSelect", + "ParameterFormTypeTagSelect", + "ParameterFormTypeTextArea", + "ParameterFormTypeError" + ] + }, "codersdk.PatchGroupIDPSyncConfigRequest": { "type": "object", "properties": { @@ -14381,6 +14551,121 @@ const docTemplate = `{ } } }, + "codersdk.PreviewParameter": { + "type": "object", + "properties": { + "default_value": { + "$ref": "#/definitions/codersdk.NullHCLString" + }, + "description": { + "type": "string" + }, + "diagnostics": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.FriendlyDiagnostic" + } + }, + "display_name": { + "type": "string" + }, + "ephemeral": { + "type": "boolean" + }, + "form_type": { + "$ref": "#/definitions/codersdk.ParameterFormType" + }, + "icon": { + "type": "string" + }, + "mutable": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameterOption" + } + }, + "order": { + "description": "legacy_variable_name was removed (= 14)", + "type": "integer" + }, + "required": { + "type": "boolean" + }, + "styling": { + "$ref": "#/definitions/codersdk.PreviewParameterStyling" + }, + "type": { + "$ref": "#/definitions/codersdk.OptionType" + }, + "validations": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameterValidation" + } + }, + "value": { + "$ref": "#/definitions/codersdk.NullHCLString" + } + } + }, + "codersdk.PreviewParameterOption": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/codersdk.NullHCLString" + } + } + }, + "codersdk.PreviewParameterStyling": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "placeholder": { + "type": "string" + } + } + }, + "codersdk.PreviewParameterValidation": { + "type": "object", + "properties": { + "validation_error": { + "type": "string" + }, + "validation_max": { + "type": "integer" + }, + "validation_min": { + "type": "integer" + }, + "validation_monotonic": { + "type": "string" + }, + "validation_regex": { + "description": "All validation attributes are optional.", + "type": "string" + } + } + }, "codersdk.PrometheusConfig": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 986862df59a09..076f170d27e72 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -5212,10 +5212,31 @@ "type": "string", "format": "uuid", "description": "Template version ID", - "name": "user", + "name": "templateversion", "in": "path", "required": true - }, + } + ], + "responses": { + "101": { + "description": "Switching Protocols" + } + } + } + }, + "/templateversions/{templateversion}/dynamic-parameters/evaluate": { + "post": { + "security": [ + { + "CoderSessionToken": [] + } + ], + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["Templates"], + "summary": "Evaluate dynamic parameters for template version", + "operationId": "evaluate-dynamic-parameters-for-template-version", + "parameters": [ { "type": "string", "format": "uuid", @@ -5223,11 +5244,23 @@ "name": "templateversion", "in": "path", "required": true + }, + { + "description": "Initial parameter values", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/codersdk.DynamicParametersRequest" + } } ], "responses": { - "101": { - "description": "Switching Protocols" + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/codersdk.DynamicParametersResponse" + } } } } @@ -11279,6 +11312,22 @@ } } }, + "codersdk.DiagnosticExtra": { + "type": "object", + "properties": { + "code": { + "type": "string" + } + } + }, + "codersdk.DiagnosticSeverityString": { + "type": "string", + "enum": ["error", "warning"], + "x-enum-varnames": [ + "DiagnosticSeverityError", + "DiagnosticSeverityWarning" + ] + }, "codersdk.DisplayApp": { "type": "string", "enum": [ @@ -11296,6 +11345,46 @@ "DisplayAppSSH" ] }, + "codersdk.DynamicParametersRequest": { + "type": "object", + "properties": { + "id": { + "description": "ID identifies the request. The response contains the same\nID so that the client can match it to the request.", + "type": "integer" + }, + "inputs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "owner_id": { + "description": "OwnerID if uuid.Nil, it defaults to `codersdk.Me`", + "type": "string", + "format": "uuid" + } + } + }, + "codersdk.DynamicParametersResponse": { + "type": "object", + "properties": { + "diagnostics": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.FriendlyDiagnostic" + } + }, + "id": { + "type": "integer" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameter" + } + } + } + }, "codersdk.Entitlement": { "type": "string", "enum": ["entitled", "grace_period", "not_entitled"], @@ -11572,6 +11661,23 @@ } } }, + "codersdk.FriendlyDiagnostic": { + "type": "object", + "properties": { + "detail": { + "type": "string" + }, + "extra": { + "$ref": "#/definitions/codersdk.DiagnosticExtra" + }, + "severity": { + "$ref": "#/definitions/codersdk.DiagnosticSeverityString" + }, + "summary": { + "type": "string" + } + } + }, "codersdk.GenerateAPIKeyResponse": { "type": "object", "properties": { @@ -12314,6 +12420,17 @@ } } }, + "codersdk.NullHCLString": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "string" + } + } + }, "codersdk.OAuth2AppEndpoints": { "type": "object", "properties": { @@ -12571,6 +12688,16 @@ } } }, + "codersdk.OptionType": { + "type": "string", + "enum": ["string", "number", "bool", "list(string)"], + "x-enum-varnames": [ + "OptionTypeString", + "OptionTypeNumber", + "OptionTypeBoolean", + "OptionTypeListString" + ] + }, "codersdk.Organization": { "type": "object", "required": ["created_at", "id", "is_default", "updated_at"], @@ -12713,6 +12840,35 @@ } } }, + "codersdk.ParameterFormType": { + "type": "string", + "enum": [ + "", + "radio", + "slider", + "input", + "dropdown", + "checkbox", + "switch", + "multi-select", + "tag-select", + "textarea", + "error" + ], + "x-enum-varnames": [ + "ParameterFormTypeDefault", + "ParameterFormTypeRadio", + "ParameterFormTypeSlider", + "ParameterFormTypeInput", + "ParameterFormTypeDropdown", + "ParameterFormTypeCheckbox", + "ParameterFormTypeSwitch", + "ParameterFormTypeMultiSelect", + "ParameterFormTypeTagSelect", + "ParameterFormTypeTextArea", + "ParameterFormTypeError" + ] + }, "codersdk.PatchGroupIDPSyncConfigRequest": { "type": "object", "properties": { @@ -13021,6 +13177,121 @@ } } }, + "codersdk.PreviewParameter": { + "type": "object", + "properties": { + "default_value": { + "$ref": "#/definitions/codersdk.NullHCLString" + }, + "description": { + "type": "string" + }, + "diagnostics": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.FriendlyDiagnostic" + } + }, + "display_name": { + "type": "string" + }, + "ephemeral": { + "type": "boolean" + }, + "form_type": { + "$ref": "#/definitions/codersdk.ParameterFormType" + }, + "icon": { + "type": "string" + }, + "mutable": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameterOption" + } + }, + "order": { + "description": "legacy_variable_name was removed (= 14)", + "type": "integer" + }, + "required": { + "type": "boolean" + }, + "styling": { + "$ref": "#/definitions/codersdk.PreviewParameterStyling" + }, + "type": { + "$ref": "#/definitions/codersdk.OptionType" + }, + "validations": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.PreviewParameterValidation" + } + }, + "value": { + "$ref": "#/definitions/codersdk.NullHCLString" + } + } + }, + "codersdk.PreviewParameterOption": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/codersdk.NullHCLString" + } + } + }, + "codersdk.PreviewParameterStyling": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "placeholder": { + "type": "string" + } + } + }, + "codersdk.PreviewParameterValidation": { + "type": "object", + "properties": { + "validation_error": { + "type": "string" + }, + "validation_max": { + "type": "integer" + }, + "validation_min": { + "type": "integer" + }, + "validation_monotonic": { + "type": "string" + }, + "validation_regex": { + "description": "All validation attributes are optional.", + "type": "string" + } + } + }, "codersdk.PrometheusConfig": { "type": "object", "properties": { diff --git a/coderd/coderd.go b/coderd/coderd.go index 69d942304acea..0b8a13befde56 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1156,7 +1156,10 @@ func New(options *Options) *API { r.Use( httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentDynamicParameters), ) - r.Get("/dynamic-parameters", api.templateVersionDynamicParameters) + r.Route("/dynamic-parameters", func(r chi.Router) { + r.Post("/evaluate", api.templateVersionDynamicParametersEvaluate) + r.Get("/", api.templateVersionDynamicParametersWebsocket) + }) }) }) r.Route("/users", func(r chi.Router) { diff --git a/coderd/parameters.go b/coderd/parameters.go index d1e989c8ad032..d8551b2031f7a 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -29,57 +29,89 @@ import ( "github.com/coder/websocket" ) +// @Summary Evaluate dynamic parameters for template version +// @ID evaluate-dynamic-parameters-for-template-version +// @Security CoderSessionToken +// @Tags Templates +// @Param templateversion path string true "Template version ID" format(uuid) +// @Accept json +// @Produce json +// @Param request body codersdk.DynamicParametersRequest true "Initial parameter values" +// @Success 200 {object} codersdk.DynamicParametersResponse +// @Router /templateversions/{templateversion}/dynamic-parameters/evaluate [post] +func (api *API) templateVersionDynamicParametersEvaluate(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var req codersdk.DynamicParametersRequest + if !httpapi.Read(ctx, rw, r, &req) { + return + } + + api.templateVersionDynamicParameters(false, req)(rw, r) +} + // @Summary Open dynamic parameters WebSocket by template version // @ID open-dynamic-parameters-websocket-by-template-version // @Security CoderSessionToken // @Tags Templates -// @Param user path string true "Template version ID" format(uuid) // @Param templateversion path string true "Template version ID" format(uuid) // @Success 101 // @Router /templateversions/{templateversion}/dynamic-parameters [get] -func (api *API) templateVersionDynamicParameters(rw http.ResponseWriter, r *http.Request) { - ctx := r.Context() - templateVersion := httpmw.TemplateVersionParam(r) +func (api *API) templateVersionDynamicParametersWebsocket(rw http.ResponseWriter, r *http.Request) { + apikey := httpmw.APIKey(r) + + api.templateVersionDynamicParameters(true, codersdk.DynamicParametersRequest{ + ID: -1, + Inputs: map[string]string{}, + OwnerID: apikey.UserID, + })(rw, r) +} - // Check that the job has completed successfully - job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) - if httpapi.Is404Error(err) { - httpapi.ResourceNotFound(rw) - return - } - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching provisioner job.", - Detail: err.Error(), - }) - return - } - if !job.CompletedAt.Valid { - httpapi.Write(ctx, rw, http.StatusTooEarly, codersdk.Response{ - Message: "Template version job has not finished", - }) - return - } +func (api *API) templateVersionDynamicParameters(listen bool, initial codersdk.DynamicParametersRequest) func(rw http.ResponseWriter, r *http.Request) { + return func(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + templateVersion := httpmw.TemplateVersionParam(r) - tf, err := api.Database.GetTemplateVersionTerraformValues(ctx, templateVersion.ID) - if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to retrieve Terraform values for template version", - Detail: err.Error(), - }) - return - } + // Check that the job has completed successfully + job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) + if httpapi.Is404Error(err) { + httpapi.ResourceNotFound(rw) + return + } + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching provisioner job.", + Detail: err.Error(), + }) + return + } + if !job.CompletedAt.Valid { + httpapi.Write(ctx, rw, http.StatusTooEarly, codersdk.Response{ + Message: "Template version job has not finished", + }) + return + } - if wsbuilder.ProvisionerVersionSupportsDynamicParameters(tf.ProvisionerdVersion) { - api.handleDynamicParameters(rw, r, tf, templateVersion) - } else { - api.handleStaticParameters(rw, r, templateVersion.ID) + tf, err := api.Database.GetTemplateVersionTerraformValues(ctx, templateVersion.ID) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Failed to retrieve Terraform values for template version", + Detail: err.Error(), + }) + return + } + + if wsbuilder.ProvisionerVersionSupportsDynamicParameters(tf.ProvisionerdVersion) { + api.handleDynamicParameters(listen, rw, r, tf, templateVersion, initial) + } else { + api.handleStaticParameters(listen, rw, r, templateVersion.ID, initial) + } } } type previewFunction func(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) -func (api *API) handleDynamicParameters(rw http.ResponseWriter, r *http.Request, tf database.TemplateVersionTerraformValue, templateVersion database.TemplateVersion) { +// nolint:revive +func (api *API) handleDynamicParameters(listen bool, rw http.ResponseWriter, r *http.Request, tf database.TemplateVersionTerraformValue, templateVersion database.TemplateVersion, initial codersdk.DynamicParametersRequest) { var ( ctx = r.Context() apikey = httpmw.APIKey(r) @@ -159,7 +191,7 @@ func (api *API) handleDynamicParameters(rw http.ResponseWriter, r *http.Request, }, } - api.handleParameterWebsocket(rw, r, apikey.UserID, func(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { + dynamicRender := func(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { if ownerID == uuid.Nil { // Default to the authenticated user // Nice for testing @@ -186,10 +218,16 @@ func (api *API) handleDynamicParameters(rw http.ResponseWriter, r *http.Request, } return preview.Preview(ctx, input, templateFS) - }) + } + if listen { + api.handleParameterWebsocket(rw, r, initial, dynamicRender) + } else { + api.handleParameterEvaluate(rw, r, initial, dynamicRender) + } } -func (api *API) handleStaticParameters(rw http.ResponseWriter, r *http.Request, version uuid.UUID) { +// nolint:revive +func (api *API) handleStaticParameters(listen bool, rw http.ResponseWriter, r *http.Request, version uuid.UUID, initial codersdk.DynamicParametersRequest) { ctx := r.Context() dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, version) if err != nil { @@ -275,7 +313,7 @@ func (api *API) handleStaticParameters(rw http.ResponseWriter, r *http.Request, params = append(params, param) } - api.handleParameterWebsocket(rw, r, uuid.Nil, func(_ context.Context, _ uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { + staticRender := func(_ context.Context, _ uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { for i := range params { param := ¶ms[i] paramValue, ok := values[param.Name] @@ -297,10 +335,31 @@ func (api *API) handleStaticParameters(rw http.ResponseWriter, r *http.Request, Detail: "To restore full functionality, please re-import the terraform as a new template version.", }, } - }) + } + if listen { + api.handleParameterWebsocket(rw, r, initial, staticRender) + } else { + api.handleParameterEvaluate(rw, r, initial, staticRender) + } +} + +func (*API) handleParameterEvaluate(rw http.ResponseWriter, r *http.Request, initial codersdk.DynamicParametersRequest, render previewFunction) { + ctx := r.Context() + + // Send an initial form state, computed without any user input. + result, diagnostics := render(ctx, initial.OwnerID, initial.Inputs) + response := codersdk.DynamicParametersResponse{ + ID: 0, + Diagnostics: db2sdk.HCLDiagnostics(diagnostics), + } + if result != nil { + response.Parameters = db2sdk.List(result.Parameters, db2sdk.PreviewParameter) + } + + httpapi.Write(ctx, rw, http.StatusOK, response) } -func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request, ownerID uuid.UUID, render previewFunction) { +func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request, initial codersdk.DynamicParametersRequest, render previewFunction) { ctx, cancel := context.WithTimeout(r.Context(), 30*time.Minute) defer cancel() @@ -320,7 +379,7 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request ) // Send an initial form state, computed without any user input. - result, diagnostics := render(ctx, ownerID, map[string]string{}) + result, diagnostics := render(ctx, initial.OwnerID, initial.Inputs) response := codersdk.DynamicParametersResponse{ ID: -1, // Always start with -1. Diagnostics: db2sdk.HCLDiagnostics(diagnostics), diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index f8e2152f629be..6b0f8254a720c 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -3281,6 +3281,35 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | `workspace_prebuilds` | [codersdk.PrebuildsConfig](#codersdkprebuildsconfig) | false | | | | `write_config` | boolean | false | | | +## codersdk.DiagnosticExtra + +```json +{ + "code": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------|--------|----------|--------------|-------------| +| `code` | string | false | | | + +## codersdk.DiagnosticSeverityString + +```json +"error" +``` + +### Properties + +#### Enumerated Values + +| Value | +|-----------| +| `error` | +| `warning` | + ## codersdk.DisplayApp ```json @@ -3299,6 +3328,111 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o | `port_forwarding_helper` | | `ssh_helper` | +## codersdk.DynamicParametersRequest + +```json +{ + "id": 0, + "inputs": { + "property1": "string", + "property2": "string" + }, + "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|--------------------|---------|----------|--------------|--------------------------------------------------------------------------------------------------------------| +| `id` | integer | false | | ID identifies the request. The response contains the same ID so that the client can match it to the request. | +| `inputs` | object | false | | | +| ยป `[any property]` | string | false | | | +| `owner_id` | string | false | | Owner ID if uuid.Nil, it defaults to `codersdk.Me` | + +## codersdk.DynamicParametersResponse + +```json +{ + "diagnostics": [ + { + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" + } + ], + "id": 0, + "parameters": [ + { + "default_value": { + "valid": true, + "value": "string" + }, + "description": "string", + "diagnostics": [ + { + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" + } + ], + "display_name": "string", + "ephemeral": true, + "form_type": "", + "icon": "string", + "mutable": true, + "name": "string", + "options": [ + { + "description": "string", + "icon": "string", + "name": "string", + "value": { + "valid": true, + "value": "string" + } + } + ], + "order": 0, + "required": true, + "styling": { + "disabled": true, + "label": "string", + "placeholder": "string" + }, + "type": "string", + "validations": [ + { + "validation_error": "string", + "validation_max": 0, + "validation_min": 0, + "validation_monotonic": "string", + "validation_regex": "string" + } + ], + "value": { + "valid": true, + "value": "string" + } + } + ] +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|---------------|---------------------------------------------------------------------|----------|--------------|-------------| +| `diagnostics` | array of [codersdk.FriendlyDiagnostic](#codersdkfriendlydiagnostic) | false | | | +| `id` | integer | false | | | +| `parameters` | array of [codersdk.PreviewParameter](#codersdkpreviewparameter) | false | | | + ## codersdk.Entitlement ```json @@ -3584,6 +3718,28 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith | `entitlement` | [codersdk.Entitlement](#codersdkentitlement) | false | | | | `limit` | integer | false | | | +## codersdk.FriendlyDiagnostic + +```json +{ + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|------------|------------------------------------------------------------------------|----------|--------------|-------------| +| `detail` | string | false | | | +| `extra` | [codersdk.DiagnosticExtra](#codersdkdiagnosticextra) | false | | | +| `severity` | [codersdk.DiagnosticSeverityString](#codersdkdiagnosticseveritystring) | false | | | +| `summary` | string | false | | | + ## codersdk.GenerateAPIKeyResponse ```json @@ -4548,6 +4704,22 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith |------------|----------------------------|----------|--------------|----------------------------------------------------------------------| | `endpoint` | [serpent.URL](#serpenturl) | false | | The URL to which the payload will be sent with an HTTP POST request. | +## codersdk.NullHCLString + +```json +{ + "valid": true, + "value": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|---------|---------|----------|--------------|-------------| +| `valid` | boolean | false | | | +| `value` | string | false | | | + ## codersdk.OAuth2AppEndpoints ```json @@ -4818,6 +4990,23 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith | `user_roles_default` | array of string | false | | | | `username_field` | string | false | | | +## codersdk.OptionType + +```json +"string" +``` + +### Properties + +#### Enumerated Values + +| Value | +|----------------| +| `string` | +| `number` | +| `bool` | +| `list(string)` | + ## codersdk.Organization ```json @@ -4985,6 +5174,30 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith | `count` | integer | false | | | | `members` | array of [codersdk.OrganizationMemberWithUserData](#codersdkorganizationmemberwithuserdata) | false | | | +## codersdk.ParameterFormType + +```json +"" +``` + +### Properties + +#### Enumerated Values + +| Value | +|----------------| +| `` | +| `radio` | +| `slider` | +| `input` | +| `dropdown` | +| `checkbox` | +| `switch` | +| `multi-select` | +| `tag-select` | +| `textarea` | +| `error` | + ## codersdk.PatchGroupIDPSyncConfigRequest ```json @@ -5319,6 +5532,150 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith | `name` | string | false | | | | `value` | string | false | | | +## codersdk.PreviewParameter + +```json +{ + "default_value": { + "valid": true, + "value": "string" + }, + "description": "string", + "diagnostics": [ + { + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" + } + ], + "display_name": "string", + "ephemeral": true, + "form_type": "", + "icon": "string", + "mutable": true, + "name": "string", + "options": [ + { + "description": "string", + "icon": "string", + "name": "string", + "value": { + "valid": true, + "value": "string" + } + } + ], + "order": 0, + "required": true, + "styling": { + "disabled": true, + "label": "string", + "placeholder": "string" + }, + "type": "string", + "validations": [ + { + "validation_error": "string", + "validation_max": 0, + "validation_min": 0, + "validation_monotonic": "string", + "validation_regex": "string" + } + ], + "value": { + "valid": true, + "value": "string" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|-----------------|-------------------------------------------------------------------------------------|----------|--------------|-----------------------------------------| +| `default_value` | [codersdk.NullHCLString](#codersdknullhclstring) | false | | | +| `description` | string | false | | | +| `diagnostics` | array of [codersdk.FriendlyDiagnostic](#codersdkfriendlydiagnostic) | false | | | +| `display_name` | string | false | | | +| `ephemeral` | boolean | false | | | +| `form_type` | [codersdk.ParameterFormType](#codersdkparameterformtype) | false | | | +| `icon` | string | false | | | +| `mutable` | boolean | false | | | +| `name` | string | false | | | +| `options` | array of [codersdk.PreviewParameterOption](#codersdkpreviewparameteroption) | false | | | +| `order` | integer | false | | legacy_variable_name was removed (= 14) | +| `required` | boolean | false | | | +| `styling` | [codersdk.PreviewParameterStyling](#codersdkpreviewparameterstyling) | false | | | +| `type` | [codersdk.OptionType](#codersdkoptiontype) | false | | | +| `validations` | array of [codersdk.PreviewParameterValidation](#codersdkpreviewparametervalidation) | false | | | +| `value` | [codersdk.NullHCLString](#codersdknullhclstring) | false | | | + +## codersdk.PreviewParameterOption + +```json +{ + "description": "string", + "icon": "string", + "name": "string", + "value": { + "valid": true, + "value": "string" + } +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|---------------|--------------------------------------------------|----------|--------------|-------------| +| `description` | string | false | | | +| `icon` | string | false | | | +| `name` | string | false | | | +| `value` | [codersdk.NullHCLString](#codersdknullhclstring) | false | | | + +## codersdk.PreviewParameterStyling + +```json +{ + "disabled": true, + "label": "string", + "placeholder": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|---------------|---------|----------|--------------|-------------| +| `disabled` | boolean | false | | | +| `label` | string | false | | | +| `placeholder` | string | false | | | + +## codersdk.PreviewParameterValidation + +```json +{ + "validation_error": "string", + "validation_max": 0, + "validation_min": 0, + "validation_monotonic": "string", + "validation_regex": "string" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|------------------------|---------|----------|--------------|-----------------------------------------| +| `validation_error` | string | false | | | +| `validation_max` | integer | false | | | +| `validation_min` | integer | false | | | +| `validation_monotonic` | string | false | | | +| `validation_regex` | string | false | | All validation attributes are optional. | + ## codersdk.PrometheusConfig ```json diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index 6075af775c9bc..b1957873a1be6 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -2593,7 +2593,6 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d | Name | In | Type | Required | Description | |-------------------|------|--------------|----------|---------------------| -| `user` | path | string(uuid) | true | Template version ID | | `templateversion` | path | string(uuid) | true | Template version ID | ### Responses @@ -2604,6 +2603,125 @@ curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/d To perform this operation, you must be authenticated. [Learn more](authentication.md). +## Evaluate dynamic parameters for template version + +### Code samples + +```shell +# Example request using curl +curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/dynamic-parameters/evaluate \ + -H 'Content-Type: application/json' \ + -H 'Accept: application/json' \ + -H 'Coder-Session-Token: API_KEY' +``` + +`POST /templateversions/{templateversion}/dynamic-parameters/evaluate` + +> Body parameter + +```json +{ + "id": 0, + "inputs": { + "property1": "string", + "property2": "string" + }, + "owner_id": "8826ee2e-7933-4665-aef2-2393f84a0d05" +} +``` + +### Parameters + +| Name | In | Type | Required | Description | +|-------------------|------|----------------------------------------------------------------------------------|----------|--------------------------| +| `templateversion` | path | string(uuid) | true | Template version ID | +| `body` | body | [codersdk.DynamicParametersRequest](schemas.md#codersdkdynamicparametersrequest) | true | Initial parameter values | + +### Example responses + +> 200 Response + +```json +{ + "diagnostics": [ + { + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" + } + ], + "id": 0, + "parameters": [ + { + "default_value": { + "valid": true, + "value": "string" + }, + "description": "string", + "diagnostics": [ + { + "detail": "string", + "extra": { + "code": "string" + }, + "severity": "error", + "summary": "string" + } + ], + "display_name": "string", + "ephemeral": true, + "form_type": "", + "icon": "string", + "mutable": true, + "name": "string", + "options": [ + { + "description": "string", + "icon": "string", + "name": "string", + "value": { + "valid": true, + "value": "string" + } + } + ], + "order": 0, + "required": true, + "styling": { + "disabled": true, + "label": "string", + "placeholder": "string" + }, + "type": "string", + "validations": [ + { + "validation_error": "string", + "validation_max": 0, + "validation_min": 0, + "validation_monotonic": "string", + "validation_regex": "string" + } + ], + "value": { + "valid": true, + "value": "string" + } + } + ] +} +``` + +### Responses + +| Status | Meaning | Description | Schema | +|--------|---------------------------------------------------------|-------------|------------------------------------------------------------------------------------| +| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.DynamicParametersResponse](schemas.md#codersdkdynamicparametersresponse) | + +To perform this operation, you must be authenticated. [Learn more](authentication.md). + ## Get external auth by template version ### Code samples