mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
feat: add template abstract metadata
This commit is contained in:
Generated
+14
@@ -17883,6 +17883,11 @@ const docTemplate = `{
|
||||
"template_version_id"
|
||||
],
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string",
|
||||
"maxLength": 2048
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||
"type": "integer"
|
||||
@@ -23315,6 +23320,10 @@ const docTemplate = `{
|
||||
"codersdk.Template": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string"
|
||||
},
|
||||
"active_user_count": {
|
||||
"description": "ActiveUserCount is set to -1 when loading.",
|
||||
"type": "integer"
|
||||
@@ -24427,6 +24436,11 @@ const docTemplate = `{
|
||||
"codersdk.UpdateTemplateMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string",
|
||||
"maxLength": 2048
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||
"type": "integer"
|
||||
|
||||
Generated
+14
@@ -16174,6 +16174,11 @@
|
||||
"type": "object",
|
||||
"required": ["name", "template_version_id"],
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string",
|
||||
"maxLength": 2048
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||
"type": "integer"
|
||||
@@ -21411,6 +21416,10 @@
|
||||
"codersdk.Template": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string"
|
||||
},
|
||||
"active_user_count": {
|
||||
"description": "ActiveUserCount is set to -1 when loading.",
|
||||
"type": "integer"
|
||||
@@ -22464,6 +22473,11 @@
|
||||
"codersdk.UpdateTemplateMeta": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"abstract": {
|
||||
"description": "Abstract is a longer-form summary surfaced to agents to help them pick\nthe right template. Up to 2048 characters.",
|
||||
"type": "string",
|
||||
"maxLength": 2048
|
||||
},
|
||||
"activity_bump_ms": {
|
||||
"description": "ActivityBumpMillis allows optionally specifying the activity bump\nduration for all workspaces created from this template. Defaults to 1h\nbut can be set to 0 to disable activity bumping.",
|
||||
"type": "integer"
|
||||
|
||||
@@ -535,6 +535,7 @@ func Template(t testing.TB, db database.Store, seed database.Template) database.
|
||||
Provisioner: takeFirst(seed.Provisioner, database.ProvisionerTypeEcho),
|
||||
ActiveVersionID: takeFirst(seed.ActiveVersionID, uuid.New()),
|
||||
Description: takeFirst(seed.Description, testutil.GetRandomName(t)),
|
||||
Abstract: seed.Abstract,
|
||||
CreatedBy: takeFirst(seed.CreatedBy, uuid.New()),
|
||||
Icon: takeFirst(seed.Icon, testutil.GetRandomName(t)),
|
||||
UserACL: seed.UserACL,
|
||||
|
||||
Generated
+5
-1
@@ -3095,7 +3095,8 @@ CREATE TABLE templates (
|
||||
max_port_sharing_level app_sharing_level DEFAULT 'owner'::app_sharing_level NOT NULL,
|
||||
use_classic_parameter_flow boolean DEFAULT false NOT NULL,
|
||||
cors_behavior cors_behavior DEFAULT 'simple'::cors_behavior NOT NULL,
|
||||
disable_module_cache boolean DEFAULT false NOT NULL
|
||||
disable_module_cache boolean DEFAULT false NOT NULL,
|
||||
abstract character varying(2048) DEFAULT ''::character varying NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN templates.default_ttl IS 'The default duration for autostop for workspaces created from this template.';
|
||||
@@ -3118,6 +3119,8 @@ COMMENT ON COLUMN templates.deprecated IS 'If set to a non empty string, the tem
|
||||
|
||||
COMMENT ON COLUMN templates.use_classic_parameter_flow IS 'Determines whether to default to the dynamic parameter creation flow for this template or continue using the legacy classic parameter creation flow.This is a template wide setting, the template admin can revert to the classic flow if there are any issues. An escape hatch is required, as workspace creation is a core workflow and cannot break. This column will be removed when the dynamic parameter creation flow is stable.';
|
||||
|
||||
COMMENT ON COLUMN templates.abstract IS 'Longer-form summary used to help agents pick the right template.';
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.id,
|
||||
templates.created_at,
|
||||
@@ -3150,6 +3153,7 @@ CREATE VIEW template_with_names AS
|
||||
templates.use_classic_parameter_flow,
|
||||
templates.cors_behavior,
|
||||
templates.disable_module_cache,
|
||||
templates.abstract,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
ALTER TABLE templates DROP COLUMN abstract;
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.*,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name,
|
||||
COALESCE(organizations.display_name, ''::text) AS organization_display_name,
|
||||
COALESCE(organizations.icon, ''::text) AS organization_icon
|
||||
FROM ((templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)))
|
||||
LEFT JOIN organizations ON ((templates.organization_id = organizations.id)));
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
@@ -0,0 +1,20 @@
|
||||
DROP VIEW template_with_names;
|
||||
|
||||
ALTER TABLE templates
|
||||
ADD COLUMN abstract character varying(2048) DEFAULT ''::character varying NOT NULL;
|
||||
|
||||
COMMENT ON COLUMN templates.abstract IS 'Longer-form summary used to help agents pick the right template.';
|
||||
|
||||
CREATE VIEW template_with_names AS
|
||||
SELECT templates.*,
|
||||
COALESCE(visible_users.avatar_url, ''::text) AS created_by_avatar_url,
|
||||
COALESCE(visible_users.username, ''::text) AS created_by_username,
|
||||
COALESCE(visible_users.name, ''::text) AS created_by_name,
|
||||
COALESCE(organizations.name, ''::text) AS organization_name,
|
||||
COALESCE(organizations.display_name, ''::text) AS organization_display_name,
|
||||
COALESCE(organizations.icon, ''::text) AS organization_icon
|
||||
FROM ((templates
|
||||
LEFT JOIN visible_users ON ((templates.created_by = visible_users.id)))
|
||||
LEFT JOIN organizations ON ((templates.organization_id = organizations.id)));
|
||||
|
||||
COMMENT ON VIEW template_with_names IS 'Joins in the display name information such as username, avatar, and organization name.';
|
||||
@@ -129,6 +129,7 @@ func (q *sqlQuerier) GetAuthorizedTemplates(ctx context.Context, arg GetTemplate
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CorsBehavior,
|
||||
&i.DisableModuleCache,
|
||||
&i.Abstract,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
|
||||
Generated
+3
@@ -5479,6 +5479,7 @@ type Template struct {
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"`
|
||||
DisableModuleCache bool `db:"disable_module_cache" json:"disable_module_cache"`
|
||||
Abstract string `db:"abstract" json:"abstract"`
|
||||
CreatedByAvatarURL string `db:"created_by_avatar_url" json:"created_by_avatar_url"`
|
||||
CreatedByUsername string `db:"created_by_username" json:"created_by_username"`
|
||||
CreatedByName string `db:"created_by_name" json:"created_by_name"`
|
||||
@@ -5529,6 +5530,8 @@ type TemplateTable struct {
|
||||
UseClassicParameterFlow bool `db:"use_classic_parameter_flow" json:"use_classic_parameter_flow"`
|
||||
CorsBehavior CorsBehavior `db:"cors_behavior" json:"cors_behavior"`
|
||||
DisableModuleCache bool `db:"disable_module_cache" json:"disable_module_cache"`
|
||||
// Longer-form summary used to help agents pick the right template.
|
||||
Abstract string `db:"abstract" json:"abstract"`
|
||||
}
|
||||
|
||||
// Records aggregated usage statistics for templates/users. All usage is rounded up to the nearest minute.
|
||||
|
||||
Generated
+25
-15
@@ -24767,7 +24767,7 @@ func (q *sqlQuerier) GetTemplateAverageBuildTime(ctx context.Context, templateID
|
||||
|
||||
const getTemplateByID = `-- name: GetTemplateByID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, abstract, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names
|
||||
WHERE
|
||||
@@ -24811,6 +24811,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CorsBehavior,
|
||||
&i.DisableModuleCache,
|
||||
&i.Abstract,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -24823,7 +24824,7 @@ func (q *sqlQuerier) GetTemplateByID(ctx context.Context, id uuid.UUID) (Templat
|
||||
|
||||
const getTemplateByOrganizationAndName = `-- name: GetTemplateByOrganizationAndName :one
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, abstract, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon
|
||||
FROM
|
||||
template_with_names AS templates
|
||||
WHERE
|
||||
@@ -24875,6 +24876,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CorsBehavior,
|
||||
&i.DisableModuleCache,
|
||||
&i.Abstract,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -24886,7 +24888,7 @@ func (q *sqlQuerier) GetTemplateByOrganizationAndName(ctx context.Context, arg G
|
||||
}
|
||||
|
||||
const getTemplates = `-- name: GetTemplates :many
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
SELECT id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, abstract, created_by_avatar_url, created_by_username, created_by_name, organization_name, organization_display_name, organization_icon FROM template_with_names AS templates
|
||||
ORDER BY (name, id) ASC
|
||||
`
|
||||
|
||||
@@ -24931,6 +24933,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CorsBehavior,
|
||||
&i.DisableModuleCache,
|
||||
&i.Abstract,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -24953,7 +24956,7 @@ func (q *sqlQuerier) GetTemplates(ctx context.Context) ([]Template, error) {
|
||||
|
||||
const getTemplatesWithFilter = `-- name: GetTemplatesWithFilter :many
|
||||
SELECT
|
||||
t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.disable_module_cache, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon
|
||||
t.id, t.created_at, t.updated_at, t.organization_id, t.deleted, t.name, t.provisioner, t.active_version_id, t.description, t.default_ttl, t.created_by, t.icon, t.user_acl, t.group_acl, t.display_name, t.allow_user_cancel_workspace_jobs, t.allow_user_autostart, t.allow_user_autostop, t.failure_ttl, t.time_til_dormant, t.time_til_dormant_autodelete, t.autostop_requirement_days_of_week, t.autostop_requirement_weeks, t.autostart_block_days_of_week, t.require_active_version, t.deprecated, t.activity_bump, t.max_port_sharing_level, t.use_classic_parameter_flow, t.cors_behavior, t.disable_module_cache, t.abstract, t.created_by_avatar_url, t.created_by_username, t.created_by_name, t.organization_name, t.organization_display_name, t.organization_icon
|
||||
FROM
|
||||
template_with_names AS t
|
||||
LEFT JOIN
|
||||
@@ -25113,6 +25116,7 @@ func (q *sqlQuerier) GetTemplatesWithFilter(ctx context.Context, arg GetTemplate
|
||||
&i.UseClassicParameterFlow,
|
||||
&i.CorsBehavior,
|
||||
&i.DisableModuleCache,
|
||||
&i.Abstract,
|
||||
&i.CreatedByAvatarURL,
|
||||
&i.CreatedByUsername,
|
||||
&i.CreatedByName,
|
||||
@@ -25144,6 +25148,7 @@ INSERT INTO
|
||||
provisioner,
|
||||
active_version_id,
|
||||
description,
|
||||
abstract,
|
||||
created_by,
|
||||
icon,
|
||||
user_acl,
|
||||
@@ -25155,7 +25160,7 @@ INSERT INTO
|
||||
cors_behavior
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
||||
`
|
||||
|
||||
type InsertTemplateParams struct {
|
||||
@@ -25167,6 +25172,7 @@ type InsertTemplateParams struct {
|
||||
Provisioner ProvisionerType `db:"provisioner" json:"provisioner"`
|
||||
ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Abstract string `db:"abstract" json:"abstract"`
|
||||
CreatedBy uuid.UUID `db:"created_by" json:"created_by"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
UserACL TemplateACL `db:"user_acl" json:"user_acl"`
|
||||
@@ -25188,6 +25194,7 @@ func (q *sqlQuerier) InsertTemplate(ctx context.Context, arg InsertTemplateParam
|
||||
arg.Provisioner,
|
||||
arg.ActiveVersionID,
|
||||
arg.Description,
|
||||
arg.Abstract,
|
||||
arg.CreatedBy,
|
||||
arg.Icon,
|
||||
arg.UserACL,
|
||||
@@ -25291,15 +25298,16 @@ UPDATE
|
||||
SET
|
||||
updated_at = $2,
|
||||
description = $3,
|
||||
name = $4,
|
||||
icon = $5,
|
||||
display_name = $6,
|
||||
allow_user_cancel_workspace_jobs = $7,
|
||||
group_acl = $8,
|
||||
max_port_sharing_level = $9,
|
||||
use_classic_parameter_flow = $10,
|
||||
cors_behavior = $11,
|
||||
disable_module_cache = $12
|
||||
abstract = $4,
|
||||
name = $5,
|
||||
icon = $6,
|
||||
display_name = $7,
|
||||
allow_user_cancel_workspace_jobs = $8,
|
||||
group_acl = $9,
|
||||
max_port_sharing_level = $10,
|
||||
use_classic_parameter_flow = $11,
|
||||
cors_behavior = $12,
|
||||
disable_module_cache = $13
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
@@ -25308,6 +25316,7 @@ type UpdateTemplateMetaByIDParams struct {
|
||||
ID uuid.UUID `db:"id" json:"id"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
Description string `db:"description" json:"description"`
|
||||
Abstract string `db:"abstract" json:"abstract"`
|
||||
Name string `db:"name" json:"name"`
|
||||
Icon string `db:"icon" json:"icon"`
|
||||
DisplayName string `db:"display_name" json:"display_name"`
|
||||
@@ -25324,6 +25333,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl
|
||||
arg.ID,
|
||||
arg.UpdatedAt,
|
||||
arg.Description,
|
||||
arg.Abstract,
|
||||
arg.Name,
|
||||
arg.Icon,
|
||||
arg.DisplayName,
|
||||
@@ -35319,7 +35329,7 @@ LEFT JOIN LATERAL (
|
||||
) latest_build ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache
|
||||
id, created_at, updated_at, organization_id, deleted, name, provisioner, active_version_id, description, default_ttl, created_by, icon, user_acl, group_acl, display_name, allow_user_cancel_workspace_jobs, allow_user_autostart, allow_user_autostop, failure_ttl, time_til_dormant, time_til_dormant_autodelete, autostop_requirement_days_of_week, autostop_requirement_weeks, autostart_block_days_of_week, require_active_version, deprecated, activity_bump, max_port_sharing_level, use_classic_parameter_flow, cors_behavior, disable_module_cache, abstract
|
||||
FROM
|
||||
templates
|
||||
WHERE
|
||||
|
||||
@@ -129,6 +129,7 @@ INSERT INTO
|
||||
provisioner,
|
||||
active_version_id,
|
||||
description,
|
||||
abstract,
|
||||
created_by,
|
||||
icon,
|
||||
user_acl,
|
||||
@@ -140,7 +141,7 @@ INSERT INTO
|
||||
cors_behavior
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17);
|
||||
($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18);
|
||||
|
||||
-- name: UpdateTemplateActiveVersionByID :exec
|
||||
UPDATE
|
||||
@@ -166,15 +167,16 @@ UPDATE
|
||||
SET
|
||||
updated_at = $2,
|
||||
description = $3,
|
||||
name = $4,
|
||||
icon = $5,
|
||||
display_name = $6,
|
||||
allow_user_cancel_workspace_jobs = $7,
|
||||
group_acl = $8,
|
||||
max_port_sharing_level = $9,
|
||||
use_classic_parameter_flow = $10,
|
||||
cors_behavior = $11,
|
||||
disable_module_cache = $12
|
||||
abstract = $4,
|
||||
name = $5,
|
||||
icon = $6,
|
||||
display_name = $7,
|
||||
allow_user_cancel_workspace_jobs = $8,
|
||||
group_acl = $9,
|
||||
max_port_sharing_level = $10,
|
||||
use_classic_parameter_flow = $11,
|
||||
cors_behavior = $12,
|
||||
disable_module_cache = $13
|
||||
WHERE
|
||||
id = $1
|
||||
;
|
||||
|
||||
@@ -220,6 +220,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
OrganizationID: organization.ID,
|
||||
Name: createTemplate.Name,
|
||||
Description: createTemplate.Description,
|
||||
Abstract: createTemplate.Abstract,
|
||||
CreatedBy: apiKey.UserID,
|
||||
Icon: createTemplate.Icon,
|
||||
DisplayName: createTemplate.DisplayName,
|
||||
@@ -429,6 +430,7 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque
|
||||
Provisioner: importJob.Provisioner,
|
||||
ActiveVersionID: templateVersion.ID,
|
||||
Description: createTemplate.Description,
|
||||
Abstract: createTemplate.Abstract,
|
||||
CreatedBy: apiKey.UserID,
|
||||
UserACL: database.TemplateACL{},
|
||||
GroupACL: defaultsGroups,
|
||||
@@ -764,6 +766,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
|
||||
Name: resolved.name,
|
||||
DisplayName: resolved.displayName,
|
||||
Description: resolved.description,
|
||||
Abstract: resolved.abstract,
|
||||
Icon: resolved.icon,
|
||||
AllowUserCancelWorkspaceJobs: resolved.allowUserCancelWorkspaceJobs,
|
||||
GroupACL: resolved.groupACL,
|
||||
@@ -1017,6 +1020,7 @@ func (api *API) convertTemplate(
|
||||
ActiveUserCount: owners,
|
||||
BuildTimeStats: buildTimeStats,
|
||||
Description: template.Description,
|
||||
Abstract: template.Abstract,
|
||||
Icon: template.Icon,
|
||||
DefaultTTLMillis: time.Duration(template.DefaultTTL).Milliseconds(),
|
||||
ActivityBumpMillis: time.Duration(template.ActivityBump).Milliseconds(),
|
||||
|
||||
@@ -19,6 +19,7 @@ type templateMetaUpdate struct {
|
||||
name string
|
||||
displayName string
|
||||
description string
|
||||
abstract string
|
||||
icon string
|
||||
defaultTTLMillis int64
|
||||
activityBumpMillis int64
|
||||
@@ -70,6 +71,7 @@ func resolveTemplateMetaUpdate(
|
||||
name: ptr.NilToDefault(req.Name, template.Name),
|
||||
displayName: ptr.NilToDefault(req.DisplayName, template.DisplayName),
|
||||
description: ptr.NilToDefault(req.Description, template.Description),
|
||||
abstract: ptr.NilToDefault(req.Abstract, template.Abstract),
|
||||
icon: ptr.NilToDefault(req.Icon, template.Icon),
|
||||
defaultTTLMillis: ptr.NilToDefault(req.DefaultTTLMillis, time.Duration(template.DefaultTTL).Milliseconds()),
|
||||
activityBumpMillis: ptr.NilToDefault(req.ActivityBumpMillis, time.Duration(template.ActivityBump).Milliseconds()),
|
||||
|
||||
@@ -42,6 +42,7 @@ func baselineTemplate() database.Template {
|
||||
UseClassicParameterFlow: true,
|
||||
CorsBehavior: database.CorsBehaviorPassthru,
|
||||
DisableModuleCache: true,
|
||||
Abstract: "Existing abstract.",
|
||||
GroupACL: database.TemplateACL{
|
||||
orgID.String(): {"read"},
|
||||
},
|
||||
@@ -70,6 +71,7 @@ func baselineResolved() templateMetaUpdate {
|
||||
name: tpl.Name,
|
||||
displayName: tpl.DisplayName,
|
||||
description: tpl.Description,
|
||||
abstract: tpl.Abstract,
|
||||
icon: tpl.Icon,
|
||||
defaultTTLMillis: tpl.DefaultTTL / 1e6,
|
||||
activityBumpMillis: tpl.ActivityBump / 1e6,
|
||||
@@ -148,6 +150,20 @@ func TestResolveTemplateMetaUpdate(t *testing.T) {
|
||||
r.description = "New description"
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "Abstract",
|
||||
req: codersdk.UpdateTemplateMeta{Abstract: ptr.Ref("New abstract.")},
|
||||
expected: expected{override: func(r *templateMetaUpdate) {
|
||||
r.abstract = "New abstract."
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "AbstractEmptyStringClears",
|
||||
req: codersdk.UpdateTemplateMeta{Abstract: ptr.Ref("")},
|
||||
expected: expected{override: func(r *templateMetaUpdate) {
|
||||
r.abstract = ""
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "Icon",
|
||||
req: codersdk.UpdateTemplateMeta{Icon: ptr.Ref("/new.svg")},
|
||||
|
||||
+116
-7
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -86,6 +87,50 @@ func TestPostTemplateByOrganization(t *testing.T) {
|
||||
assert.Equal(t, database.AuditActionCreate, auditor.AuditLogs()[2].Action)
|
||||
})
|
||||
|
||||
t.Run("Abstract", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
abstract string
|
||||
wantError bool
|
||||
}{
|
||||
{name: "PersistsValid", abstract: strings.Repeat("a", 2048)},
|
||||
{name: "RejectsOverLimit", abstract: strings.Repeat("a", 2049), wantError: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(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, nil)
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
created, err := client.CreateTemplate(ctx, user.OrganizationID, codersdk.CreateTemplateRequest{
|
||||
Name: "abstract-test",
|
||||
VersionID: version.ID,
|
||||
Abstract: tc.abstract,
|
||||
})
|
||||
if tc.wantError {
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
require.Len(t, apiErr.Validations, 1)
|
||||
require.Equal(t, "abstract", apiErr.Validations[0].Field)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.abstract, created.Abstract)
|
||||
got, err := client.Template(ctx, created.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.abstract, got.Abstract)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("AlreadyExists", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ownerClient := coderdtest.New(t, nil)
|
||||
@@ -942,6 +987,50 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
assert.Equal(t, database.AuditActionWrite, auditor.AuditLogs()[4].Action)
|
||||
})
|
||||
|
||||
t.Run("Abstract", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
abstract string
|
||||
wantError bool
|
||||
}{
|
||||
{name: "PersistsValid", abstract: strings.Repeat("a", 2048)},
|
||||
{name: "RejectsOverLimit", abstract: strings.Repeat("a", 2049), wantError: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(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, nil)
|
||||
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
|
||||
|
||||
abstract := tc.abstract
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
updated, err := client.UpdateTemplateMeta(ctx, template.ID, codersdk.UpdateTemplateMeta{
|
||||
Abstract: &abstract,
|
||||
})
|
||||
if tc.wantError {
|
||||
var apiErr *codersdk.Error
|
||||
require.ErrorAs(t, err, &apiErr)
|
||||
require.Equal(t, http.StatusBadRequest, apiErr.StatusCode())
|
||||
require.Len(t, apiErr.Validations, 1)
|
||||
require.Equal(t, "abstract", apiErr.Validations[0].Field)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.abstract, updated.Abstract)
|
||||
got, err := client.Template(ctx, template.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.abstract, got.Abstract)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("AlreadyExists", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1336,6 +1425,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, template.Name, updated.Name)
|
||||
assert.Equal(t, template.Description, updated.Description)
|
||||
assert.Equal(t, template.Abstract, updated.Abstract)
|
||||
assert.Equal(t, template.Icon, updated.Icon)
|
||||
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||
assert.Equal(t, template.ActivityBumpMillis, updated.ActivityBumpMillis)
|
||||
@@ -1371,6 +1461,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
assert.WithinDuration(t, template.UpdatedAt, updated.UpdatedAt, time.Minute)
|
||||
assert.Equal(t, template.Name, updated.Name)
|
||||
assert.Equal(t, template.Description, updated.Description)
|
||||
assert.Equal(t, template.Abstract, updated.Abstract)
|
||||
assert.Equal(t, template.Icon, updated.Icon)
|
||||
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||
})
|
||||
@@ -1665,22 +1756,26 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
|
||||
displayName := "Test Display Name"
|
||||
description := "test-description"
|
||||
abstract := "test abstract for agents"
|
||||
icon := "/icon/icon.png"
|
||||
defaultTTLMillis := 10 * time.Hour.Milliseconds()
|
||||
|
||||
reference := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
||||
ctr.DisplayName = displayName
|
||||
ctr.Description = description
|
||||
ctr.Abstract = abstract
|
||||
ctr.Icon = icon
|
||||
ctr.DefaultTTLMillis = ptr.Ref(defaultTTLMillis)
|
||||
})
|
||||
require.Equal(t, displayName, reference.DisplayName)
|
||||
require.Equal(t, description, reference.Description)
|
||||
require.Equal(t, abstract, reference.Abstract)
|
||||
require.Equal(t, icon, reference.Icon)
|
||||
|
||||
restoreReq := codersdk.UpdateTemplateMeta{
|
||||
DisplayName: &displayName,
|
||||
Description: &description,
|
||||
Abstract: &abstract,
|
||||
Icon: &icon,
|
||||
DefaultTTLMillis: ptr.Ref(defaultTTLMillis),
|
||||
}
|
||||
@@ -1688,6 +1783,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
type expected struct {
|
||||
displayName string
|
||||
description string
|
||||
abstract string
|
||||
icon string
|
||||
defaultTTLMillis int64
|
||||
}
|
||||
@@ -1702,22 +1798,27 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
{
|
||||
name: "Only update default_ttl_ms",
|
||||
req: codersdk.UpdateTemplateMeta{DefaultTTLMillis: ptr.Ref(99 * time.Hour.Milliseconds())},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, icon: reference.Icon, defaultTTLMillis: 99 * time.Hour.Milliseconds()},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: 99 * time.Hour.Milliseconds()},
|
||||
},
|
||||
{
|
||||
name: "Clear display name",
|
||||
req: codersdk.UpdateTemplateMeta{DisplayName: ptr.Ref("")},
|
||||
expected: expected{displayName: "", description: reference.Description, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: "", description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Clear description",
|
||||
req: codersdk.UpdateTemplateMeta{Description: ptr.Ref("")},
|
||||
expected: expected{displayName: reference.DisplayName, description: "", icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: reference.DisplayName, description: "", abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Clear abstract",
|
||||
req: codersdk.UpdateTemplateMeta{Abstract: ptr.Ref("")},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: "", icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Clear icon",
|
||||
req: codersdk.UpdateTemplateMeta{Icon: ptr.Ref("")},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, icon: "", defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: "", defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
// A request whose only field is nil is a true no-op under the new
|
||||
// PATCH semantics; the handler returns 304 Not Modified and the
|
||||
@@ -1725,17 +1826,22 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
{
|
||||
name: "Nil display name is a no-op",
|
||||
req: codersdk.UpdateTemplateMeta{DisplayName: nil},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Nil description is a no-op",
|
||||
req: codersdk.UpdateTemplateMeta{Description: nil},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Nil abstract is a no-op",
|
||||
req: codersdk.UpdateTemplateMeta{Abstract: nil},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
{
|
||||
name: "Nil icon is a no-op",
|
||||
req: codersdk.UpdateTemplateMeta{Icon: nil},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
expected: expected{displayName: reference.DisplayName, description: reference.Description, abstract: reference.Abstract, icon: reference.Icon, defaultTTLMillis: defaultTTLMillis},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1757,6 +1863,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expected.displayName, updated.DisplayName)
|
||||
assert.Equal(t, tc.expected.description, updated.Description)
|
||||
assert.Equal(t, tc.expected.abstract, updated.Abstract)
|
||||
assert.Equal(t, tc.expected.icon, updated.Icon)
|
||||
assert.Equal(t, tc.expected.defaultTTLMillis, updated.DefaultTTLMillis)
|
||||
})
|
||||
@@ -1774,6 +1881,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) {
|
||||
ctr.DisplayName = "Original Display"
|
||||
ctr.Description = "Original description"
|
||||
ctr.Abstract = "Original abstract"
|
||||
ctr.Icon = "/icon/original.png"
|
||||
ctr.DefaultTTLMillis = ptr.Ref((24 * time.Hour).Milliseconds())
|
||||
ctr.AllowUserCancelWorkspaceJobs = ptr.Ref(true)
|
||||
@@ -1789,6 +1897,7 @@ func TestPatchTemplateMeta(t *testing.T) {
|
||||
assert.Equal(t, template.Name, updated.Name)
|
||||
assert.Equal(t, template.DisplayName, updated.DisplayName)
|
||||
assert.Equal(t, template.Description, updated.Description)
|
||||
assert.Equal(t, template.Abstract, updated.Abstract)
|
||||
assert.Equal(t, template.Icon, updated.Icon)
|
||||
assert.Equal(t, template.DefaultTTLMillis, updated.DefaultTTLMillis)
|
||||
assert.Equal(t, template.AllowUserCancelWorkspaceJobs, updated.AllowUserCancelWorkspaceJobs)
|
||||
|
||||
@@ -41,7 +41,7 @@ func ListTemplates(db database.Store, organizationID uuid.UUID, options ListTemp
|
||||
"list_templates",
|
||||
"List available workspace templates. Optionally filter by a "+
|
||||
"search query matching template name or description. "+
|
||||
"Use this to find a template before creating a workspace. "+
|
||||
"Results include short UI descriptions and agent-facing abstracts when present. "+
|
||||
"Results are ordered by number of active developers (most popular first). "+
|
||||
"Returns 10 per page. Use the page parameter to paginate through results.",
|
||||
func(ctx context.Context, args listTemplatesArgs, _ fantasy.ToolCall) (fantasy.ToolResponse, error) {
|
||||
@@ -128,6 +128,9 @@ func ListTemplates(db database.Store, organizationID uuid.UUID, options ListTemp
|
||||
if desc := strings.TrimSpace(t.Description); desc != "" {
|
||||
item["description"] = truncateRunes(desc, 200)
|
||||
}
|
||||
if abstract := strings.TrimSpace(t.Abstract); abstract != "" {
|
||||
item["abstract"] = abstract
|
||||
}
|
||||
if count, ok := ownerCounts[t.ID]; ok && count > 0 {
|
||||
item["active_developers"] = count
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package chattool_test
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"charm.land/fantasy"
|
||||
@@ -121,6 +122,120 @@ func TestListTemplates_OrganizationFilter(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestListTemplates_Abstract(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
template database.Template
|
||||
want string
|
||||
wantPresent bool
|
||||
}{
|
||||
{
|
||||
name: "LongAbstract",
|
||||
template: database.Template{
|
||||
Name: "with-abstract",
|
||||
Description: "short description",
|
||||
Abstract: strings.Repeat("a", 1000),
|
||||
},
|
||||
want: strings.Repeat("a", 1000),
|
||||
wantPresent: true,
|
||||
},
|
||||
{
|
||||
name: "ShortAbstractUntouched",
|
||||
template: database.Template{
|
||||
Name: "short-abstract",
|
||||
Description: "short description",
|
||||
Abstract: "a concise abstract",
|
||||
},
|
||||
want: "a concise abstract",
|
||||
wantPresent: true,
|
||||
},
|
||||
{
|
||||
name: "EmptyAbstractOmitted",
|
||||
template: database.Template{
|
||||
Name: "no-abstract",
|
||||
Description: "short description",
|
||||
Abstract: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "WhitespaceOnlyAbstractOmitted",
|
||||
template: database.Template{
|
||||
Name: "whitespace-abstract",
|
||||
Description: "short description",
|
||||
Abstract: " \t \n ",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fixture := newListTemplatesFixture(t)
|
||||
template := tc.template
|
||||
template.OrganizationID = fixture.org.ID
|
||||
template.CreatedBy = fixture.user.ID
|
||||
tpl := dbgen.Template(t, fixture.db, template)
|
||||
|
||||
items := fixture.listTemplates(t, "{}")
|
||||
require.Len(t, items, 1)
|
||||
require.Equal(t, tpl.ID.String(), items[0]["id"].(string))
|
||||
require.Equal(t, "short description", items[0]["description"].(string))
|
||||
|
||||
got, ok := items[0]["abstract"]
|
||||
require.Equal(t, tc.wantPresent, ok)
|
||||
if tc.wantPresent {
|
||||
require.Equal(t, tc.want, got.(string))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type listTemplatesFixture struct {
|
||||
db database.Store
|
||||
user database.User
|
||||
org database.Organization
|
||||
}
|
||||
|
||||
func newListTemplatesFixture(t *testing.T) listTemplatesFixture {
|
||||
t.Helper()
|
||||
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
_ = dbgen.OrganizationMember(t, db, database.OrganizationMember{
|
||||
UserID: user.ID,
|
||||
OrganizationID: org.ID,
|
||||
})
|
||||
return listTemplatesFixture{db: db, user: user, org: org}
|
||||
}
|
||||
|
||||
func (f listTemplatesFixture) listTemplates(t *testing.T, input string) []map[string]any {
|
||||
t.Helper()
|
||||
|
||||
tool := chattool.ListTemplates(f.db, f.org.ID, chattool.ListTemplatesOptions{
|
||||
OwnerID: f.user.ID,
|
||||
})
|
||||
resp, err := tool.Run(testutil.Context(t, testutil.WaitShort), fantasy.ToolCall{
|
||||
ID: "list-templates",
|
||||
Name: "list_templates",
|
||||
Input: input,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.False(t, resp.IsError)
|
||||
|
||||
var result map[string]any
|
||||
require.NoError(t, json.Unmarshal([]byte(resp.Content), &result))
|
||||
templates := result["templates"].([]any)
|
||||
items := make([]map[string]any, 0, len(templates))
|
||||
for _, template := range templates {
|
||||
items = append(items, template.(map[string]any))
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
//nolint:tparallel,paralleltest // Subtests share a single DB and run sequentially.
|
||||
func TestTemplateAllowlistEnforcement(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -88,6 +88,9 @@ func ReadTemplate(db database.Store, organizationID uuid.UUID, options ReadTempl
|
||||
if desc := strings.TrimSpace(template.Description); desc != "" {
|
||||
templateInfo["description"] = desc
|
||||
}
|
||||
if abstract := strings.TrimSpace(template.Abstract); abstract != "" {
|
||||
templateInfo["abstract"] = abstract
|
||||
}
|
||||
|
||||
paramList := make([]map[string]any, 0, len(params))
|
||||
for _, p := range params {
|
||||
|
||||
@@ -181,3 +181,74 @@ func TestReadTemplate_NoPresets(t *testing.T) {
|
||||
_, hasPresets := result["presets"]
|
||||
require.False(t, hasPresets, "presets key should be absent when there are none")
|
||||
}
|
||||
|
||||
func TestReadTemplate_Abstract(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
abstract string
|
||||
want string
|
||||
wantPresent bool
|
||||
}{
|
||||
{
|
||||
name: "Present",
|
||||
abstract: "A long-form summary used by agents to pick the right template.",
|
||||
want: "A long-form summary used by agents to pick the right template.",
|
||||
wantPresent: true,
|
||||
},
|
||||
{name: "Empty"},
|
||||
{name: "WhitespaceOnly", abstract: " \t \n "},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tmplInfo := readTemplateInfo(t, tc.abstract)
|
||||
got, ok := tmplInfo["abstract"]
|
||||
require.Equal(t, tc.wantPresent, ok)
|
||||
if tc.wantPresent {
|
||||
require.Equal(t, tc.want, got.(string))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func readTemplateInfo(t *testing.T, abstract string) map[string]any {
|
||||
t.Helper()
|
||||
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
_ = dbgen.OrganizationMember(t, db, database.OrganizationMember{
|
||||
UserID: user.ID,
|
||||
OrganizationID: org.ID,
|
||||
})
|
||||
|
||||
tv := dbgen.TemplateVersion(t, db, database.TemplateVersion{
|
||||
OrganizationID: org.ID,
|
||||
CreatedBy: user.ID,
|
||||
})
|
||||
tmpl := dbgen.Template(t, db, database.Template{
|
||||
OrganizationID: org.ID,
|
||||
CreatedBy: user.ID,
|
||||
ActiveVersionID: tv.ID,
|
||||
Abstract: abstract,
|
||||
})
|
||||
|
||||
tool := chattool.ReadTemplate(db, org.ID, chattool.ReadTemplateOptions{
|
||||
OwnerID: user.ID,
|
||||
})
|
||||
resp, err := tool.Run(testutil.Context(t, testutil.WaitShort), fantasy.ToolCall{
|
||||
ID: "abstract",
|
||||
Name: "read_template",
|
||||
Input: `{"template_id":"` + tmpl.ID.String() + `"}`,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.False(t, resp.IsError)
|
||||
|
||||
var result map[string]any
|
||||
require.NoError(t, json.Unmarshal([]byte(resp.Content), &result))
|
||||
return result["template"].(map[string]any)
|
||||
}
|
||||
|
||||
@@ -144,6 +144,9 @@ type CreateTemplateRequest struct {
|
||||
// Description is a description of what the template contains. It must be
|
||||
// less than 128 bytes.
|
||||
Description string `json:"description,omitempty" validate:"lt=128"`
|
||||
// Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
// the right template. Up to 2048 characters.
|
||||
Abstract string `json:"abstract,omitempty" validate:"max=2048"`
|
||||
// Icon is a relative path or external URL that specifies
|
||||
// an icon to be displayed in the dashboard.
|
||||
Icon string `json:"icon,omitempty"`
|
||||
|
||||
+18
-12
@@ -27,15 +27,18 @@ type Template struct {
|
||||
Provisioner ProvisionerType `json:"provisioner" enums:"terraform"`
|
||||
ActiveVersionID uuid.UUID `json:"active_version_id" format:"uuid"`
|
||||
// ActiveUserCount is set to -1 when loading.
|
||||
ActiveUserCount int `json:"active_user_count"`
|
||||
BuildTimeStats TemplateBuildTimeStats `json:"build_time_stats"`
|
||||
Description string `json:"description"`
|
||||
Deprecated bool `json:"deprecated"`
|
||||
DeprecationMessage string `json:"deprecation_message"`
|
||||
Deleted bool `json:"deleted"`
|
||||
Icon string `json:"icon"`
|
||||
DefaultTTLMillis int64 `json:"default_ttl_ms"`
|
||||
ActivityBumpMillis int64 `json:"activity_bump_ms"`
|
||||
ActiveUserCount int `json:"active_user_count"`
|
||||
BuildTimeStats TemplateBuildTimeStats `json:"build_time_stats"`
|
||||
Description string `json:"description"`
|
||||
// Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
// the right template. Up to 2048 characters.
|
||||
Abstract string `json:"abstract"`
|
||||
Deprecated bool `json:"deprecated"`
|
||||
DeprecationMessage string `json:"deprecation_message"`
|
||||
Deleted bool `json:"deleted"`
|
||||
Icon string `json:"icon"`
|
||||
DefaultTTLMillis int64 `json:"default_ttl_ms"`
|
||||
ActivityBumpMillis int64 `json:"activity_bump_ms"`
|
||||
// AutostopRequirement and AutostartRequirement are enterprise features. Its
|
||||
// value is only used if your license is entitled to use the advanced template
|
||||
// scheduling feature.
|
||||
@@ -218,9 +221,12 @@ type ACLAvailable struct {
|
||||
// UpdateTemplateMeta is the request body for the PATCH /templates/{template}
|
||||
// endpoint. All fields are optional. Fields that are nil are not modified.
|
||||
type UpdateTemplateMeta struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,template_name"`
|
||||
DisplayName *string `json:"display_name,omitempty" validate:"omitempty,template_display_name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,template_name"`
|
||||
DisplayName *string `json:"display_name,omitempty" validate:"omitempty,template_display_name"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
// Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
// the right template. Up to 2048 characters.
|
||||
Abstract *string `json:"abstract,omitempty" validate:"omitempty,max=2048"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
DefaultTTLMillis *int64 `json:"default_ttl_ms,omitempty"`
|
||||
// ActivityBumpMillis allows optionally specifying the activity bump
|
||||
|
||||
@@ -57,10 +57,17 @@ func searchTemplates(ctx context.Context, deps Deps, query string) ([]SearchResu
|
||||
}
|
||||
results := make([]SearchResultItem, len(templates))
|
||||
for i, template := range templates {
|
||||
parts := make([]string, 0, 2)
|
||||
if d := strings.TrimSpace(template.Description); d != "" {
|
||||
parts = append(parts, d)
|
||||
}
|
||||
if a := strings.TrimSpace(template.Abstract); a != "" {
|
||||
parts = append(parts, a)
|
||||
}
|
||||
results[i] = SearchResultItem{
|
||||
ID: createObjectID(ObjectTypeTemplate, template.ID.String()).String(),
|
||||
Title: template.DisplayName,
|
||||
Text: template.Description,
|
||||
Text: strings.Join(parts, "\n\n"),
|
||||
URL: fmt.Sprintf("%s/templates/%s/%s", serverURL, template.OrganizationName, template.Name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,51 @@ func TestChatGPTSearch_TemplateMultipleFilters(t *testing.T) {
|
||||
require.Equal(t, expectedID, result.Results[0].ID, "Should match the docker template in org2")
|
||||
}
|
||||
|
||||
func TestChatGPTSearch_TemplateIncludesAbstract(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client, store := coderdtest.NewWithDatabase(t, nil)
|
||||
owner := coderdtest.CreateFirstUser(t, client)
|
||||
|
||||
const (
|
||||
desc = "Short description."
|
||||
abstract = "Detailed summary that distinguishes this template."
|
||||
)
|
||||
|
||||
dbgen.Template(t, store, database.Template{
|
||||
OrganizationID: owner.OrganizationID,
|
||||
CreatedBy: owner.UserID,
|
||||
Name: "with-abstract",
|
||||
DisplayName: "With Abstract",
|
||||
Description: desc,
|
||||
Abstract: abstract,
|
||||
})
|
||||
dbgen.Template(t, store, database.Template{
|
||||
OrganizationID: owner.OrganizationID,
|
||||
CreatedBy: owner.UserID,
|
||||
Name: "no-abstract",
|
||||
DisplayName: "No Abstract",
|
||||
Description: desc,
|
||||
})
|
||||
|
||||
deps, err := toolsdk.NewDeps(client)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := testTool(t, toolsdk.ChatGPTSearch, deps, toolsdk.SearchArgs{Query: "templates"})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, result.Results, 2)
|
||||
|
||||
byTitle := make(map[string]toolsdk.SearchResultItem, len(result.Results))
|
||||
for _, item := range result.Results {
|
||||
byTitle[item.Title] = item
|
||||
}
|
||||
require.Contains(t, byTitle, "With Abstract")
|
||||
require.Contains(t, byTitle, "No Abstract")
|
||||
require.Contains(t, byTitle["With Abstract"].Text, desc)
|
||||
require.Contains(t, byTitle["With Abstract"].Text, abstract)
|
||||
require.Equal(t, desc, byTitle["No Abstract"].Text)
|
||||
}
|
||||
|
||||
func TestChatGPTSearch_WorkspaceSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ var ListWorkspaces = Tool[ListWorkspacesArgs, []MinimalWorkspace]{
|
||||
var ListTemplates = Tool[NoArgs, []MinimalTemplate]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: ToolNameListTemplates,
|
||||
Description: "Lists templates for the authenticated user.",
|
||||
Description: "Lists templates for the authenticated user. Description is short UI text; abstract is richer selection context.",
|
||||
Schema: aisdk.Schema{
|
||||
Properties: map[string]any{},
|
||||
Required: []string{},
|
||||
@@ -640,6 +640,7 @@ var ListTemplates = Tool[NoArgs, []MinimalTemplate]{
|
||||
ID: template.ID.String(),
|
||||
Name: template.Name,
|
||||
Description: template.Description,
|
||||
Abstract: template.Abstract,
|
||||
ActiveVersionID: template.ActiveVersionID,
|
||||
ActiveUserCount: template.ActiveUserCount,
|
||||
}
|
||||
@@ -732,7 +733,7 @@ func toPresetView(p codersdk.Preset) presetView {
|
||||
var GetTemplate = Tool[GetTemplateArgs, TemplateDetail]{
|
||||
Tool: aisdk.Tool{
|
||||
Name: ToolNameGetTemplate,
|
||||
Description: `Get details about a workspace template, including its configurable parameters and available presets for the active version.
|
||||
Description: `Get details about a workspace template, including its abstract, configurable parameters, and available presets for the active version.
|
||||
|
||||
Use this after finding a template with coder_list_templates and before creating a workspace with coder_create_workspace. Presets, when present, can be passed to coder_create_workspace as template_version_preset_id.
|
||||
|
||||
@@ -777,6 +778,7 @@ When selecting a preset: if a preset is marked default and the user has not spec
|
||||
ID: template.ID.String(),
|
||||
Name: template.Name,
|
||||
Description: template.Description,
|
||||
Abstract: template.Abstract,
|
||||
ActiveVersionID: template.ActiveVersionID,
|
||||
ActiveUserCount: template.ActiveUserCount,
|
||||
},
|
||||
@@ -1719,6 +1721,7 @@ type MinimalTemplate struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Abstract string `json:"abstract,omitempty"`
|
||||
ActiveVersionID uuid.UUID `json:"active_version_id"`
|
||||
ActiveUserCount int `json:"active_user_count"`
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -309,6 +310,7 @@ func TestTools(t *testing.T) {
|
||||
})
|
||||
for i, template := range result {
|
||||
require.Equal(t, expected[i].ID.String(), template.ID)
|
||||
require.Equal(t, expected[i].Abstract, template.Abstract)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -738,6 +740,27 @@ func TestTools(t *testing.T) {
|
||||
})
|
||||
require.ErrorContains(t, err, "get template")
|
||||
})
|
||||
|
||||
t.Run("Abstract", func(t *testing.T) {
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
absBuild := dbfake.WorkspaceBuild(t, store, database.WorkspaceTable{
|
||||
OrganizationID: owner.OrganizationID,
|
||||
OwnerID: member.ID,
|
||||
}).Do()
|
||||
abstract := strings.Repeat("b", 600)
|
||||
_, err := client.UpdateTemplateMeta(ctx, absBuild.Template.ID, codersdk.UpdateTemplateMeta{
|
||||
Abstract: &abstract,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
tb, err := toolsdk.NewDeps(memberClient)
|
||||
require.NoError(t, err)
|
||||
result, err := testTool(t, toolsdk.GetTemplate, tb, toolsdk.GetTemplateArgs{
|
||||
TemplateID: absBuild.Template.ID.String(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, abstract, result.Abstract)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("GetWorkspaceAgentLogs", func(t *testing.T) {
|
||||
|
||||
@@ -13,40 +13,40 @@ We track the following resources:
|
||||
|
||||
<!-- Code generated by 'make docs/admin/security/audit-logs.md'. DO NOT EDIT -->
|
||||
|
||||
| <b>Resource<b> | | |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AIGatewayKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>hashed_secret</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>secret_prefix</td><td>true</td></tr></tbody></table> |
|
||||
| AIProvider<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>base_url</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>enabled</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>settings</td><td>true</td></tr><tr><td>settings_key_id</td><td>false</td></tr><tr><td>type</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AIProviderKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>api_key</td><td>true</td></tr><tr><td>api_key_key_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>provider_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| APIKey<br><i>login, logout, register, create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>allow_list</td><td>false</td></tr><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scopes</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AiSeatState<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>first_used_at</td><td>true</td></tr><tr><td>last_event_description</td><td>true</td></tr><tr><td>last_event_type</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>true</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableGroupAiBudget<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>false</td></tr><tr><td>group_name</td><td>false</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableOrganizationMember<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>roles</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| Chat<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>agent_id</td><td>false</td></tr><tr><td>archived</td><td>true</td></tr><tr><td>build_id</td><td>false</td></tr><tr><td>client_type</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamic_tools</td><td>false</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>heartbeat_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>labels</td><td>true</td></tr><tr><td>last_error</td><td>false</td></tr><tr><td>last_injected_context</td><td>false</td></tr><tr><td>last_model_config_id</td><td>false</td></tr><tr><td>last_read_message_id</td><td>false</td></tr><tr><td>last_turn_summary</td><td>false</td></tr><tr><td>mcp_server_ids</td><td>true</td></tr><tr><td>mode</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>owner_name</td><td>false</td></tr><tr><td>owner_username</td><td>false</td></tr><tr><td>parent_chat_id</td><td>false</td></tr><tr><td>pin_order</td><td>true</td></tr><tr><td>plan_mode</td><td>false</td></tr><tr><td>root_chat_id</td><td>false</td></tr><tr><td>started_at</td><td>false</td></tr><tr><td>status</td><td>false</td></tr><tr><td>title</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr><tr><td>worker_id</td><td>false</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| CustomRole<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_system</td><td>false</td></tr><tr><td>member_permissions</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>org_permissions</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>site_permissions</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_permissions</td><td>true</td></tr></tbody></table> |
|
||||
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>private_key_key_id</td><td>false</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| GroupSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>auto_create_missing_groups</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>legacy_group_name_mapping</td><td>false</td></tr><tr><td>mapping</td><td>true</td></tr><tr><td>regex_filter</td><td>true</td></tr></tbody></table> |
|
||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>enabled_by_default</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>notifier_paused</td><td>true</td></tr></tbody></table> |
|
||||
| OAuth2ProviderApp<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>callback_url</td><td>true</td></tr><tr><td>client_id_issued_at</td><td>false</td></tr><tr><td>client_secret_expires_at</td><td>true</td></tr><tr><td>client_type</td><td>true</td></tr><tr><td>client_uri</td><td>true</td></tr><tr><td>contacts</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamically_registered</td><td>true</td></tr><tr><td>grant_types</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwks</td><td>true</td></tr><tr><td>jwks_uri</td><td>true</td></tr><tr><td>logo_uri</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>policy_uri</td><td>true</td></tr><tr><td>redirect_uris</td><td>true</td></tr><tr><td>registration_access_token</td><td>true</td></tr><tr><td>registration_client_uri</td><td>true</td></tr><tr><td>response_types</td><td>true</td></tr><tr><td>scope</td><td>true</td></tr><tr><td>software_id</td><td>true</td></tr><tr><td>software_version</td><td>true</td></tr><tr><td>token_endpoint_auth_method</td><td>true</td></tr><tr><td>tos_uri</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>shareable_workspace_owners</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| PrebuildsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>reconciliation_paused</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| TaskTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>prompt</td><td>true</td></tr><tr><td>template_parameters</td><td>true</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>disable_module_cache</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_service_account</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
|
||||
| UserSkill<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>content</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_name</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>template_version_preset_id</td><td>false</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>next_start_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| <b>Resource<b> | | |
|
||||
|-----------------------------------------------------------------|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AIGatewayKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>hashed_secret</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>secret_prefix</td><td>true</td></tr></tbody></table> |
|
||||
| AIProvider<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>base_url</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>enabled</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>settings</td><td>true</td></tr><tr><td>settings_key_id</td><td>false</td></tr><tr><td>type</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AIProviderKey<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>api_key</td><td>true</td></tr><tr><td>api_key_key_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>provider_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| APIKey<br><i>login, logout, register, create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>allow_list</td><td>false</td></tr><tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>ip_address</td><td>false</td></tr><tr><td>last_used</td><td>true</td></tr><tr><td>lifetime_seconds</td><td>false</td></tr><tr><td>login_type</td><td>false</td></tr><tr><td>scopes</td><td>false</td></tr><tr><td>token_name</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AiSeatState<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>first_used_at</td><td>true</td></tr><tr><td>last_event_description</td><td>true</td></tr><tr><td>last_event_type</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| AuditOAuthConvertState<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>expires_at</td><td>true</td></tr><tr><td>from_login_type</td><td>true</td></tr><tr><td>to_login_type</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| Group<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>true</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>members</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>quota_allowance</td><td>true</td></tr><tr><td>source</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableGroupAiBudget<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>group_id</td><td>false</td></tr><tr><td>group_name</td><td>false</td></tr><tr><td>spend_limit</td><td>true</td></tr><tr><td>spend_limit_micros</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| AuditableOrganizationMember<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>roles</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| Chat<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>agent_id</td><td>false</td></tr><tr><td>archived</td><td>true</td></tr><tr><td>build_id</td><td>false</td></tr><tr><td>client_type</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamic_tools</td><td>false</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>heartbeat_at</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>labels</td><td>true</td></tr><tr><td>last_error</td><td>false</td></tr><tr><td>last_injected_context</td><td>false</td></tr><tr><td>last_model_config_id</td><td>false</td></tr><tr><td>last_read_message_id</td><td>false</td></tr><tr><td>last_turn_summary</td><td>false</td></tr><tr><td>mcp_server_ids</td><td>true</td></tr><tr><td>mode</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>owner_name</td><td>false</td></tr><tr><td>owner_username</td><td>false</td></tr><tr><td>parent_chat_id</td><td>false</td></tr><tr><td>pin_order</td><td>true</td></tr><tr><td>plan_mode</td><td>false</td></tr><tr><td>root_chat_id</td><td>false</td></tr><tr><td>started_at</td><td>false</td></tr><tr><td>status</td><td>false</td></tr><tr><td>title</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr><tr><td>worker_id</td><td>false</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| CustomRole<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_system</td><td>false</td></tr><tr><td>member_permissions</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>org_permissions</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>site_permissions</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_permissions</td><td>true</td></tr></tbody></table> |
|
||||
| GitSSHKey<br><i>create</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>private_key</td><td>true</td></tr><tr><td>private_key_key_id</td><td>false</td></tr><tr><td>public_key</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| GroupSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>auto_create_missing_groups</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>legacy_group_name_mapping</td><td>false</td></tr><tr><td>mapping</td><td>true</td></tr><tr><td>regex_filter</td><td>true</td></tr></tbody></table> |
|
||||
| HealthSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>dismissed_healthchecks</td><td>true</td></tr><tr><td>id</td><td>false</td></tr></tbody></table> |
|
||||
| License<br><i>create, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>exp</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwt</td><td>false</td></tr><tr><td>uploaded_at</td><td>true</td></tr><tr><td>uuid</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationTemplate<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>actions</td><td>true</td></tr><tr><td>body_template</td><td>true</td></tr><tr><td>enabled_by_default</td><td>true</td></tr><tr><td>group</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>kind</td><td>true</td></tr><tr><td>method</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>title_template</td><td>true</td></tr></tbody></table> |
|
||||
| NotificationsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>notifier_paused</td><td>true</td></tr></tbody></table> |
|
||||
| OAuth2ProviderApp<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>callback_url</td><td>true</td></tr><tr><td>client_id_issued_at</td><td>false</td></tr><tr><td>client_secret_expires_at</td><td>true</td></tr><tr><td>client_type</td><td>true</td></tr><tr><td>client_uri</td><td>true</td></tr><tr><td>contacts</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>dynamically_registered</td><td>true</td></tr><tr><td>grant_types</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>jwks</td><td>true</td></tr><tr><td>jwks_uri</td><td>true</td></tr><tr><td>logo_uri</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>policy_uri</td><td>true</td></tr><tr><td>redirect_uris</td><td>true</td></tr><tr><td>registration_access_token</td><td>true</td></tr><tr><td>registration_client_uri</td><td>true</td></tr><tr><td>response_types</td><td>true</td></tr><tr><td>scope</td><td>true</td></tr><tr><td>software_id</td><td>true</td></tr><tr><td>software_version</td><td>true</td></tr><tr><td>token_endpoint_auth_method</td><td>true</td></tr><tr><td>tos_uri</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| OAuth2ProviderAppSecret<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>app_id</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>display_secret</td><td>false</td></tr><tr><td>hashed_secret</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>secret_prefix</td><td>false</td></tr></tbody></table> |
|
||||
| Organization<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>false</td></tr><tr><td>is_default</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>shareable_workspace_owners</td><td>true</td></tr><tr><td>updated_at</td><td>true</td></tr></tbody></table> |
|
||||
| OrganizationSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>assign_default</td><td>true</td></tr><tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| PrebuildsSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>id</td><td>false</td></tr><tr><td>reconciliation_paused</td><td>true</td></tr></tbody></table> |
|
||||
| RoleSyncSettings<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>field</td><td>true</td></tr><tr><td>mapping</td><td>true</td></tr></tbody></table> |
|
||||
| TaskTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>deleted_at</td><td>false</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>prompt</td><td>true</td></tr><tr><td>template_parameters</td><td>true</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>workspace_id</td><td>true</td></tr></tbody></table> |
|
||||
| Template<br><i>write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>abstract</td><td>true</td></tr><tr><td>active_version_id</td><td>true</td></tr><tr><td>activity_bump</td><td>true</td></tr><tr><td>allow_user_autostart</td><td>true</td></tr><tr><td>allow_user_autostop</td><td>true</td></tr><tr><td>allow_user_cancel_workspace_jobs</td><td>true</td></tr><tr><td>autostart_block_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_days_of_week</td><td>true</td></tr><tr><td>autostop_requirement_weeks</td><td>true</td></tr><tr><td>cors_behavior</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>default_ttl</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deprecated</td><td>true</td></tr><tr><td>description</td><td>true</td></tr><tr><td>disable_module_cache</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>failure_ttl</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>max_port_sharing_level</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_display_name</td><td>false</td></tr><tr><td>organization_icon</td><td>false</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>organization_name</td><td>false</td></tr><tr><td>provisioner</td><td>true</td></tr><tr><td>require_active_version</td><td>true</td></tr><tr><td>time_til_dormant</td><td>true</td></tr><tr><td>time_til_dormant_autodelete</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>use_classic_parameter_flow</td><td>true</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
| TemplateVersion<br><i>create, write</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>archived</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>created_by</td><td>true</td></tr><tr><td>created_by_avatar_url</td><td>false</td></tr><tr><td>created_by_name</td><td>false</td></tr><tr><td>created_by_username</td><td>false</td></tr><tr><td>external_auth_providers</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>true</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>message</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>readme</td><td>true</td></tr><tr><td>source_example_id</td><td>false</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr></tbody></table> |
|
||||
| User<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>avatar_url</td><td>false</td></tr><tr><td>chat_spend_limit_micros</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>true</td></tr><tr><td>email</td><td>true</td></tr><tr><td>github_com_user_id</td><td>false</td></tr><tr><td>hashed_one_time_passcode</td><td>false</td></tr><tr><td>hashed_password</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>is_service_account</td><td>true</td></tr><tr><td>is_system</td><td>true</td></tr><tr><td>last_seen_at</td><td>false</td></tr><tr><td>login_type</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>one_time_passcode_expires_at</td><td>true</td></tr><tr><td>quiet_hours_schedule</td><td>true</td></tr><tr><td>rbac_roles</td><td>true</td></tr><tr><td>status</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>username</td><td>true</td></tr></tbody></table> |
|
||||
| UserSecret<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>env_name</td><td>true</td></tr><tr><td>file_path</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr><tr><td>value</td><td>true</td></tr><tr><td>value_key_id</td><td>false</td></tr></tbody></table> |
|
||||
| UserSkill<br><i>create, write, delete</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>content</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>description</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_id</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceBuild<br><i>start, stop</i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>build_number</td><td>false</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>daily_cost</td><td>false</td></tr><tr><td>deadline</td><td>false</td></tr><tr><td>has_ai_task</td><td>false</td></tr><tr><td>has_external_agent</td><td>false</td></tr><tr><td>id</td><td>false</td></tr><tr><td>initiator_by_avatar_url</td><td>false</td></tr><tr><td>initiator_by_name</td><td>false</td></tr><tr><td>initiator_by_username</td><td>false</td></tr><tr><td>initiator_id</td><td>false</td></tr><tr><td>job_id</td><td>false</td></tr><tr><td>max_deadline</td><td>false</td></tr><tr><td>reason</td><td>false</td></tr><tr><td>template_version_id</td><td>true</td></tr><tr><td>template_version_preset_id</td><td>false</td></tr><tr><td>transition</td><td>false</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>workspace_id</td><td>false</td></tr></tbody></table> |
|
||||
| WorkspaceProxy<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>created_at</td><td>true</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>derp_enabled</td><td>true</td></tr><tr><td>derp_only</td><td>true</td></tr><tr><td>display_name</td><td>true</td></tr><tr><td>icon</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>name</td><td>true</td></tr><tr><td>region_id</td><td>true</td></tr><tr><td>token_hashed_secret</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>url</td><td>true</td></tr><tr><td>version</td><td>true</td></tr><tr><td>wildcard_hostname</td><td>true</td></tr></tbody></table> |
|
||||
| WorkspaceTable<br><i></i> | <table><thead><tr><th>Field</th><th>Tracked</th></tr></thead><tbody> | <tr><td>automatic_updates</td><td>true</td></tr><tr><td>autostart_schedule</td><td>true</td></tr><tr><td>created_at</td><td>false</td></tr><tr><td>deleted</td><td>false</td></tr><tr><td>deleting_at</td><td>true</td></tr><tr><td>dormant_at</td><td>true</td></tr><tr><td>favorite</td><td>true</td></tr><tr><td>group_acl</td><td>true</td></tr><tr><td>id</td><td>true</td></tr><tr><td>last_used_at</td><td>false</td></tr><tr><td>name</td><td>true</td></tr><tr><td>next_start_at</td><td>true</td></tr><tr><td>organization_id</td><td>false</td></tr><tr><td>owner_id</td><td>true</td></tr><tr><td>template_id</td><td>true</td></tr><tr><td>ttl</td><td>true</td></tr><tr><td>updated_at</td><td>false</td></tr><tr><td>user_acl</td><td>true</td></tr></tbody></table> |
|
||||
|
||||
<!-- End generated by 'make docs/admin/security/audit-logs.md'. -->
|
||||
|
||||
|
||||
Generated
+6
@@ -4876,6 +4876,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"activity_bump_ms": 0,
|
||||
"allow_user_autostart": true,
|
||||
"allow_user_autostop": true,
|
||||
@@ -4912,6 +4913,7 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|---------------------------------------|--------------------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `abstract` | string | false | | Abstract is a longer-form summary surfaced to agents to help them pick the right template. Up to 2048 characters. |
|
||||
| `activity_bump_ms` | integer | false | | Activity bump ms allows optionally specifying the activity bump duration for all workspaces created from this template. Defaults to 1h but can be set to 0 to disable activity bumping. |
|
||||
| `allow_user_autostart` | boolean | false | | Allow user autostart allows users to set a schedule for autostarting their workspace. By default this is true. This can only be disabled when using an enterprise license. |
|
||||
| `allow_user_autostop` | boolean | false | | Allow user autostop allows users to set a custom workspace TTL to use in place of the template's DefaultTTL field. By default this is true. If false, the DefaultTTL will always be used. This can only be disabled when using an enterprise license. |
|
||||
@@ -11969,6 +11971,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -12029,6 +12032,7 @@ Only certain features set these fields: - FeatureManagedAgentLimit|
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------|----------|--------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `abstract` | string | false | | Abstract is a longer-form summary surfaced to agents to help them pick the right template. Up to 2048 characters. |
|
||||
| `active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `active_version_id` | string | false | | |
|
||||
| `activity_bump_ms` | integer | false | | |
|
||||
@@ -13212,6 +13216,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"activity_bump_ms": 0,
|
||||
"allow_user_autostart": true,
|
||||
"allow_user_autostop": true,
|
||||
@@ -13251,6 +13256,7 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------|----------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `abstract` | string | false | | Abstract is a longer-form summary surfaced to agents to help them pick the right template. Up to 2048 characters. |
|
||||
| `activity_bump_ms` | integer | false | | Activity bump ms allows optionally specifying the activity bump duration for all workspaces created from this template. Defaults to 1h but can be set to 0 to disable activity bumping. |
|
||||
| `allow_user_autostart` | boolean | false | | |
|
||||
| `allow_user_autostop` | boolean | false | | |
|
||||
|
||||
Generated
+10
@@ -30,6 +30,7 @@ To include deprecated templates, specify `deprecated:true` in the search query.
|
||||
```json
|
||||
[
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -100,6 +101,7 @@ Status Code **200**
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|--------------------------------------|------------------------------------------------------------------------------------------|----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» abstract` | string | false | | Abstract is a longer-form summary surfaced to agents to help them pick the right template. Up to 2048 characters. |
|
||||
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `» active_version_id` | string(uuid) | false | | |
|
||||
| `» activity_bump_ms` | integer | false | | |
|
||||
@@ -171,6 +173,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"activity_bump_ms": 0,
|
||||
"allow_user_autostart": true,
|
||||
"allow_user_autostop": true,
|
||||
@@ -216,6 +219,7 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -368,6 +372,7 @@ curl -X GET http://coder-server:8080/api/v2/organizations/{organization}/templat
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -790,6 +795,7 @@ To include deprecated templates, specify `deprecated:true` in the search query.
|
||||
```json
|
||||
[
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -860,6 +866,7 @@ Status Code **200**
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|--------------------------------------|------------------------------------------------------------------------------------------|----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `[array item]` | array | false | | |
|
||||
| `» abstract` | string | false | | Abstract is a longer-form summary surfaced to agents to help them pick the right template. Up to 2048 characters. |
|
||||
| `» active_user_count` | integer | false | | Active user count is set to -1 when loading. |
|
||||
| `» active_version_id` | string(uuid) | false | | |
|
||||
| `» activity_bump_ms` | integer | false | | |
|
||||
@@ -994,6 +1001,7 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template} \
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
@@ -1120,6 +1128,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"activity_bump_ms": 0,
|
||||
"allow_user_autostart": true,
|
||||
"allow_user_autostop": true,
|
||||
@@ -1168,6 +1177,7 @@ curl -X PATCH http://coder-server:8080/api/v2/templates/{template} \
|
||||
|
||||
```json
|
||||
{
|
||||
"abstract": "string",
|
||||
"active_user_count": 0,
|
||||
"active_version_id": "eae64611-bd53-4a80-bb77-df1e432c0fbc",
|
||||
"activity_bump_ms": 0,
|
||||
|
||||
@@ -105,6 +105,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
|
||||
"provisioner": ActionTrack,
|
||||
"active_version_id": ActionTrack,
|
||||
"description": ActionTrack,
|
||||
"abstract": ActionTrack,
|
||||
"icon": ActionTrack,
|
||||
"default_ttl": ActionTrack,
|
||||
"autostart_block_days_of_week": ActionTrack,
|
||||
|
||||
Generated
+15
@@ -3476,6 +3476,11 @@ export interface CreateTemplateRequest {
|
||||
* less than 128 bytes.
|
||||
*/
|
||||
readonly description?: string;
|
||||
/**
|
||||
* Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
* the right template. Up to 2048 characters.
|
||||
*/
|
||||
readonly abstract?: string;
|
||||
/**
|
||||
* Icon is a relative path or external URL that specifies
|
||||
* an icon to be displayed in the dashboard.
|
||||
@@ -8025,6 +8030,11 @@ export interface Template {
|
||||
readonly active_user_count: number;
|
||||
readonly build_time_stats: TemplateBuildTimeStats;
|
||||
readonly description: string;
|
||||
/**
|
||||
* Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
* the right template. Up to 2048 characters.
|
||||
*/
|
||||
readonly abstract: string;
|
||||
readonly deprecated: boolean;
|
||||
readonly deprecation_message: string;
|
||||
readonly deleted: boolean;
|
||||
@@ -8841,6 +8851,11 @@ export interface UpdateTemplateMeta {
|
||||
readonly name?: string;
|
||||
readonly display_name?: string;
|
||||
readonly description?: string;
|
||||
/**
|
||||
* Abstract is a longer-form summary surfaced to agents to help them pick
|
||||
* the right template. Up to 2048 characters.
|
||||
*/
|
||||
readonly abstract?: string;
|
||||
readonly icon?: string;
|
||||
readonly default_ttl_ms?: number;
|
||||
/**
|
||||
|
||||
+17
@@ -38,6 +38,8 @@ import {
|
||||
|
||||
const MAX_DESCRIPTION_CHAR_LIMIT = 128;
|
||||
const MAX_DESCRIPTION_MESSAGE = `Please enter a description that is no longer than ${MAX_DESCRIPTION_CHAR_LIMIT} characters.`;
|
||||
const MAX_ABSTRACT_CHAR_LIMIT = 2048;
|
||||
const MAX_ABSTRACT_MESSAGE = `Please enter an abstract that is no longer than ${MAX_ABSTRACT_CHAR_LIMIT} characters.`;
|
||||
|
||||
export const validationSchema = Yup.object({
|
||||
name: nameValidator("Name"),
|
||||
@@ -46,6 +48,7 @@ export const validationSchema = Yup.object({
|
||||
MAX_DESCRIPTION_CHAR_LIMIT,
|
||||
MAX_DESCRIPTION_MESSAGE,
|
||||
),
|
||||
abstract: Yup.string().max(MAX_ABSTRACT_CHAR_LIMIT, MAX_ABSTRACT_MESSAGE),
|
||||
allow_user_cancel_workspace_jobs: Yup.boolean(),
|
||||
icon: iconValidator,
|
||||
require_active_version: Yup.boolean(),
|
||||
@@ -85,6 +88,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
name: template.name,
|
||||
display_name: template.display_name,
|
||||
description: template.description,
|
||||
abstract: template.abstract,
|
||||
icon: template.icon,
|
||||
allow_user_cancel_workspace_jobs:
|
||||
template.allow_user_cancel_workspace_jobs,
|
||||
@@ -148,6 +152,19 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
|
||||
rows={2}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...getFieldHelpers("abstract", {
|
||||
helperText:
|
||||
"Detailed summary for agents to help choose the right template.",
|
||||
maxLength: MAX_ABSTRACT_CHAR_LIMIT,
|
||||
})}
|
||||
multiline
|
||||
disabled={isSubmitting}
|
||||
fullWidth
|
||||
label="Abstract"
|
||||
rows={5}
|
||||
/>
|
||||
|
||||
<IconField
|
||||
{...getFieldHelpers("icon")}
|
||||
disabled={isSubmitting}
|
||||
|
||||
+28
@@ -27,6 +27,7 @@ const validFormValues: FormValues = {
|
||||
name: "Name",
|
||||
display_name: "A display name",
|
||||
description: "A description",
|
||||
abstract: "An agent-facing summary",
|
||||
icon: "vscode.png",
|
||||
allow_user_cancel_workspace_jobs: false,
|
||||
allow_user_autostart: false,
|
||||
@@ -74,6 +75,7 @@ const fillAndSubmitForm = async ({
|
||||
name,
|
||||
display_name,
|
||||
description,
|
||||
abstract,
|
||||
icon,
|
||||
allow_user_cancel_workspace_jobs,
|
||||
}: FormValues) => {
|
||||
@@ -89,6 +91,12 @@ const fillAndSubmitForm = async ({
|
||||
await userEvent.clear(descriptionField);
|
||||
await userEvent.type(descriptionField, description);
|
||||
|
||||
const abstractField = await screen.findByLabelText("Abstract");
|
||||
await userEvent.clear(abstractField);
|
||||
if (abstract !== "") {
|
||||
await userEvent.type(abstractField, abstract);
|
||||
}
|
||||
|
||||
const iconField = await screen.findByLabelText("Icon");
|
||||
await userEvent.clear(iconField);
|
||||
await userEvent.type(iconField, icon);
|
||||
@@ -118,6 +126,10 @@ describe("TemplateSettingsPage", { timeout: 20_000 }, () => {
|
||||
});
|
||||
await fillAndSubmitForm(validFormValues);
|
||||
await waitFor(() => expect(API.updateTemplateMeta).toBeCalledTimes(1));
|
||||
expect(API.updateTemplateMeta).toHaveBeenCalledWith(
|
||||
MockTemplate.id,
|
||||
expect.objectContaining({ abstract: validFormValues.abstract }),
|
||||
);
|
||||
});
|
||||
|
||||
it("displays an error if the name is taken", async () => {
|
||||
@@ -165,6 +177,22 @@ describe("TemplateSettingsPage", { timeout: 20_000 }, () => {
|
||||
expect(validate).toThrowError();
|
||||
});
|
||||
|
||||
it.each<[string, string, boolean]>([
|
||||
["allows the maximum abstract length", "a".repeat(2048), false],
|
||||
["rejects an over-limit abstract", "a".repeat(2049), true],
|
||||
])("%s", (_, abstract, wantError) => {
|
||||
const values: UpdateTemplateMeta = {
|
||||
...validFormValues,
|
||||
abstract,
|
||||
};
|
||||
const validate = () => validationSchema.validateSync(values);
|
||||
if (wantError) {
|
||||
expect(validate).toThrowError();
|
||||
} else {
|
||||
expect(validate).not.toThrowError();
|
||||
}
|
||||
});
|
||||
|
||||
describe("Deprecate template", () => {
|
||||
it("deprecates a template when has access control", async () => {
|
||||
server.use(
|
||||
|
||||
+10
@@ -57,3 +57,13 @@ export const NoEntitlementsExpiredSettings: Story = {
|
||||
advancedSchedulingEnabled: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithAbstract: Story = {
|
||||
args: {
|
||||
template: {
|
||||
...MockTemplate,
|
||||
abstract:
|
||||
"This template provisions a remote VS Code environment backed by a Kubernetes pod. Agents should prefer it when the user mentions Kubernetes, k8s, or remote development.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -894,6 +894,7 @@ export const MockTemplate: TypesGen.Template = {
|
||||
},
|
||||
},
|
||||
description: "This is a test description.",
|
||||
abstract: "",
|
||||
default_ttl_ms: 24 * 60 * 60 * 1000,
|
||||
activity_bump_ms: 1 * 60 * 60 * 1000,
|
||||
autostop_requirement: {
|
||||
|
||||
Reference in New Issue
Block a user