mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
feat: Updating workspace prompts new parameters (#2598)
This commit is contained in:
202
cli/create.go
202
cli/create.go
@ -120,87 +120,11 @@ func create() *cobra.Command {
|
|||||||
schedSpec = ptr.Ref(sched.String())
|
schedSpec = ptr.Ref(sched.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
templateVersion, err := client.TemplateVersion(cmd.Context(), template.ActiveVersionID)
|
parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{
|
||||||
if err != nil {
|
Template: template,
|
||||||
return err
|
ExistingParams: []codersdk.Parameter{},
|
||||||
}
|
ParameterFile: parameterFile,
|
||||||
parameterSchemas, err := client.TemplateVersionSchema(cmd.Context(), templateVersion.ID)
|
NewWorkspaceName: workspaceName,
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parameterMapFromFile can be nil if parameter file is not specified
|
|
||||||
var parameterMapFromFile map[string]string
|
|
||||||
if parameterFile != "" {
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("Attempting to read the variables from the parameter file.")+"\r\n")
|
|
||||||
parameterMapFromFile, err = createParameterMapFromFile(parameterFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disclaimerPrinted := false
|
|
||||||
parameters := make([]codersdk.CreateParameterRequest, 0)
|
|
||||||
for _, parameterSchema := range parameterSchemas {
|
|
||||||
if !parameterSchema.AllowOverrideSource {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !disclaimerPrinted {
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
|
|
||||||
disclaimerPrinted = true
|
|
||||||
}
|
|
||||||
parameterValue, err := getParameterValueFromMapOrInput(cmd, parameterMapFromFile, parameterSchema)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
parameters = append(parameters, codersdk.CreateParameterRequest{
|
|
||||||
Name: parameterSchema.Name,
|
|
||||||
SourceValue: parameterValue,
|
|
||||||
SourceScheme: codersdk.ParameterSourceSchemeData,
|
|
||||||
DestinationScheme: parameterSchema.DefaultDestinationScheme,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout())
|
|
||||||
|
|
||||||
// Run a dry-run with the given parameters to check correctness
|
|
||||||
after := time.Now()
|
|
||||||
dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{
|
|
||||||
WorkspaceName: workspaceName,
|
|
||||||
ParameterValues: parameters,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("begin workspace dry-run: %w", err)
|
|
||||||
}
|
|
||||||
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Planning workspace...")
|
|
||||||
err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{
|
|
||||||
Fetch: func() (codersdk.ProvisionerJob, error) {
|
|
||||||
return client.TemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID)
|
|
||||||
},
|
|
||||||
Cancel: func() error {
|
|
||||||
return client.CancelTemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID)
|
|
||||||
},
|
|
||||||
Logs: func() (<-chan codersdk.ProvisionerJobLog, error) {
|
|
||||||
return client.TemplateVersionDryRunLogsAfter(cmd.Context(), templateVersion.ID, dryRun.ID, after)
|
|
||||||
},
|
|
||||||
// Don't show log output for the dry-run unless there's an error.
|
|
||||||
Silent: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
// TODO (Dean): reprompt for parameter values if we deem it to
|
|
||||||
// be a validation error
|
|
||||||
return xerrors.Errorf("dry-run workspace: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resources, err := client.TemplateVersionDryRunResources(cmd.Context(), templateVersion.ID, dryRun.ID)
|
|
||||||
if err != nil {
|
|
||||||
return xerrors.Errorf("get workspace dry-run resources: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
|
|
||||||
WorkspaceName: workspaceName,
|
|
||||||
// Since agent's haven't connected yet, hiding this makes more sense.
|
|
||||||
HideAgentState: true,
|
|
||||||
Title: "Workspace Preview",
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -214,6 +138,7 @@ func create() *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
after := time.Now()
|
||||||
workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{
|
workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.CreateWorkspaceRequest{
|
||||||
TemplateID: template.ID,
|
TemplateID: template.ID,
|
||||||
Name: workspaceName,
|
Name: workspaceName,
|
||||||
@ -242,3 +167,118 @@ func create() *cobra.Command {
|
|||||||
cliflag.DurationVarP(cmd.Flags(), &stopAfter, "stop-after", "", "CODER_WORKSPACE_STOP_AFTER", 8*time.Hour, "Specify a duration after which the workspace should shut down (e.g. 8h).")
|
cliflag.DurationVarP(cmd.Flags(), &stopAfter, "stop-after", "", "CODER_WORKSPACE_STOP_AFTER", 8*time.Hour, "Specify a duration after which the workspace should shut down (e.g. 8h).")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type prepWorkspaceBuildArgs struct {
|
||||||
|
Template codersdk.Template
|
||||||
|
ExistingParams []codersdk.Parameter
|
||||||
|
ParameterFile string
|
||||||
|
NewWorkspaceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepWorkspaceBuild will ensure a workspace build will succeed on the latest template version.
|
||||||
|
// Any missing params will be prompted to the user.
|
||||||
|
func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) ([]codersdk.CreateParameterRequest, error) {
|
||||||
|
ctx := cmd.Context()
|
||||||
|
templateVersion, err := client.TemplateVersion(ctx, args.Template.ActiveVersionID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parameterSchemas, err := client.TemplateVersionSchema(ctx, templateVersion.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parameterMapFromFile can be nil if parameter file is not specified
|
||||||
|
var parameterMapFromFile map[string]string
|
||||||
|
useParamFile := false
|
||||||
|
if args.ParameterFile != "" {
|
||||||
|
useParamFile = true
|
||||||
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("Attempting to read the variables from the parameter file.")+"\r\n")
|
||||||
|
parameterMapFromFile, err = createParameterMapFromFile(args.ParameterFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disclaimerPrinted := false
|
||||||
|
parameters := make([]codersdk.CreateParameterRequest, 0)
|
||||||
|
PromptParamLoop:
|
||||||
|
for _, parameterSchema := range parameterSchemas {
|
||||||
|
if !parameterSchema.AllowOverrideSource {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !disclaimerPrinted {
|
||||||
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n")
|
||||||
|
disclaimerPrinted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param file is all or nothing
|
||||||
|
if !useParamFile {
|
||||||
|
for _, e := range args.ExistingParams {
|
||||||
|
if e.Name == parameterSchema.Name {
|
||||||
|
// If the param already exists, we do not need to prompt it again.
|
||||||
|
// The workspace scope will reuse params for each build.
|
||||||
|
continue PromptParamLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parameterValue, err := getParameterValueFromMapOrInput(cmd, parameterMapFromFile, parameterSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters = append(parameters, codersdk.CreateParameterRequest{
|
||||||
|
Name: parameterSchema.Name,
|
||||||
|
SourceValue: parameterValue,
|
||||||
|
SourceScheme: codersdk.ParameterSourceSchemeData,
|
||||||
|
DestinationScheme: parameterSchema.DefaultDestinationScheme,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintln(cmd.OutOrStdout())
|
||||||
|
|
||||||
|
// Run a dry-run with the given parameters to check correctness
|
||||||
|
after := time.Now()
|
||||||
|
dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{
|
||||||
|
WorkspaceName: args.NewWorkspaceName,
|
||||||
|
ParameterValues: parameters,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("begin workspace dry-run: %w", err)
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Planning workspace...")
|
||||||
|
err = cliui.ProvisionerJob(cmd.Context(), cmd.OutOrStdout(), cliui.ProvisionerJobOptions{
|
||||||
|
Fetch: func() (codersdk.ProvisionerJob, error) {
|
||||||
|
return client.TemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID)
|
||||||
|
},
|
||||||
|
Cancel: func() error {
|
||||||
|
return client.CancelTemplateVersionDryRun(cmd.Context(), templateVersion.ID, dryRun.ID)
|
||||||
|
},
|
||||||
|
Logs: func() (<-chan codersdk.ProvisionerJobLog, error) {
|
||||||
|
return client.TemplateVersionDryRunLogsAfter(cmd.Context(), templateVersion.ID, dryRun.ID, after)
|
||||||
|
},
|
||||||
|
// Don't show log output for the dry-run unless there's an error.
|
||||||
|
Silent: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// TODO (Dean): reprompt for parameter values if we deem it to
|
||||||
|
// be a validation error
|
||||||
|
return nil, xerrors.Errorf("dry-run workspace: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resources, err := client.TemplateVersionDryRunResources(cmd.Context(), templateVersion.ID, dryRun.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("get workspace dry-run resources: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cliui.WorkspaceResources(cmd.OutOrStdout(), resources, cliui.WorkspaceResourcesOptions{
|
||||||
|
WorkspaceName: args.NewWorkspaceName,
|
||||||
|
// Since agents haven't connected yet, hiding this makes more sense.
|
||||||
|
HideAgentState: true,
|
||||||
|
Title: "Workspace Preview",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters, nil
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
func delete() *cobra.Command {
|
func deleteWorkspace() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Annotations: workspaceCommand,
|
Annotations: workspaceCommand,
|
||||||
Use: "delete <workspace>",
|
Use: "delete <workspace>",
|
||||||
|
@ -69,7 +69,7 @@ func Root() *cobra.Command {
|
|||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
configSSH(),
|
configSSH(),
|
||||||
create(),
|
create(),
|
||||||
delete(),
|
deleteWorkspace(),
|
||||||
dotfiles(),
|
dotfiles(),
|
||||||
gitssh(),
|
gitssh(),
|
||||||
list(),
|
list(),
|
||||||
|
@ -6,11 +6,17 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/coder/coder/cli/cliflag"
|
||||||
"github.com/coder/coder/codersdk"
|
"github.com/coder/coder/codersdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func update() *cobra.Command {
|
func update() *cobra.Command {
|
||||||
return &cobra.Command{
|
var (
|
||||||
|
parameterFile string
|
||||||
|
alwaysPrompt bool
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
Annotations: workspaceCommand,
|
Annotations: workspaceCommand,
|
||||||
Use: "update",
|
Use: "update",
|
||||||
Short: "Update a workspace to the latest template version",
|
Short: "Update a workspace to the latest template version",
|
||||||
@ -23,7 +29,7 @@ func update() *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !workspace.Outdated {
|
if !workspace.Outdated && !alwaysPrompt {
|
||||||
_, _ = fmt.Printf("Workspace isn't outdated!\n")
|
_, _ = fmt.Printf("Workspace isn't outdated!\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -31,10 +37,30 @@ func update() *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var existingParams []codersdk.Parameter
|
||||||
|
if !alwaysPrompt {
|
||||||
|
existingParams, err = client.Parameters(cmd.Context(), codersdk.ParameterWorkspace, workspace.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{
|
||||||
|
Template: template,
|
||||||
|
ExistingParams: existingParams,
|
||||||
|
ParameterFile: parameterFile,
|
||||||
|
NewWorkspaceName: workspace.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{
|
||||||
TemplateVersionID: template.ActiveVersionID,
|
TemplateVersionID: template.ActiveVersionID,
|
||||||
Transition: workspace.LatestBuild.Transition,
|
Transition: workspace.LatestBuild.Transition,
|
||||||
|
ParameterValues: parameters,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -53,4 +79,8 @@ func update() *cobra.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().BoolVar(&alwaysPrompt, "always-prompt", false, "Always prompt all parameters. Does not pull parameter values from existing workspace")
|
||||||
|
cliflag.StringVarP(cmd.Flags(), ¶meterFile, "parameter-file", "", "CODER_PARAMETER_FILE", "", "Specify a file path with parameter values.")
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -400,6 +400,43 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
|
|||||||
// This must happen in a transaction to ensure history can be inserted, and
|
// This must happen in a transaction to ensure history can be inserted, and
|
||||||
// the prior history can update it's "after" column to point at the new.
|
// the prior history can update it's "after" column to point at the new.
|
||||||
err = api.Database.InTx(func(db database.Store) error {
|
err = api.Database.InTx(func(db database.Store) error {
|
||||||
|
existing, err := db.ParameterValues(r.Context(), database.ParameterValuesParams{
|
||||||
|
Scopes: []database.ParameterScope{database.ParameterScopeWorkspace},
|
||||||
|
ScopeIds: []uuid.UUID{workspace.ID},
|
||||||
|
})
|
||||||
|
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
|
||||||
|
return xerrors.Errorf("Fetch previous parameters: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write/Update any new params
|
||||||
|
now := database.Now()
|
||||||
|
for _, param := range createBuild.ParameterValues {
|
||||||
|
for _, exists := range existing {
|
||||||
|
// If the param exists, delete the old param before inserting the new one
|
||||||
|
if exists.Name == param.Name {
|
||||||
|
err = db.DeleteParameterValueByID(r.Context(), exists.ID)
|
||||||
|
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
|
||||||
|
return xerrors.Errorf("Failed to delete old param %q: %w", exists.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.InsertParameterValue(r.Context(), database.InsertParameterValueParams{
|
||||||
|
ID: uuid.New(),
|
||||||
|
Name: param.Name,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
Scope: database.ParameterScopeWorkspace,
|
||||||
|
ScopeID: workspace.ID,
|
||||||
|
SourceScheme: database.ParameterSourceScheme(param.SourceScheme),
|
||||||
|
SourceValue: param.SourceValue,
|
||||||
|
DestinationScheme: database.ParameterDestinationScheme(param.DestinationScheme),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("insert parameter value: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
workspaceBuildID := uuid.New()
|
workspaceBuildID := uuid.New()
|
||||||
input, err := json.Marshal(workspaceProvisionJob{
|
input, err := json.Marshal(workspaceProvisionJob{
|
||||||
WorkspaceBuildID: workspaceBuildID,
|
WorkspaceBuildID: workspaceBuildID,
|
||||||
|
@ -37,6 +37,10 @@ type CreateWorkspaceBuildRequest struct {
|
|||||||
Transition WorkspaceTransition `json:"transition" validate:"oneof=create start stop delete,required"`
|
Transition WorkspaceTransition `json:"transition" validate:"oneof=create start stop delete,required"`
|
||||||
DryRun bool `json:"dry_run,omitempty"`
|
DryRun bool `json:"dry_run,omitempty"`
|
||||||
ProvisionerState []byte `json:"state,omitempty"`
|
ProvisionerState []byte `json:"state,omitempty"`
|
||||||
|
// ParameterValues are optional. It will write params to the 'workspace' scope.
|
||||||
|
// This will overwrite any existing parameters with the same name.
|
||||||
|
// This will not delete old params not included in this list.
|
||||||
|
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkspaceOptions struct {
|
type WorkspaceOptions struct {
|
||||||
|
@ -104,6 +104,7 @@ export interface CreateWorkspaceBuildRequest {
|
|||||||
readonly transition: WorkspaceTransition
|
readonly transition: WorkspaceTransition
|
||||||
readonly dry_run?: boolean
|
readonly dry_run?: boolean
|
||||||
readonly state?: string
|
readonly state?: string
|
||||||
|
readonly parameter_values?: CreateParameterRequest[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/organizations.go:76:6
|
// From codersdk/organizations.go:76:6
|
||||||
@ -232,7 +233,7 @@ export interface ProvisionerJobLog {
|
|||||||
readonly output: string
|
readonly output: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:202:6
|
// From codersdk/workspaces.go:206:6
|
||||||
export interface PutExtendWorkspaceRequest {
|
export interface PutExtendWorkspaceRequest {
|
||||||
readonly deadline: string
|
readonly deadline: string
|
||||||
}
|
}
|
||||||
@ -305,12 +306,12 @@ export interface UpdateUserProfileRequest {
|
|||||||
readonly username: string
|
readonly username: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:161:6
|
// From codersdk/workspaces.go:165:6
|
||||||
export interface UpdateWorkspaceAutostartRequest {
|
export interface UpdateWorkspaceAutostartRequest {
|
||||||
readonly schedule?: string
|
readonly schedule?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:181:6
|
// From codersdk/workspaces.go:185:6
|
||||||
export interface UpdateWorkspaceTTLRequest {
|
export interface UpdateWorkspaceTTLRequest {
|
||||||
readonly ttl_ms?: number
|
readonly ttl_ms?: number
|
||||||
}
|
}
|
||||||
@ -464,17 +465,17 @@ export interface WorkspaceBuild {
|
|||||||
readonly reason: BuildReason
|
readonly reason: BuildReason
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:84:6
|
// From codersdk/workspaces.go:88:6
|
||||||
export interface WorkspaceBuildsRequest extends Pagination {
|
export interface WorkspaceBuildsRequest extends Pagination {
|
||||||
readonly WorkspaceID: string
|
readonly WorkspaceID: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:220:6
|
// From codersdk/workspaces.go:224:6
|
||||||
export interface WorkspaceFilter {
|
export interface WorkspaceFilter {
|
||||||
readonly q?: string
|
readonly q?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// From codersdk/workspaces.go:42:6
|
// From codersdk/workspaces.go:46:6
|
||||||
export interface WorkspaceOptions {
|
export interface WorkspaceOptions {
|
||||||
readonly include_deleted?: boolean
|
readonly include_deleted?: boolean
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user