diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 8d7920c2d2..61a6989ba2 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -9585,6 +9585,9 @@ const docTemplate = `{ "codersdk.TemplateParameterUsage": { "type": "object", "properties": { + "description": { + "type": "string" + }, "display_name": { "type": "string" }, @@ -9604,6 +9607,9 @@ const docTemplate = `{ "format": "uuid" } }, + "type": { + "type": "string" + }, "values": { "type": "array", "items": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index bc4c0e7b8a..982ed81626 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -8665,6 +8665,9 @@ "codersdk.TemplateParameterUsage": { "type": "object", "properties": { + "description": { + "type": "string" + }, "display_name": { "type": "string" }, @@ -8684,6 +8687,9 @@ "format": "uuid" } }, + "type": { + "type": "string" + }, "values": { "type": "array", "items": { diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index 263611d5b1..893cfdadea 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -3,6 +3,7 @@ package db2sdk import ( "encoding/json" + "sort" "github.com/google/uuid" @@ -29,20 +30,10 @@ func WorkspaceBuildParameter(p database.WorkspaceBuildParameter) codersdk.Worksp } func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) { - var protoOptions []*proto.RichParameterOption - err := json.Unmarshal(param.Options, &protoOptions) + options, err := templateVersionParameterOptions(param.Options) 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 := parameter.Plaintext(param.Description) if err != nil { @@ -132,3 +123,61 @@ func Role(role rbac.Role) codersdk.Role { Name: role.Name, } } + +func TemplateInsightsParameters(parameterRows []database.GetTemplateParameterInsightsRow) ([]codersdk.TemplateParameterUsage, error) { + parametersByNum := make(map[int64]*codersdk.TemplateParameterUsage) + for _, param := range parameterRows { + if _, ok := parametersByNum[param.Num]; !ok { + var opts []codersdk.TemplateVersionParameterOption + err := json.Unmarshal(param.Options, &opts) + if err != nil { + return nil, err + } + + plaintextDescription, err := parameter.Plaintext(param.Description) + if err != nil { + return nil, err + } + + parametersByNum[param.Num] = &codersdk.TemplateParameterUsage{ + TemplateIDs: param.TemplateIDs, + Name: param.Name, + Type: param.Type, + DisplayName: param.DisplayName, + Description: plaintextDescription, + Options: opts, + } + } + parametersByNum[param.Num].Values = append(parametersByNum[param.Num].Values, codersdk.TemplateParameterValue{ + Value: param.Value, + Count: param.Count, + }) + } + parametersUsage := []codersdk.TemplateParameterUsage{} + for _, param := range parametersByNum { + parametersUsage = append(parametersUsage, *param) + } + + sort.Slice(parametersUsage, func(i, j int) bool { + return parametersUsage[i].Name < parametersUsage[j].Name + }) + return parametersUsage, nil +} + +func templateVersionParameterOptions(rawOptions json.RawMessage) ([]codersdk.TemplateVersionParameterOption, error) { + var protoOptions []*proto.RichParameterOption + err := json.Unmarshal(rawOptions, &protoOptions) + if err != nil { + return nil, err + } + var options []codersdk.TemplateVersionParameterOption + for _, option := range protoOptions { + options = append(options, codersdk.TemplateVersionParameterOption{ + Name: option.Name, + Description: option.Description, + Value: option.Value, + Icon: option.Icon, + }) + } + return options, nil +} diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index cc0d05aaee..c968a52f8d 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -2186,6 +2186,7 @@ func (q *FakeQuerier) GetTemplateParameterInsights(ctx context.Context, arg data uniqueTemplateParams[key] = &database.GetTemplateParameterInsightsRow{ Num: num, Name: tvp.Name, + Type: tvp.Type, DisplayName: tvp.DisplayName, Description: tvp.Description, Options: tvp.Options, @@ -2220,6 +2221,7 @@ func (q *FakeQuerier) GetTemplateParameterInsights(ctx context.Context, arg data TemplateIDs: uniqueSortedUUIDs(utp.TemplateIDs), Name: utp.Name, DisplayName: utp.DisplayName, + Type: utp.Type, Description: utp.Description, Options: utp.Options, Value: value, diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 3e07fc22f1..8748e4d7ca 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1582,16 +1582,18 @@ WITH latest_workspace_builds AS ( tvp.name, tvp.display_name, tvp.description, - tvp.options + tvp.options, + tvp.type FROM latest_workspace_builds wb JOIN template_version_parameters tvp ON (tvp.template_version_id = wb.template_version_id) - GROUP BY tvp.name, tvp.display_name, tvp.description, tvp.options + GROUP BY tvp.name, tvp.display_name, tvp.description, tvp.options, tvp.type ) SELECT utp.num, utp.template_ids, utp.name, + utp.type, utp.display_name, utp.description, utp.options, @@ -1599,7 +1601,7 @@ SELECT COUNT(wbp.value) AS count FROM unique_template_params utp JOIN workspace_build_parameters wbp ON (utp.workspace_build_ids @> ARRAY[wbp.workspace_build_id] AND utp.name = wbp.name) -GROUP BY utp.num, utp.name, utp.display_name, utp.description, utp.options, utp.template_ids, wbp.value +GROUP BY utp.num, utp.name, utp.display_name, utp.description, utp.options, utp.template_ids, utp.type, wbp.value ` type GetTemplateParameterInsightsParams struct { @@ -1612,6 +1614,7 @@ type GetTemplateParameterInsightsRow struct { Num int64 `db:"num" json:"num"` TemplateIDs []uuid.UUID `db:"template_ids" json:"template_ids"` Name string `db:"name" json:"name"` + Type string `db:"type" json:"type"` DisplayName string `db:"display_name" json:"display_name"` Description string `db:"description" json:"description"` Options json.RawMessage `db:"options" json:"options"` @@ -1636,6 +1639,7 @@ func (q *sqlQuerier) GetTemplateParameterInsights(ctx context.Context, arg GetTe &i.Num, pq.Array(&i.TemplateIDs), &i.Name, + &i.Type, &i.DisplayName, &i.Description, &i.Options, diff --git a/coderd/database/queries/insights.sql b/coderd/database/queries/insights.sql index 94a80117dc..ad8c581161 100644 --- a/coderd/database/queries/insights.sql +++ b/coderd/database/queries/insights.sql @@ -149,16 +149,18 @@ WITH latest_workspace_builds AS ( tvp.name, tvp.display_name, tvp.description, - tvp.options + tvp.options, + tvp.type FROM latest_workspace_builds wb JOIN template_version_parameters tvp ON (tvp.template_version_id = wb.template_version_id) - GROUP BY tvp.name, tvp.display_name, tvp.description, tvp.options + GROUP BY tvp.name, tvp.display_name, tvp.description, tvp.options, tvp.type ) SELECT utp.num, utp.template_ids, utp.name, + utp.type, utp.display_name, utp.description, utp.options, @@ -166,4 +168,4 @@ SELECT COUNT(wbp.value) AS count FROM unique_template_params utp JOIN workspace_build_parameters wbp ON (utp.workspace_build_ids @> ARRAY[wbp.workspace_build_id] AND utp.name = wbp.name) -GROUP BY utp.num, utp.name, utp.display_name, utp.description, utp.options, utp.template_ids, wbp.value; +GROUP BY utp.num, utp.name, utp.display_name, utp.description, utp.options, utp.template_ids, utp.type, wbp.value; diff --git a/coderd/insights.go b/coderd/insights.go index b643303dd0..509e78a18e 100644 --- a/coderd/insights.go +++ b/coderd/insights.go @@ -2,10 +2,8 @@ package coderd import ( "context" - "encoding/json" "fmt" "net/http" - "sort" "time" "github.com/google/uuid" @@ -13,6 +11,7 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/codersdk" @@ -244,7 +243,7 @@ func (api *API) insightsTemplates(rw http.ResponseWriter, r *http.Request) { return } - parametersUsage, err := convertTemplateInsightsParameters(parameterRows) + parametersUsage, err := db2sdk.TemplateInsightsParameters(parameterRows) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error converting template parameter insights.", @@ -315,39 +314,6 @@ func convertTemplateInsightsBuiltinApps(usage database.GetTemplateInsightsRow) [ } } -func convertTemplateInsightsParameters(parameterRows []database.GetTemplateParameterInsightsRow) ([]codersdk.TemplateParameterUsage, error) { - parametersByNum := make(map[int64]*codersdk.TemplateParameterUsage) - for _, param := range parameterRows { - if _, ok := parametersByNum[param.Num]; !ok { - var opts []codersdk.TemplateVersionParameterOption - err := json.Unmarshal(param.Options, &opts) - if err != nil { - return nil, xerrors.Errorf("unmarshal template parameter options: %w", err) - } - parametersByNum[param.Num] = &codersdk.TemplateParameterUsage{ - TemplateIDs: param.TemplateIDs, - Name: param.Name, - DisplayName: param.DisplayName, - Options: opts, - } - } - parametersByNum[param.Num].Values = append(parametersByNum[param.Num].Values, codersdk.TemplateParameterValue{ - Value: param.Value, - Count: param.Count, - }) - } - parametersUsage := []codersdk.TemplateParameterUsage{} - for _, param := range parametersByNum { - parametersUsage = append(parametersUsage, *param) - } - - sort.Slice(parametersUsage, func(i, j int) bool { - return parametersUsage[i].Name < parametersUsage[j].Name - }) - - return parametersUsage, nil -} - // parseInsightsStartAndEndTime parses the start and end time query parameters // and returns the parsed values. The client provided timezone must be preserved // when parsing the time. Verification is performed so that the start and end diff --git a/coderd/insights_test.go b/coderd/insights_test.go index 2469cc0f4b..be75b31f5e 100644 --- a/coderd/insights_test.go +++ b/coderd/insights_test.go @@ -405,6 +405,8 @@ func TestTemplateInsights(t *testing.T) { // The workspace uses 3 parameters require.Len(t, resp.Report.ParametersUsage, 3) assert.Equal(t, firstParameterName, resp.Report.ParametersUsage[0].Name) + assert.Equal(t, firstParameterType, resp.Report.ParametersUsage[0].Type) + assert.Equal(t, firstParameterDescription, resp.Report.ParametersUsage[0].Description) assert.Equal(t, firstParameterDisplayName, resp.Report.ParametersUsage[0].DisplayName) assert.Contains(t, resp.Report.ParametersUsage[0].Values, codersdk.TemplateParameterValue{ Value: firstParameterValue, @@ -414,6 +416,8 @@ func TestTemplateInsights(t *testing.T) { assert.Empty(t, resp.Report.ParametersUsage[0].Options) assert.Equal(t, secondParameterName, resp.Report.ParametersUsage[1].Name) + assert.Equal(t, secondParameterType, resp.Report.ParametersUsage[1].Type) + assert.Equal(t, secondParameterDescription, resp.Report.ParametersUsage[1].Description) assert.Equal(t, secondParameterDisplayName, resp.Report.ParametersUsage[1].DisplayName) assert.Contains(t, resp.Report.ParametersUsage[1].Values, codersdk.TemplateParameterValue{ Value: secondParameterValue, @@ -423,6 +427,8 @@ func TestTemplateInsights(t *testing.T) { assert.Empty(t, resp.Report.ParametersUsage[1].Options) assert.Equal(t, thirdParameterName, resp.Report.ParametersUsage[2].Name) + assert.Equal(t, thirdParameterType, resp.Report.ParametersUsage[2].Type) + assert.Equal(t, thirdParameterDescription, resp.Report.ParametersUsage[2].Description) assert.Equal(t, thirdParameterDisplayName, resp.Report.ParametersUsage[2].DisplayName) assert.Contains(t, resp.Report.ParametersUsage[2].Values, codersdk.TemplateParameterValue{ Value: thirdParameterValue, diff --git a/codersdk/insights.go b/codersdk/insights.go index bfc51bd208..24e2ba140d 100644 --- a/codersdk/insights.go +++ b/codersdk/insights.go @@ -138,6 +138,8 @@ type TemplateParameterUsage struct { TemplateIDs []uuid.UUID `json:"template_ids" format:"uuid"` DisplayName string `json:"display_name"` Name string `json:"name"` + Type string `json:"type"` + Description string `json:"description"` Options []TemplateVersionParameterOption `json:"options,omitempty"` Values []TemplateParameterValue `json:"values"` } diff --git a/docs/api/insights.md b/docs/api/insights.md index 11843e63f0..3c421c6417 100644 --- a/docs/api/insights.md +++ b/docs/api/insights.md @@ -80,6 +80,7 @@ curl -X GET http://coder-server:8080/api/v2/insights/templates \ "end_time": "2019-08-24T14:15:22Z", "parameters_usage": [ { + "description": "string", "display_name": "string", "name": "string", "options": [ @@ -91,6 +92,7 @@ curl -X GET http://coder-server:8080/api/v2/insights/templates \ } ], "template_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "type": "string", "values": [ { "count": 0, diff --git a/docs/api/schemas.md b/docs/api/schemas.md index 192cc9625e..2f09bfb672 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -4321,6 +4321,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "end_time": "2019-08-24T14:15:22Z", "parameters_usage": [ { + "description": "string", "display_name": "string", "name": "string", "options": [ @@ -4332,6 +4333,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in } ], "template_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "type": "string", "values": [ { "count": 0, @@ -4384,6 +4386,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in "end_time": "2019-08-24T14:15:22Z", "parameters_usage": [ { + "description": "string", "display_name": "string", "name": "string", "options": [ @@ -4395,6 +4398,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in } ], "template_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "type": "string", "values": [ { "count": 0, @@ -4420,6 +4424,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ```json { + "description": "string", "display_name": "string", "name": "string", "options": [ @@ -4431,6 +4436,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in } ], "template_ids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "type": "string", "values": [ { "count": 0, @@ -4444,10 +4450,12 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | Name | Type | Required | Restrictions | Description | | -------------- | ------------------------------------------------------------------------------------------- | -------- | ------------ | ----------- | +| `description` | string | false | | | | `display_name` | string | false | | | | `name` | string | false | | | | `options` | array of [codersdk.TemplateVersionParameterOption](#codersdktemplateversionparameteroption) | false | | | | `template_ids` | array of string | false | | | +| `type` | string | false | | | | `values` | array of [codersdk.TemplateParameterValue](#codersdktemplateparametervalue) | false | | | ## codersdk.TemplateParameterValue diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index f8b91abb92..7b9b79d69b 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -987,6 +987,8 @@ export interface TemplateParameterUsage { readonly template_ids: string[] readonly display_name: string readonly name: string + readonly type: string + readonly description: string readonly options?: TemplateVersionParameterOption[] readonly values: TemplateParameterValue[] }