From 5130f093aa442daf05b2fec98a5be7345df8ffd5 Mon Sep 17 00:00:00 2001 From: Ivan Dagelic Date: Fri, 18 Oct 2024 16:43:37 +0200 Subject: [PATCH] feat: set default target (#1269) BREAKING CHANGE: provider interface has been changed so they need to be updated. Signed-off-by: Ivan Dagelic --- docs/daytona_git-providers_delete.md | 1 + docs/daytona_target.md | 1 + docs/daytona_target_set-default.md | 18 ++ hack/docs/daytona_git-providers_delete.yaml | 4 + hack/docs/daytona_target.yaml | 1 + hack/docs/daytona_target_set-default.yaml | 9 + internal/testing/provider/targets/store.go | 54 ++++- internal/util/apiclient/conversion/target.go | 17 ++ pkg/api/controllers/target/list.go | 2 +- pkg/api/controllers/target/remove.go | 5 +- pkg/api/controllers/target/set.go | 46 +++- pkg/api/docs/docs.go | 49 +++- pkg/api/docs/swagger.json | 49 +++- pkg/api/docs/swagger.yaml | 34 ++- pkg/api/server.go | 1 + pkg/apiclient/README.md | 2 + pkg/apiclient/api/openapi.yaml | 44 +++- pkg/apiclient/api_target.go | 110 ++++++++- pkg/apiclient/docs/CreateProviderTargetDTO.md | 93 ++++++++ pkg/apiclient/docs/ProviderTarget.md | 23 +- pkg/apiclient/docs/TargetAPI.md | 73 +++++- .../model_create_provider_target_dto.go | 212 ++++++++++++++++++ pkg/apiclient/model_provider_target.go | 32 ++- pkg/cmd/cmd.go | 1 + pkg/cmd/provider/install.go | 2 +- pkg/cmd/target/remove.go | 2 +- pkg/cmd/target/set.go | 6 +- pkg/cmd/target/setdefault.go | 73 ++++++ pkg/cmd/target/target.go | 1 + pkg/cmd/workspace/create.go | 15 +- pkg/cmd/workspace/util/get_target.go | 41 +++- pkg/db/dto/provider_target.go | 5 +- pkg/db/provider_target_store.go | 37 ++- pkg/provider/manager/manager.go | 10 +- pkg/provider/provider.go | 2 +- pkg/provider/rpc_client.go | 4 +- pkg/provider/rpc_server.go | 4 +- pkg/provider/store.go | 10 +- pkg/provider/types.go | 3 +- .../providertargets/dto/providertargets.go | 12 + pkg/server/providertargets/service.go | 54 ++++- pkg/server/providertargets/service_test.go | 24 +- pkg/server/workspaces/create.go | 2 +- pkg/server/workspaces/get.go | 3 +- pkg/server/workspaces/list.go | 3 +- pkg/server/workspaces/remove.go | 5 +- pkg/server/workspaces/service.go | 2 +- pkg/server/workspaces/start.go | 4 +- pkg/server/workspaces/stop.go | 5 +- pkg/views/projectconfig/list/view.go | 11 +- pkg/views/target/list/view.go | 23 +- pkg/views/target/select.go | 10 +- pkg/views/target/view.go | 10 +- 53 files changed, 1144 insertions(+), 120 deletions(-) create mode 100644 docs/daytona_target_set-default.md create mode 100644 hack/docs/daytona_target_set-default.yaml create mode 100644 internal/util/apiclient/conversion/target.go create mode 100644 pkg/apiclient/docs/CreateProviderTargetDTO.md create mode 100644 pkg/apiclient/model_create_provider_target_dto.go create mode 100644 pkg/cmd/target/setdefault.go create mode 100644 pkg/server/providertargets/dto/providertargets.go diff --git a/docs/daytona_git-providers_delete.md b/docs/daytona_git-providers_delete.md index d1a58999db..ab7a22aa23 100644 --- a/docs/daytona_git-providers_delete.md +++ b/docs/daytona_git-providers_delete.md @@ -10,6 +10,7 @@ daytona git-providers delete [flags] ``` -a, --all Remove all Git providers + -y, --yes Confirm deletion without prompt ``` ### Options inherited from parent commands diff --git a/docs/daytona_target.md b/docs/daytona_target.md index ef81ee4dbf..32b4b9f7f3 100644 --- a/docs/daytona_target.md +++ b/docs/daytona_target.md @@ -14,4 +14,5 @@ Manage provider targets * [daytona target list](daytona_target_list.md) - List targets * [daytona target remove](daytona_target_remove.md) - Remove target * [daytona target set](daytona_target_set.md) - Set provider target +* [daytona target set-default](daytona_target_set-default.md) - Set target to be used by default diff --git a/docs/daytona_target_set-default.md b/docs/daytona_target_set-default.md new file mode 100644 index 0000000000..d37fb3155c --- /dev/null +++ b/docs/daytona_target_set-default.md @@ -0,0 +1,18 @@ +## daytona target set-default + +Set target to be used by default + +``` +daytona target set-default [TARGET_NAME] [flags] +``` + +### Options inherited from parent commands + +``` + --help help for daytona +``` + +### SEE ALSO + +* [daytona target](daytona_target.md) - Manage provider targets + diff --git a/hack/docs/daytona_git-providers_delete.yaml b/hack/docs/daytona_git-providers_delete.yaml index 849bc2bb9d..95d0109933 100644 --- a/hack/docs/daytona_git-providers_delete.yaml +++ b/hack/docs/daytona_git-providers_delete.yaml @@ -6,6 +6,10 @@ options: shorthand: a default_value: "false" usage: Remove all Git providers + - name: "yes" + shorthand: "y" + default_value: "false" + usage: Confirm deletion without prompt inherited_options: - name: help default_value: "false" diff --git a/hack/docs/daytona_target.yaml b/hack/docs/daytona_target.yaml index 3549650232..92ce570824 100644 --- a/hack/docs/daytona_target.yaml +++ b/hack/docs/daytona_target.yaml @@ -9,3 +9,4 @@ see_also: - daytona target list - List targets - daytona target remove - Remove target - daytona target set - Set provider target + - daytona target set-default - Set target to be used by default diff --git a/hack/docs/daytona_target_set-default.yaml b/hack/docs/daytona_target_set-default.yaml new file mode 100644 index 0000000000..138758fbd2 --- /dev/null +++ b/hack/docs/daytona_target_set-default.yaml @@ -0,0 +1,9 @@ +name: daytona target set-default +synopsis: Set target to be used by default +usage: daytona target set-default [TARGET_NAME] [flags] +inherited_options: + - name: help + default_value: "false" + usage: help for daytona +see_also: + - daytona target - Manage provider targets diff --git a/internal/testing/provider/targets/store.go b/internal/testing/provider/targets/store.go index 1539e0693b..160089e340 100644 --- a/internal/testing/provider/targets/store.go +++ b/internal/testing/provider/targets/store.go @@ -6,6 +6,8 @@ package targets import ( + "fmt" + "github.com/daytonaio/daytona/pkg/provider" ) @@ -19,22 +21,20 @@ func NewInMemoryTargetStore() provider.TargetStore { } } -func (s *InMemoryTargetStore) List() ([]*provider.ProviderTarget, error) { - targets := []*provider.ProviderTarget{} - for _, t := range s.targets { - targets = append(targets, t) - } - - return targets, nil +func (s *InMemoryTargetStore) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { + return s.processFilters(filter) } -func (s *InMemoryTargetStore) Find(targetName string) (*provider.ProviderTarget, error) { - target, ok := s.targets[targetName] - if !ok { +func (s *InMemoryTargetStore) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { + targets, err := s.processFilters(filter) + if err != nil { + return nil, err + } + if len(targets) == 0 { return nil, provider.ErrTargetNotFound } - return target, nil + return targets[0], nil } func (s *InMemoryTargetStore) Save(target *provider.ProviderTarget) error { @@ -46,3 +46,35 @@ func (s *InMemoryTargetStore) Delete(target *provider.ProviderTarget) error { delete(s.targets, target.Name) return nil } + +func (s *InMemoryTargetStore) processFilters(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { + var result []*provider.ProviderTarget + filteredTargets := make(map[string]*provider.ProviderTarget) + for k, v := range s.targets { + filteredTargets[k] = v + } + + if filter != nil { + if filter.Name != nil { + target, ok := s.targets[*filter.Name] + if ok { + return []*provider.ProviderTarget{target}, nil + } else { + return []*provider.ProviderTarget{}, fmt.Errorf("target with name %s not found", *filter.Name) + } + } + if filter.Default != nil { + for _, target := range filteredTargets { + if target.IsDefault != *filter.Default { + delete(filteredTargets, target.Name) + } + } + } + } + + for _, target := range filteredTargets { + result = append(result, target) + } + + return result, nil +} diff --git a/internal/util/apiclient/conversion/target.go b/internal/util/apiclient/conversion/target.go new file mode 100644 index 0000000000..2ad2ba2f33 --- /dev/null +++ b/internal/util/apiclient/conversion/target.go @@ -0,0 +1,17 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package conversion + +import ( + "github.com/daytonaio/daytona/pkg/provider" + "github.com/daytonaio/daytona/pkg/server/providertargets/dto" +) + +func ToProviderTarget(createProviderTargetDto dto.CreateProviderTargetDTO) *provider.ProviderTarget { + return &provider.ProviderTarget{ + Name: createProviderTargetDto.Name, + ProviderInfo: createProviderTargetDto.ProviderInfo, + Options: createProviderTargetDto.Options, + } +} diff --git a/pkg/api/controllers/target/list.go b/pkg/api/controllers/target/list.go index 40971e78f4..d60a913125 100644 --- a/pkg/api/controllers/target/list.go +++ b/pkg/api/controllers/target/list.go @@ -24,7 +24,7 @@ import ( func ListTargets(ctx *gin.Context) { server := server.GetInstance(nil) - targets, err := server.ProviderTargetService.List() + targets, err := server.ProviderTargetService.List(nil) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to list targets: %w", err)) return diff --git a/pkg/api/controllers/target/remove.go b/pkg/api/controllers/target/remove.go index 558852ff10..dcf61ea6ce 100644 --- a/pkg/api/controllers/target/remove.go +++ b/pkg/api/controllers/target/remove.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" + "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/server" "github.com/gin-gonic/gin" ) @@ -26,7 +27,9 @@ func RemoveTarget(ctx *gin.Context) { server := server.GetInstance(nil) - target, err := server.ProviderTargetService.Find(targetName) + target, err := server.ProviderTargetService.Find(&provider.TargetFilter{ + Name: &targetName, + }) if err != nil { ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find target: %w", err)) return diff --git a/pkg/api/controllers/target/set.go b/pkg/api/controllers/target/set.go index 9d698ab4b7..93b681f23e 100644 --- a/pkg/api/controllers/target/set.go +++ b/pkg/api/controllers/target/set.go @@ -7,8 +7,10 @@ import ( "fmt" "net/http" + "github.com/daytonaio/daytona/internal/util/apiclient/conversion" "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/server" + "github.com/daytonaio/daytona/pkg/server/providertargets/dto" "github.com/gin-gonic/gin" ) @@ -17,13 +19,13 @@ import ( // @Tags target // @Summary Set a target // @Description Set a target -// @Param target body ProviderTarget true "Target to set" +// @Param target body CreateProviderTargetDTO true "Target to set" // @Success 201 // @Router /target [put] // // @id SetTarget func SetTarget(ctx *gin.Context) { - var req provider.ProviderTarget + var req dto.CreateProviderTargetDTO err := ctx.BindJSON(&req) if err != nil { ctx.AbortWithError(http.StatusBadRequest, fmt.Errorf("invalid request body: %w", err)) @@ -32,13 +34,7 @@ func SetTarget(ctx *gin.Context) { server := server.GetInstance(nil) - target, err := server.ProviderTargetService.Find(req.Name) - if err == nil { - target.Options = req.Options - target.ProviderInfo = req.ProviderInfo - } else { - target = &req - } + target := conversion.ToProviderTarget(req) err = server.ProviderTargetService.Save(target) if err != nil { @@ -48,3 +44,35 @@ func SetTarget(ctx *gin.Context) { ctx.Status(201) } + +// SetDefaultTarget godoc +// +// @Tags target +// @Summary Set target to default +// @Description Set target to default +// @Param target path string true "Target name" +// @Success 200 +// @Router /target/{target}/set-default [patch] +// +// @id SetDefaultTarget +func SetDefaultTarget(ctx *gin.Context) { + targetName := ctx.Param("target") + + server := server.GetInstance(nil) + + target, err := server.ProviderTargetService.Find(&provider.TargetFilter{ + Name: &targetName, + }) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to find target: %w", err)) + return + } + + err = server.ProviderTargetService.SetDefault(target) + if err != nil { + ctx.AbortWithError(http.StatusNotFound, fmt.Errorf("failed to set project config to default: %s", err.Error())) + return + } + + ctx.Status(200) +} diff --git a/pkg/api/docs/docs.go b/pkg/api/docs/docs.go index 1a6420214a..4da6f466a7 100644 --- a/pkg/api/docs/docs.go +++ b/pkg/api/docs/docs.go @@ -1522,7 +1522,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ProviderTarget" + "$ref": "#/definitions/CreateProviderTargetDTO" } } ], @@ -1557,6 +1557,30 @@ const docTemplate = `{ } } }, + "/target/{target}/set-default": { + "patch": { + "description": "Set target to default", + "tags": [ + "target" + ], + "summary": "Set target to default", + "operationId": "SetDefaultTarget", + "parameters": [ + { + "type": "string", + "description": "Target name", + "name": "target", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/workspace": { "get": { "description": "List workspaces", @@ -2107,6 +2131,25 @@ const docTemplate = `{ } } }, + "CreateProviderTargetDTO": { + "type": "object", + "required": [ + "name", + "options", + "providerInfo" + ], + "properties": { + "name": { + "type": "string" + }, + "options": { + "type": "string" + }, + "providerInfo": { + "$ref": "#/definitions/provider.ProviderInfo" + } + } + }, "CreateWorkspaceDTO": { "type": "object", "required": [ @@ -2680,11 +2723,15 @@ const docTemplate = `{ "ProviderTarget": { "type": "object", "required": [ + "isDefault", "name", "options", "providerInfo" ], "properties": { + "isDefault": { + "type": "boolean" + }, "name": { "type": "string" }, diff --git a/pkg/api/docs/swagger.json b/pkg/api/docs/swagger.json index 16b10e422d..96e17c2048 100644 --- a/pkg/api/docs/swagger.json +++ b/pkg/api/docs/swagger.json @@ -1519,7 +1519,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/ProviderTarget" + "$ref": "#/definitions/CreateProviderTargetDTO" } } ], @@ -1554,6 +1554,30 @@ } } }, + "/target/{target}/set-default": { + "patch": { + "description": "Set target to default", + "tags": [ + "target" + ], + "summary": "Set target to default", + "operationId": "SetDefaultTarget", + "parameters": [ + { + "type": "string", + "description": "Target name", + "name": "target", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/workspace": { "get": { "description": "List workspaces", @@ -2104,6 +2128,25 @@ } } }, + "CreateProviderTargetDTO": { + "type": "object", + "required": [ + "name", + "options", + "providerInfo" + ], + "properties": { + "name": { + "type": "string" + }, + "options": { + "type": "string" + }, + "providerInfo": { + "$ref": "#/definitions/provider.ProviderInfo" + } + } + }, "CreateWorkspaceDTO": { "type": "object", "required": [ @@ -2677,11 +2720,15 @@ "ProviderTarget": { "type": "object", "required": [ + "isDefault", "name", "options", "providerInfo" ], "properties": { + "isDefault": { + "type": "boolean" + }, "name": { "type": "string" }, diff --git a/pkg/api/docs/swagger.yaml b/pkg/api/docs/swagger.yaml index 9c15a45ad6..2a8ad5ccb5 100644 --- a/pkg/api/docs/swagger.yaml +++ b/pkg/api/docs/swagger.yaml @@ -185,6 +185,19 @@ definitions: required: - repository type: object + CreateProviderTargetDTO: + properties: + name: + type: string + options: + type: string + providerInfo: + $ref: '#/definitions/provider.ProviderInfo' + required: + - name + - options + - providerInfo + type: object CreateWorkspaceDTO: properties: id: @@ -578,6 +591,8 @@ definitions: type: object ProviderTarget: properties: + isDefault: + type: boolean name: type: string options: @@ -586,6 +601,7 @@ definitions: providerInfo: $ref: '#/definitions/provider.ProviderInfo' required: + - isDefault - name - options - providerInfo @@ -1883,7 +1899,7 @@ paths: name: target required: true schema: - $ref: '#/definitions/ProviderTarget' + $ref: '#/definitions/CreateProviderTargetDTO' responses: "201": description: Created @@ -1906,6 +1922,22 @@ paths: summary: Remove a target tags: - target + /target/{target}/set-default: + patch: + description: Set target to default + operationId: SetDefaultTarget + parameters: + - description: Target name + in: path + name: target + required: true + type: string + responses: + "200": + description: OK + summary: Set target to default + tags: + - target /workspace: get: description: List workspaces diff --git a/pkg/api/server.go b/pkg/api/server.go index cb66be76d2..e58fa606aa 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -208,6 +208,7 @@ func (a *ApiServer) Start() error { { targetController.GET("/", target.ListTargets) targetController.PUT("/", target.SetTarget) + targetController.PATCH("/:target/set-default", target.SetDefaultTarget) targetController.DELETE("/:target", target.RemoveTarget) } diff --git a/pkg/apiclient/README.md b/pkg/apiclient/README.md index 5c2e1633f7..5ba3d8f89c 100644 --- a/pkg/apiclient/README.md +++ b/pkg/apiclient/README.md @@ -129,6 +129,7 @@ Class | Method | HTTP request | Description *ServerAPI* | [**SetConfig**](docs/ServerAPI.md#setconfig) | **Post** /server/config | Set the server configuration *TargetAPI* | [**ListTargets**](docs/TargetAPI.md#listtargets) | **Get** /target | List targets *TargetAPI* | [**RemoveTarget**](docs/TargetAPI.md#removetarget) | **Delete** /target/{target} | Remove a target +*TargetAPI* | [**SetDefaultTarget**](docs/TargetAPI.md#setdefaulttarget) | **Patch** /target/{target}/set-default | Set target to default *TargetAPI* | [**SetTarget**](docs/TargetAPI.md#settarget) | **Put** /target | Set a target *WorkspaceAPI* | [**CreateWorkspace**](docs/WorkspaceAPI.md#createworkspace) | **Post** /workspace | Create a workspace *WorkspaceAPI* | [**GetWorkspace**](docs/WorkspaceAPI.md#getworkspace) | **Get** /workspace/{workspaceId} | Get workspace info @@ -157,6 +158,7 @@ Class | Method | HTTP request | Description - [CreateProjectConfigDTO](docs/CreateProjectConfigDTO.md) - [CreateProjectDTO](docs/CreateProjectDTO.md) - [CreateProjectSourceDTO](docs/CreateProjectSourceDTO.md) + - [CreateProviderTargetDTO](docs/CreateProviderTargetDTO.md) - [CreateWorkspaceDTO](docs/CreateWorkspaceDTO.md) - [DevcontainerConfig](docs/DevcontainerConfig.md) - [FRPSConfig](docs/FRPSConfig.md) diff --git a/pkg/apiclient/api/openapi.yaml b/pkg/apiclient/api/openapi.yaml index 8db9bbd616..e04f42f998 100644 --- a/pkg/apiclient/api/openapi.yaml +++ b/pkg/apiclient/api/openapi.yaml @@ -1079,7 +1079,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/ProviderTarget' + $ref: '#/components/schemas/CreateProviderTargetDTO' description: Target to set required: true responses: @@ -1108,6 +1108,24 @@ paths: summary: Remove a target tags: - target + /target/{target}/set-default: + patch: + description: Set target to default + operationId: SetDefaultTarget + parameters: + - description: Target name + in: path + name: target + required: true + schema: + type: string + responses: + "200": + content: {} + description: OK + summary: Set target to default + tags: + - target /workspace: get: description: List workspaces @@ -1617,6 +1635,26 @@ components: required: - repository type: object + CreateProviderTargetDTO: + example: + name: name + options: options + providerInfo: + name: name + label: label + version: version + properties: + name: + type: string + options: + type: string + providerInfo: + $ref: '#/components/schemas/provider.ProviderInfo' + required: + - name + - options + - providerInfo + type: object CreateWorkspaceDTO: example: projects: @@ -2263,6 +2301,7 @@ components: type: object ProviderTarget: example: + isDefault: true name: name options: options providerInfo: @@ -2270,6 +2309,8 @@ components: label: label version: version properties: + isDefault: + type: boolean name: type: string options: @@ -2278,6 +2319,7 @@ components: providerInfo: $ref: '#/components/schemas/provider.ProviderInfo' required: + - isDefault - name - options - providerInfo diff --git a/pkg/apiclient/api_target.go b/pkg/apiclient/api_target.go index 143c5ce7da..09ace864e4 100644 --- a/pkg/apiclient/api_target.go +++ b/pkg/apiclient/api_target.go @@ -242,14 +242,120 @@ func (a *TargetAPIService) RemoveTargetExecute(r ApiRemoveTargetRequest) (*http. return localVarHTTPResponse, nil } +type ApiSetDefaultTargetRequest struct { + ctx context.Context + ApiService *TargetAPIService + target string +} + +func (r ApiSetDefaultTargetRequest) Execute() (*http.Response, error) { + return r.ApiService.SetDefaultTargetExecute(r) +} + +/* +SetDefaultTarget Set target to default + +Set target to default + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param target Target name + @return ApiSetDefaultTargetRequest +*/ +func (a *TargetAPIService) SetDefaultTarget(ctx context.Context, target string) ApiSetDefaultTargetRequest { + return ApiSetDefaultTargetRequest{ + ApiService: a, + ctx: ctx, + target: target, + } +} + +// Execute executes the request +func (a *TargetAPIService) SetDefaultTargetExecute(r ApiSetDefaultTargetRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPatch + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "TargetAPIService.SetDefaultTarget") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/target/{target}/set-default" + localVarPath = strings.Replace(localVarPath, "{"+"target"+"}", url.PathEscape(parameterValueToString(r.target, "target")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + type ApiSetTargetRequest struct { ctx context.Context ApiService *TargetAPIService - target *ProviderTarget + target *CreateProviderTargetDTO } // Target to set -func (r ApiSetTargetRequest) Target(target ProviderTarget) ApiSetTargetRequest { +func (r ApiSetTargetRequest) Target(target CreateProviderTargetDTO) ApiSetTargetRequest { r.target = &target return r } diff --git a/pkg/apiclient/docs/CreateProviderTargetDTO.md b/pkg/apiclient/docs/CreateProviderTargetDTO.md new file mode 100644 index 0000000000..87e2ba03a3 --- /dev/null +++ b/pkg/apiclient/docs/CreateProviderTargetDTO.md @@ -0,0 +1,93 @@ +# CreateProviderTargetDTO + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | | +**Options** | **string** | | +**ProviderInfo** | [**ProviderProviderInfo**](ProviderProviderInfo.md) | | + +## Methods + +### NewCreateProviderTargetDTO + +`func NewCreateProviderTargetDTO(name string, options string, providerInfo ProviderProviderInfo, ) *CreateProviderTargetDTO` + +NewCreateProviderTargetDTO instantiates a new CreateProviderTargetDTO object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateProviderTargetDTOWithDefaults + +`func NewCreateProviderTargetDTOWithDefaults() *CreateProviderTargetDTO` + +NewCreateProviderTargetDTOWithDefaults instantiates a new CreateProviderTargetDTO object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *CreateProviderTargetDTO) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *CreateProviderTargetDTO) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *CreateProviderTargetDTO) SetName(v string)` + +SetName sets Name field to given value. + + +### GetOptions + +`func (o *CreateProviderTargetDTO) GetOptions() string` + +GetOptions returns the Options field if non-nil, zero value otherwise. + +### GetOptionsOk + +`func (o *CreateProviderTargetDTO) GetOptionsOk() (*string, bool)` + +GetOptionsOk returns a tuple with the Options field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetOptions + +`func (o *CreateProviderTargetDTO) SetOptions(v string)` + +SetOptions sets Options field to given value. + + +### GetProviderInfo + +`func (o *CreateProviderTargetDTO) GetProviderInfo() ProviderProviderInfo` + +GetProviderInfo returns the ProviderInfo field if non-nil, zero value otherwise. + +### GetProviderInfoOk + +`func (o *CreateProviderTargetDTO) GetProviderInfoOk() (*ProviderProviderInfo, bool)` + +GetProviderInfoOk returns a tuple with the ProviderInfo field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProviderInfo + +`func (o *CreateProviderTargetDTO) SetProviderInfo(v ProviderProviderInfo)` + +SetProviderInfo sets ProviderInfo field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/ProviderTarget.md b/pkg/apiclient/docs/ProviderTarget.md index 08ab4e874c..e4592a685d 100644 --- a/pkg/apiclient/docs/ProviderTarget.md +++ b/pkg/apiclient/docs/ProviderTarget.md @@ -4,6 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**IsDefault** | **bool** | | **Name** | **string** | | **Options** | **string** | JSON encoded map of options | **ProviderInfo** | [**ProviderProviderInfo**](ProviderProviderInfo.md) | | @@ -12,7 +13,7 @@ Name | Type | Description | Notes ### NewProviderTarget -`func NewProviderTarget(name string, options string, providerInfo ProviderProviderInfo, ) *ProviderTarget` +`func NewProviderTarget(isDefault bool, name string, options string, providerInfo ProviderProviderInfo, ) *ProviderTarget` NewProviderTarget instantiates a new ProviderTarget object This constructor will assign default values to properties that have it defined, @@ -27,6 +28,26 @@ NewProviderTargetWithDefaults instantiates a new ProviderTarget object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetIsDefault + +`func (o *ProviderTarget) GetIsDefault() bool` + +GetIsDefault returns the IsDefault field if non-nil, zero value otherwise. + +### GetIsDefaultOk + +`func (o *ProviderTarget) GetIsDefaultOk() (*bool, bool)` + +GetIsDefaultOk returns a tuple with the IsDefault field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIsDefault + +`func (o *ProviderTarget) SetIsDefault(v bool)` + +SetIsDefault sets IsDefault field to given value. + + ### GetName `func (o *ProviderTarget) GetName() string` diff --git a/pkg/apiclient/docs/TargetAPI.md b/pkg/apiclient/docs/TargetAPI.md index 0458163bb1..d4232dba94 100644 --- a/pkg/apiclient/docs/TargetAPI.md +++ b/pkg/apiclient/docs/TargetAPI.md @@ -6,6 +6,7 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**ListTargets**](TargetAPI.md#ListTargets) | **Get** /target | List targets [**RemoveTarget**](TargetAPI.md#RemoveTarget) | **Delete** /target/{target} | Remove a target +[**SetDefaultTarget**](TargetAPI.md#SetDefaultTarget) | **Patch** /target/{target}/set-default | Set target to default [**SetTarget**](TargetAPI.md#SetTarget) | **Put** /target | Set a target @@ -139,6 +140,74 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## SetDefaultTarget + +> SetDefaultTarget(ctx, target).Execute() + +Set target to default + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + target := "target_example" // string | Target name + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.TargetAPI.SetDefaultTarget(context.Background(), target).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `TargetAPI.SetDefaultTarget``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**target** | **string** | Target name | + +### Other Parameters + +Other parameters are passed through a pointer to a apiSetDefaultTargetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## SetTarget > SetTarget(ctx).Target(target).Execute() @@ -160,7 +229,7 @@ import ( ) func main() { - target := *openapiclient.NewProviderTarget("Name_example", "Options_example", *openapiclient.NewProviderProviderInfo("Name_example", "Version_example")) // ProviderTarget | Target to set + target := *openapiclient.NewCreateProviderTargetDTO("Name_example", "Options_example", *openapiclient.NewProviderProviderInfo("Name_example", "Version_example")) // CreateProviderTargetDTO | Target to set configuration := openapiclient.NewConfiguration() apiClient := openapiclient.NewAPIClient(configuration) @@ -183,7 +252,7 @@ Other parameters are passed through a pointer to a apiSetTargetRequest struct vi Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **target** | [**ProviderTarget**](ProviderTarget.md) | Target to set | + **target** | [**CreateProviderTargetDTO**](CreateProviderTargetDTO.md) | Target to set | ### Return type diff --git a/pkg/apiclient/model_create_provider_target_dto.go b/pkg/apiclient/model_create_provider_target_dto.go new file mode 100644 index 0000000000..acd7ba8273 --- /dev/null +++ b/pkg/apiclient/model_create_provider_target_dto.go @@ -0,0 +1,212 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the CreateProviderTargetDTO type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateProviderTargetDTO{} + +// CreateProviderTargetDTO struct for CreateProviderTargetDTO +type CreateProviderTargetDTO struct { + Name string `json:"name"` + Options string `json:"options"` + ProviderInfo ProviderProviderInfo `json:"providerInfo"` +} + +type _CreateProviderTargetDTO CreateProviderTargetDTO + +// NewCreateProviderTargetDTO instantiates a new CreateProviderTargetDTO object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateProviderTargetDTO(name string, options string, providerInfo ProviderProviderInfo) *CreateProviderTargetDTO { + this := CreateProviderTargetDTO{} + this.Name = name + this.Options = options + this.ProviderInfo = providerInfo + return &this +} + +// NewCreateProviderTargetDTOWithDefaults instantiates a new CreateProviderTargetDTO object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateProviderTargetDTOWithDefaults() *CreateProviderTargetDTO { + this := CreateProviderTargetDTO{} + return &this +} + +// GetName returns the Name field value +func (o *CreateProviderTargetDTO) GetName() string { + if o == nil { + var ret string + return ret + } + + return o.Name +} + +// GetNameOk returns a tuple with the Name field value +// and a boolean to check if the value has been set. +func (o *CreateProviderTargetDTO) GetNameOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Name, true +} + +// SetName sets field value +func (o *CreateProviderTargetDTO) SetName(v string) { + o.Name = v +} + +// GetOptions returns the Options field value +func (o *CreateProviderTargetDTO) GetOptions() string { + if o == nil { + var ret string + return ret + } + + return o.Options +} + +// GetOptionsOk returns a tuple with the Options field value +// and a boolean to check if the value has been set. +func (o *CreateProviderTargetDTO) GetOptionsOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Options, true +} + +// SetOptions sets field value +func (o *CreateProviderTargetDTO) SetOptions(v string) { + o.Options = v +} + +// GetProviderInfo returns the ProviderInfo field value +func (o *CreateProviderTargetDTO) GetProviderInfo() ProviderProviderInfo { + if o == nil { + var ret ProviderProviderInfo + return ret + } + + return o.ProviderInfo +} + +// GetProviderInfoOk returns a tuple with the ProviderInfo field value +// and a boolean to check if the value has been set. +func (o *CreateProviderTargetDTO) GetProviderInfoOk() (*ProviderProviderInfo, bool) { + if o == nil { + return nil, false + } + return &o.ProviderInfo, true +} + +// SetProviderInfo sets field value +func (o *CreateProviderTargetDTO) SetProviderInfo(v ProviderProviderInfo) { + o.ProviderInfo = v +} + +func (o CreateProviderTargetDTO) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateProviderTargetDTO) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["name"] = o.Name + toSerialize["options"] = o.Options + toSerialize["providerInfo"] = o.ProviderInfo + return toSerialize, nil +} + +func (o *CreateProviderTargetDTO) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "name", + "options", + "providerInfo", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varCreateProviderTargetDTO := _CreateProviderTargetDTO{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varCreateProviderTargetDTO) + + if err != nil { + return err + } + + *o = CreateProviderTargetDTO(varCreateProviderTargetDTO) + + return err +} + +type NullableCreateProviderTargetDTO struct { + value *CreateProviderTargetDTO + isSet bool +} + +func (v NullableCreateProviderTargetDTO) Get() *CreateProviderTargetDTO { + return v.value +} + +func (v *NullableCreateProviderTargetDTO) Set(val *CreateProviderTargetDTO) { + v.value = val + v.isSet = true +} + +func (v NullableCreateProviderTargetDTO) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateProviderTargetDTO) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateProviderTargetDTO(val *CreateProviderTargetDTO) *NullableCreateProviderTargetDTO { + return &NullableCreateProviderTargetDTO{value: val, isSet: true} +} + +func (v NullableCreateProviderTargetDTO) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateProviderTargetDTO) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/apiclient/model_provider_target.go b/pkg/apiclient/model_provider_target.go index ff5803ec83..2d77e6a703 100644 --- a/pkg/apiclient/model_provider_target.go +++ b/pkg/apiclient/model_provider_target.go @@ -21,7 +21,8 @@ var _ MappedNullable = &ProviderTarget{} // ProviderTarget struct for ProviderTarget type ProviderTarget struct { - Name string `json:"name"` + IsDefault bool `json:"isDefault"` + Name string `json:"name"` // JSON encoded map of options Options string `json:"options"` ProviderInfo ProviderProviderInfo `json:"providerInfo"` @@ -33,8 +34,9 @@ type _ProviderTarget ProviderTarget // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewProviderTarget(name string, options string, providerInfo ProviderProviderInfo) *ProviderTarget { +func NewProviderTarget(isDefault bool, name string, options string, providerInfo ProviderProviderInfo) *ProviderTarget { this := ProviderTarget{} + this.IsDefault = isDefault this.Name = name this.Options = options this.ProviderInfo = providerInfo @@ -49,6 +51,30 @@ func NewProviderTargetWithDefaults() *ProviderTarget { return &this } +// GetIsDefault returns the IsDefault field value +func (o *ProviderTarget) GetIsDefault() bool { + if o == nil { + var ret bool + return ret + } + + return o.IsDefault +} + +// GetIsDefaultOk returns a tuple with the IsDefault field value +// and a boolean to check if the value has been set. +func (o *ProviderTarget) GetIsDefaultOk() (*bool, bool) { + if o == nil { + return nil, false + } + return &o.IsDefault, true +} + +// SetIsDefault sets field value +func (o *ProviderTarget) SetIsDefault(v bool) { + o.IsDefault = v +} + // GetName returns the Name field value func (o *ProviderTarget) GetName() string { if o == nil { @@ -131,6 +157,7 @@ func (o ProviderTarget) MarshalJSON() ([]byte, error) { func (o ProviderTarget) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} + toSerialize["isDefault"] = o.IsDefault toSerialize["name"] = o.Name toSerialize["options"] = o.Options toSerialize["providerInfo"] = o.ProviderInfo @@ -142,6 +169,7 @@ func (o *ProviderTarget) UnmarshalJSON(data []byte) (err error) { // by unmarshalling the object into a generic map with string keys and checking // that every required field exists as a key in the generic map. requiredProperties := []string{ + "isDefault", "name", "options", "providerInfo", diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 967d13b9b5..3b2cc73112 100644 --- a/pkg/cmd/cmd.go +++ b/pkg/cmd/cmd.go @@ -153,6 +153,7 @@ func ensureProfiles(cmd *cobra.Command) error { "daytona", "daytona help", "daytona docs", + "daytona generate-docs", "daytona version", "daytona profile add", "daytona serve", diff --git a/pkg/cmd/provider/install.go b/pkg/cmd/provider/install.go index dec58e96e3..f4d54e2c25 100644 --- a/pkg/cmd/provider/install.go +++ b/pkg/cmd/provider/install.go @@ -149,7 +149,7 @@ var providerInstallCmd = &cobra.Command{ return err } - targetData := apiclient.ProviderTarget{ + targetData := apiclient.CreateProviderTargetDTO{ Name: targetToSet.Name, Options: targetToSet.Options, ProviderInfo: apiclient.ProviderProviderInfo{ diff --git a/pkg/cmd/target/remove.go b/pkg/cmd/target/remove.go index 1b38bfd962..c8d2f0d0d4 100644 --- a/pkg/cmd/target/remove.go +++ b/pkg/cmd/target/remove.go @@ -52,7 +52,7 @@ var targetRemoveCmd = &cobra.Command{ return apiclient_util.HandleErrorResponse(res, err) } - selectedTarget, err := target.GetTargetFromPrompt(targetList, activeProfile.Name, nil, false) + selectedTarget, err := target.GetTargetFromPrompt(targetList, activeProfile.Name, nil, false, "Remove") if err != nil { if common.IsCtrlCAbort(err) { return nil diff --git a/pkg/cmd/target/set.go b/pkg/cmd/target/set.go index 103d7c9561..26fa592b51 100644 --- a/pkg/cmd/target/set.go +++ b/pkg/cmd/target/set.go @@ -116,7 +116,7 @@ var TargetSetCmd = &cobra.Command{ var selectedTarget *target_view.TargetView if !isNewProvider || len(filteredTargets) > 0 { - selectedTarget, err = target.GetTargetFromPrompt(filteredTargets, activeProfile.Name, nil, true) + selectedTarget, err = target.GetTargetFromPrompt(filteredTargets, activeProfile.Name, nil, true, "Set") if err != nil { if common.IsCtrlCAbort(err) { return nil @@ -151,7 +151,7 @@ var TargetSetCmd = &cobra.Command{ return err } - targetData := apiclient.ProviderTarget{ + targetData := apiclient.CreateProviderTargetDTO{ Name: selectedTarget.Name, Options: selectedTarget.Options, ProviderInfo: apiclient.ProviderProviderInfo{ @@ -165,7 +165,7 @@ var TargetSetCmd = &cobra.Command{ return apiclient_util.HandleErrorResponse(res, err) } - views.RenderInfoMessage("Target set successfully") + views.RenderInfoMessage("Target set successfully and will be used by default") return nil }, } diff --git a/pkg/cmd/target/setdefault.go b/pkg/cmd/target/setdefault.go new file mode 100644 index 0000000000..728b14f8ea --- /dev/null +++ b/pkg/cmd/target/setdefault.go @@ -0,0 +1,73 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package target + +import ( + "context" + "fmt" + + "github.com/daytonaio/daytona/cmd/daytona/config" + apiclient_util "github.com/daytonaio/daytona/internal/util/apiclient" + "github.com/daytonaio/daytona/pkg/common" + "github.com/daytonaio/daytona/pkg/views" + target_view "github.com/daytonaio/daytona/pkg/views/target" + "github.com/spf13/cobra" +) + +var targetSetDefaultCmd = &cobra.Command{ + Use: "set-default [TARGET_NAME]", + Short: "Set target to be used by default", + Args: cobra.RangeArgs(0, 1), + RunE: func(cmd *cobra.Command, args []string) error { + var targetName string + ctx := context.Background() + + apiClient, err := apiclient_util.GetApiClient(nil) + if err != nil { + return err + } + + if len(args) == 0 { + targetList, res, err := apiClient.TargetAPI.ListTargets(ctx).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + c, err := config.GetConfig() + if err != nil { + return err + } + + activeProfile, err := c.GetActiveProfile() + if err != nil { + return err + } + + selectedTarget, err := target_view.GetTargetFromPrompt(targetList, activeProfile.Name, nil, false, "Make Default") + if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } else { + return err + } + } + + if selectedTarget == nil { + return nil + } + + targetName = selectedTarget.Name + } else { + targetName = args[0] + } + + res, err := apiClient.TargetAPI.SetDefaultTarget(ctx, targetName).Execute() + if err != nil { + return apiclient_util.HandleErrorResponse(res, err) + } + + views.RenderInfoMessage(fmt.Sprintf("Target '%s' set as default", targetName)) + return nil + }, +} diff --git a/pkg/cmd/target/target.go b/pkg/cmd/target/target.go index 8d244fd5e0..2253c91081 100644 --- a/pkg/cmd/target/target.go +++ b/pkg/cmd/target/target.go @@ -18,4 +18,5 @@ func init() { TargetCmd.AddCommand(targetListCmd) TargetCmd.AddCommand(TargetSetCmd) TargetCmd.AddCommand(targetRemoveCmd) + TargetCmd.AddCommand(targetSetDefaultCmd) } diff --git a/pkg/cmd/workspace/create.go b/pkg/cmd/workspace/create.go index d0ba990d50..e89d8ba797 100644 --- a/pkg/cmd/workspace/create.go +++ b/pkg/cmd/workspace/create.go @@ -48,6 +48,7 @@ var CreateCmd = &cobra.Command{ var workspaceName string var existingWorkspaceNames []string var existingProjectConfigNames []string + promptUsingTUI := len(args) == 0 apiClient, err := apiclient_util.GetApiClient(nil) if err != nil { @@ -81,7 +82,7 @@ var CreateCmd = &cobra.Command{ existingWorkspaceNames = append(existingWorkspaceNames, workspaceInfo.Name) } - if len(args) == 0 { + if promptUsingTUI { err = processPrompting(ctx, apiClient, &workspaceName, &projects, existingWorkspaceNames) if err != nil { if common.IsCtrlCAbort(err) { @@ -132,8 +133,18 @@ var CreateCmd = &cobra.Command{ return apiclient_util.HandleErrorResponse(res, err) } - target, err := workspace_util.GetTarget(ctx, apiClient, targetList, activeProfile.Name, targetNameFlag) + target, err := workspace_util.GetTarget(workspace_util.GetTargetConfig{ + Ctx: ctx, + ApiClient: apiClient, + TargetList: targetList, + ActiveProfileName: activeProfile.Name, + TargetNameFlag: targetNameFlag, + PromptUsingTUI: promptUsingTUI, + }) if err != nil { + if common.IsCtrlCAbort(err) { + return nil + } return err } diff --git a/pkg/cmd/workspace/util/get_target.go b/pkg/cmd/workspace/util/get_target.go index 37b33605c9..49b397ed9e 100644 --- a/pkg/cmd/workspace/util/get_target.go +++ b/pkg/cmd/workspace/util/get_target.go @@ -17,17 +17,34 @@ import ( target_view "github.com/daytonaio/daytona/pkg/views/target" ) -func GetTarget(ctx context.Context, apiClient *apiclient.APIClient, targetList []apiclient.ProviderTarget, activeProfileName string, targetNameFlag string) (*target_view.TargetView, error) { - if targetNameFlag != "" { - for _, t := range targetList { - if t.Name == targetNameFlag { +type GetTargetConfig struct { + Ctx context.Context + ApiClient *apiclient.APIClient + TargetList []apiclient.ProviderTarget + ActiveProfileName string + TargetNameFlag string + PromptUsingTUI bool +} + +func GetTarget(config GetTargetConfig) (*target_view.TargetView, error) { + if config.TargetNameFlag != "" { + for _, t := range config.TargetList { + if t.Name == config.TargetNameFlag { + return util.Pointer(target_view.GetTargetViewFromTarget(t)), nil + } + } + return nil, fmt.Errorf("target '%s' not found", config.TargetNameFlag) + } + + if !config.PromptUsingTUI { + for _, t := range config.TargetList { + if t.IsDefault { return util.Pointer(target_view.GetTargetViewFromTarget(t)), nil } } - return nil, fmt.Errorf("target '%s' not found", targetNameFlag) } - serverConfig, res, err := apiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) + serverConfig, res, err := config.ApiClient.ServerAPI.GetConfigExecute(apiclient.ApiGetConfigRequest{}) if err != nil { return nil, apiclient_util.HandleErrorResponse(res, err) } @@ -48,13 +65,13 @@ func GetTarget(ctx context.Context, apiClient *apiclient.APIClient, targetList [ latestProviders := provider.GetProviderListFromManifest(providersManifestLatest) - providerViewList, err = provider.GetProviderViewOptions(apiClient, latestProviders, ctx) + providerViewList, err = provider.GetProviderViewOptions(config.ApiClient, latestProviders, config.Ctx) if err != nil { return nil, err } } - selectedTarget, err := target_view.GetTargetFromPrompt(targetList, activeProfileName, &providerViewList, false) + selectedTarget, err := target_view.GetTargetFromPrompt(config.TargetList, config.ActiveProfileName, &providerViewList, false, "Use") if err != nil { return nil, err } @@ -63,7 +80,7 @@ func GetTarget(ctx context.Context, apiClient *apiclient.APIClient, targetList [ return selectedTarget, nil } - err = provider.InstallProvider(apiClient, provider_view.ProviderView{ + err = provider.InstallProvider(config.ApiClient, provider_view.ProviderView{ Name: selectedTarget.ProviderInfo.Name, Version: selectedTarget.ProviderInfo.Version, }, providersManifest) @@ -71,13 +88,13 @@ func GetTarget(ctx context.Context, apiClient *apiclient.APIClient, targetList [ return nil, err } - targetManifest, res, err := apiClient.ProviderAPI.GetTargetManifest(context.Background(), selectedTarget.ProviderInfo.Name).Execute() + targetManifest, res, err := config.ApiClient.ProviderAPI.GetTargetManifest(context.Background(), selectedTarget.ProviderInfo.Name).Execute() if err != nil { return nil, apiclient_util.HandleErrorResponse(res, err) } selectedTarget.Name = "" - err = target_view.NewTargetNameInput(&selectedTarget.Name, util.ArrayMap(targetList, func(t apiclient.ProviderTarget) string { + err = target_view.NewTargetNameInput(&selectedTarget.Name, util.ArrayMap(config.TargetList, func(t apiclient.ProviderTarget) string { return t.Name })) if err != nil { @@ -89,7 +106,7 @@ func GetTarget(ctx context.Context, apiClient *apiclient.APIClient, targetList [ return nil, err } - res, err = apiClient.TargetAPI.SetTarget(context.Background()).Target(apiclient.ProviderTarget{ + res, err = config.ApiClient.TargetAPI.SetTarget(context.Background()).Target(apiclient.CreateProviderTargetDTO{ Name: selectedTarget.Name, Options: selectedTarget.Options, ProviderInfo: apiclient.ProviderProviderInfo{ diff --git a/pkg/db/dto/provider_target.go b/pkg/db/dto/provider_target.go index de5b5cf7cc..53f03752e6 100644 --- a/pkg/db/dto/provider_target.go +++ b/pkg/db/dto/provider_target.go @@ -11,6 +11,7 @@ type ProviderTargetDTO struct { ProviderLabel *string `json:"providerLabel,omitempty"` ProviderVersion string `json:"providerVersion"` Options string `json:"options"` + IsDefault bool `json:"isDefault"` } func ToProviderTargetDTO(providerTarget *provider.ProviderTarget) ProviderTargetDTO { @@ -20,6 +21,7 @@ func ToProviderTargetDTO(providerTarget *provider.ProviderTarget) ProviderTarget ProviderLabel: providerTarget.ProviderInfo.Label, ProviderVersion: providerTarget.ProviderInfo.Version, Options: providerTarget.Options, + IsDefault: providerTarget.IsDefault, } } @@ -31,6 +33,7 @@ func ToProviderTarget(providerTargetDTO ProviderTargetDTO) *provider.ProviderTar Label: providerTargetDTO.ProviderLabel, Version: providerTargetDTO.ProviderVersion, }, - Options: providerTargetDTO.Options, + Options: providerTargetDTO.Options, + IsDefault: providerTargetDTO.IsDefault, } } diff --git a/pkg/db/provider_target_store.go b/pkg/db/provider_target_store.go index fda1d0f790..a0efda39d8 100644 --- a/pkg/db/provider_target_store.go +++ b/pkg/db/provider_target_store.go @@ -23,24 +23,26 @@ func NewProviderTargetStore(db *gorm.DB) (*ProviderTargetStore, error) { return &ProviderTargetStore{db: db}, nil } -func (s *ProviderTargetStore) List() ([]*provider.ProviderTarget, error) { - providerTargetsDTOs := []ProviderTargetDTO{} - tx := s.db.Find(&providerTargetsDTOs) +func (s *ProviderTargetStore) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { + targetDTOs := []ProviderTargetDTO{} + tx := processTargetFilters(s.db, filter).Find(&targetDTOs) + if tx.Error != nil { return nil, tx.Error } - providerTargets := []*provider.ProviderTarget{} - for _, providerTargetDTO := range providerTargetsDTOs { - providerTargets = append(providerTargets, ToProviderTarget(providerTargetDTO)) + targets := []*provider.ProviderTarget{} + for _, targetDTO := range targetDTOs { + targets = append(targets, ToProviderTarget(targetDTO)) } - return providerTargets, nil + return targets, nil } -func (s *ProviderTargetStore) Find(targetName string) (*provider.ProviderTarget, error) { - providerTargetDTO := ProviderTargetDTO{} - tx := s.db.Where("name = ?", targetName).First(&providerTargetDTO) +func (s *ProviderTargetStore) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { + targetDTO := ProviderTargetDTO{} + tx := processTargetFilters(s.db, filter).First(&targetDTO) + if tx.Error != nil { if IsRecordNotFound(tx.Error) { return nil, provider.ErrTargetNotFound @@ -48,7 +50,7 @@ func (s *ProviderTargetStore) Find(targetName string) (*provider.ProviderTarget, return nil, tx.Error } - return ToProviderTarget(providerTargetDTO), nil + return ToProviderTarget(targetDTO), nil } func (s *ProviderTargetStore) Save(target *provider.ProviderTarget) error { @@ -71,3 +73,16 @@ func (s *ProviderTargetStore) Delete(target *provider.ProviderTarget) error { return nil } + +func processTargetFilters(tx *gorm.DB, filter *provider.TargetFilter) *gorm.DB { + if filter != nil { + if filter.Name != nil { + tx = tx.Where("name = ?", *filter.Name) + } + if filter.Default != nil { + tx = tx.Where("is_default = ?", *filter.Default) + } + } + + return tx +} diff --git a/pkg/provider/manager/manager.go b/pkg/provider/manager/manager.go index e8c5bd0a5c..caec4a0c89 100644 --- a/pkg/provider/manager/manager.go +++ b/pkg/provider/manager/manager.go @@ -147,13 +147,13 @@ func (m *ProviderManager) RegisterProvider(pluginPath string) error { return errors.New("failed to get targets: " + err.Error()) } - defaultTargets, err := (*p).GetDefaultTargets() + presetTargets, err := (*p).GetPresetTargets() if err != nil { - return errors.New("failed to get default targets: " + err.Error()) + return errors.New("failed to get preset targets: " + err.Error()) } - log.Info("Setting default targets") - for _, target := range *defaultTargets { + log.Info("Setting preset targets") + for _, target := range *presetTargets { if _, ok := existingTargets[target.Name]; ok { log.Infof("Target %s already exists. Skipping...", target.Name) continue @@ -166,7 +166,7 @@ func (m *ProviderManager) RegisterProvider(pluginPath string) error { log.Infof("Target %s set", target.Name) } } - log.Info("Default targets set") + log.Info("Preset targets set") log.Infof("Provider %s initialized", pluginRef.name) diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index f6fca3005f..0e031e2587 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -17,7 +17,7 @@ type Provider interface { GetInfo() (ProviderInfo, error) GetTargetManifest() (*ProviderTargetManifest, error) - GetDefaultTargets() (*[]ProviderTarget, error) + GetPresetTargets() (*[]ProviderTarget, error) CreateWorkspace(*WorkspaceRequest) (*util.Empty, error) StartWorkspace(*WorkspaceRequest) (*util.Empty, error) diff --git a/pkg/provider/rpc_client.go b/pkg/provider/rpc_client.go index 6088c94c55..f433ea052e 100644 --- a/pkg/provider/rpc_client.go +++ b/pkg/provider/rpc_client.go @@ -33,9 +33,9 @@ func (m *ProviderRPCClient) GetTargetManifest() (*ProviderTargetManifest, error) return &resp, err } -func (m *ProviderRPCClient) GetDefaultTargets() (*[]ProviderTarget, error) { +func (m *ProviderRPCClient) GetPresetTargets() (*[]ProviderTarget, error) { var resp []ProviderTarget - err := m.client.Call("Plugin.GetDefaultTargets", new(interface{}), &resp) + err := m.client.Call("Plugin.GetPresetTargets", new(interface{}), &resp) return &resp, err } diff --git a/pkg/provider/rpc_server.go b/pkg/provider/rpc_server.go index 9e24be61c3..8f6bde2b67 100644 --- a/pkg/provider/rpc_server.go +++ b/pkg/provider/rpc_server.go @@ -38,8 +38,8 @@ func (m *ProviderRPCServer) GetTargetManifest(arg interface{}, resp *ProviderTar return nil } -func (m *ProviderRPCServer) GetDefaultTargets(arg interface{}, resp *[]ProviderTarget) error { - targets, err := m.Impl.GetDefaultTargets() +func (m *ProviderRPCServer) GetPresetTargets(arg interface{}, resp *[]ProviderTarget) error { + targets, err := m.Impl.GetPresetTargets() if err != nil { return err } diff --git a/pkg/provider/store.go b/pkg/provider/store.go index 75c79d1d7b..82aa0a2d6b 100644 --- a/pkg/provider/store.go +++ b/pkg/provider/store.go @@ -5,18 +5,20 @@ package provider import "errors" -type Store interface { +type TargetFilter struct { + Name *string + Default *bool } type TargetStore interface { - List() ([]*ProviderTarget, error) - Find(targetName string) (*ProviderTarget, error) + List(filter *TargetFilter) ([]*ProviderTarget, error) + Find(filter *TargetFilter) (*ProviderTarget, error) Save(target *ProviderTarget) error Delete(target *ProviderTarget) error } var ( - ErrTargetNotFound = errors.New("provider not found") + ErrTargetNotFound = errors.New("target not found") ) func IsTargetNotFound(err error) bool { diff --git a/pkg/provider/types.go b/pkg/provider/types.go index 4856af89e1..72abd2d331 100644 --- a/pkg/provider/types.go +++ b/pkg/provider/types.go @@ -47,7 +47,8 @@ type ProviderTarget struct { Name string `json:"name" validate:"required"` ProviderInfo ProviderInfo `json:"providerInfo" validate:"required"` // JSON encoded map of options - Options string `json:"options" validate:"required"` + Options string `json:"options" validate:"required"` + IsDefault bool `json:"isDefault" validate:"required"` } // @name ProviderTarget type ProviderTargetManifest map[string]ProviderTargetProperty // @name ProviderTargetManifest diff --git a/pkg/server/providertargets/dto/providertargets.go b/pkg/server/providertargets/dto/providertargets.go new file mode 100644 index 0000000000..fc2e6411cc --- /dev/null +++ b/pkg/server/providertargets/dto/providertargets.go @@ -0,0 +1,12 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package dto + +import "github.com/daytonaio/daytona/pkg/provider" + +type CreateProviderTargetDTO struct { + Name string `json:"name" validate:"required"` + ProviderInfo provider.ProviderInfo `json:"providerInfo" validate:"required"` + Options string `json:"options" validate:"required"` +} // @name CreateProviderTargetDTO diff --git a/pkg/server/providertargets/service.go b/pkg/server/providertargets/service.go index 1ca23e4196..4a2f22834c 100644 --- a/pkg/server/providertargets/service.go +++ b/pkg/server/providertargets/service.go @@ -3,14 +3,18 @@ package providertargets -import "github.com/daytonaio/daytona/pkg/provider" +import ( + "github.com/daytonaio/daytona/internal/util" + "github.com/daytonaio/daytona/pkg/provider" +) type IProviderTargetService interface { Delete(target *provider.ProviderTarget) error - Find(targetName string) (*provider.ProviderTarget, error) - List() ([]*provider.ProviderTarget, error) + Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) + List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) Map() (map[string]*provider.ProviderTarget, error) Save(target *provider.ProviderTarget) error + SetDefault(target *provider.ProviderTarget) error } type ProviderTargetServiceConfig struct { @@ -27,12 +31,12 @@ func NewProviderTargetService(config ProviderTargetServiceConfig) IProviderTarge } } -func (s *ProviderTargetService) List() ([]*provider.ProviderTarget, error) { - return s.targetStore.List() +func (s *ProviderTargetService) List(filter *provider.TargetFilter) ([]*provider.ProviderTarget, error) { + return s.targetStore.List(filter) } func (s *ProviderTargetService) Map() (map[string]*provider.ProviderTarget, error) { - list, err := s.targetStore.List() + list, err := s.targetStore.List(nil) if err != nil { return nil, err } @@ -45,14 +49,46 @@ func (s *ProviderTargetService) Map() (map[string]*provider.ProviderTarget, erro return targets, nil } -func (s *ProviderTargetService) Find(targetName string) (*provider.ProviderTarget, error) { - return s.targetStore.Find(targetName) +func (s *ProviderTargetService) Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) { + return s.targetStore.Find(filter) } func (s *ProviderTargetService) Save(target *provider.ProviderTarget) error { - return s.targetStore.Save(target) + err := s.targetStore.Save(target) + if err != nil { + return err + } + + return s.SetDefault(target) } func (s *ProviderTargetService) Delete(target *provider.ProviderTarget) error { return s.targetStore.Delete(target) } + +func (s *ProviderTargetService) SetDefault(target *provider.ProviderTarget) error { + currentTarget, err := s.Find(&provider.TargetFilter{ + Name: &target.Name, + }) + if err != nil { + return err + } + + defaultTarget, err := s.Find(&provider.TargetFilter{ + Default: util.Pointer(true), + }) + if err != nil && err != provider.ErrTargetNotFound { + return err + } + + if defaultTarget != nil { + defaultTarget.IsDefault = false + err := s.targetStore.Save(defaultTarget) + if err != nil { + return err + } + } + + currentTarget.IsDefault = true + return s.targetStore.Save(currentTarget) +} diff --git a/pkg/server/providertargets/service_test.go b/pkg/server/providertargets/service_test.go index ae21f0aed2..05a14bdbb1 100644 --- a/pkg/server/providertargets/service_test.go +++ b/pkg/server/providertargets/service_test.go @@ -89,7 +89,7 @@ func TestProviderTargetService(t *testing.T) { func (s *ProviderTargetServiceTestSuite) TestList() { require := s.Require() - providerTargets, err := s.providerTargetService.List() + providerTargets, err := s.providerTargetService.List(nil) require.Nil(err) require.ElementsMatch(expectedProviderTargets, providerTargets) } @@ -105,11 +105,27 @@ func (s *ProviderTargetServiceTestSuite) TestMap() { func (s *ProviderTargetServiceTestSuite) TestFind() { require := s.Require() - providerTarget, err := s.providerTargetService.Find(providerTarget1.Name) + providerTarget, err := s.providerTargetService.Find(&provider.TargetFilter{ + Name: &providerTarget1.Name, + }) require.Nil(err) require.Equal(providerTarget1, providerTarget) } +func (s *ProviderTargetServiceTestSuite) TestSetDefault() { + require := s.Require() + + err := s.providerTargetService.SetDefault(providerTarget2) + require.Nil(err) + + providerTarget, err := s.providerTargetService.Find(&provider.TargetFilter{ + Name: &providerTarget2.Name, + }) + require.Nil(err) + + require.Equal(providerTarget2, providerTarget) +} + func (s *ProviderTargetServiceTestSuite) TestSave() { expectedProviderTargets = append(expectedProviderTargets, providerTarget4) @@ -118,7 +134,7 @@ func (s *ProviderTargetServiceTestSuite) TestSave() { err := s.providerTargetService.Save(providerTarget4) require.Nil(err) - providerTargets, err := s.providerTargetService.List() + providerTargets, err := s.providerTargetService.List(nil) require.Nil(err) require.ElementsMatch(expectedProviderTargets, providerTargets) } @@ -131,7 +147,7 @@ func (s *ProviderTargetServiceTestSuite) TestDelete() { err := s.providerTargetService.Delete(providerTarget3) require.Nil(err) - providerTargets, err := s.providerTargetService.List() + providerTargets, err := s.providerTargetService.List(nil) require.Nil(err) require.ElementsMatch(expectedProviderTargets, providerTargets) } diff --git a/pkg/server/workspaces/create.go b/pkg/server/workspaces/create.go index bac065282f..5fac385b65 100644 --- a/pkg/server/workspaces/create.go +++ b/pkg/server/workspaces/create.go @@ -132,7 +132,7 @@ func (s *WorkspaceService) CreateWorkspace(ctx context.Context, req dto.CreateWo return nil, err } - target, err := s.targetStore.Find(w.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) if err != nil { return w, err } diff --git a/pkg/server/workspaces/get.go b/pkg/server/workspaces/get.go index 811f7d765f..3b705e2461 100644 --- a/pkg/server/workspaces/get.go +++ b/pkg/server/workspaces/get.go @@ -9,6 +9,7 @@ import ( "fmt" "time" + "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/provisioner" "github.com/daytonaio/daytona/pkg/server/workspaces/dto" log "github.com/sirupsen/logrus" @@ -28,7 +29,7 @@ func (s *WorkspaceService) GetWorkspace(ctx context.Context, workspaceId string, return &response, nil } - target, err := s.targetStore.Find(ws.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &ws.Target}) if err != nil { return nil, err } diff --git a/pkg/server/workspaces/list.go b/pkg/server/workspaces/list.go index f06e312746..996bb6bc39 100644 --- a/pkg/server/workspaces/list.go +++ b/pkg/server/workspaces/list.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/provisioner" "github.com/daytonaio/daytona/pkg/server/workspaces/dto" log "github.com/sirupsen/logrus" @@ -34,7 +35,7 @@ func (s *WorkspaceService) ListWorkspaces(ctx context.Context, verbose bool) ([] go func(i int) { defer wg.Done() - target, err := s.targetStore.Find(w.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) if err != nil { log.Error(fmt.Errorf("failed to get target for %s", w.Target)) return diff --git a/pkg/server/workspaces/remove.go b/pkg/server/workspaces/remove.go index 5b002d481d..bda3117d2b 100644 --- a/pkg/server/workspaces/remove.go +++ b/pkg/server/workspaces/remove.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/daytonaio/daytona/pkg/logs" + "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/telemetry" log "github.com/sirupsen/logrus" ) @@ -20,7 +21,7 @@ func (s *WorkspaceService) RemoveWorkspace(ctx context.Context, workspaceId stri log.Infof("Destroying workspace %s", workspace.Id) - target, err := s.targetStore.Find(workspace.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) if err != nil { return err } @@ -96,7 +97,7 @@ func (s *WorkspaceService) ForceRemoveWorkspace(ctx context.Context, workspaceId log.Infof("Destroying workspace %s", workspace.Id) - target, _ := s.targetStore.Find(workspace.Target) + target, _ := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) for _, project := range workspace.Projects { // todo: go routines diff --git a/pkg/server/workspaces/service.go b/pkg/server/workspaces/service.go index 7236d9c62d..e28f544546 100644 --- a/pkg/server/workspaces/service.go +++ b/pkg/server/workspaces/service.go @@ -38,7 +38,7 @@ type IWorkspaceService interface { } type targetStore interface { - Find(targetName string) (*provider.ProviderTarget, error) + Find(filter *provider.TargetFilter) (*provider.ProviderTarget, error) } type WorkspaceServiceConfig struct { diff --git a/pkg/server/workspaces/start.go b/pkg/server/workspaces/start.go index fb4dd1f444..565a9c41f0 100644 --- a/pkg/server/workspaces/start.go +++ b/pkg/server/workspaces/start.go @@ -24,7 +24,7 @@ func (s *WorkspaceService) StartWorkspace(ctx context.Context, workspaceId strin return ErrWorkspaceNotFound } - target, err := s.targetStore.Find(w.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) if err != nil { return err } @@ -67,7 +67,7 @@ func (s *WorkspaceService) StartProject(ctx context.Context, workspaceId, projec return ErrProjectNotFound } - target, err := s.targetStore.Find(project.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) if err != nil { return err } diff --git a/pkg/server/workspaces/stop.go b/pkg/server/workspaces/stop.go index e11ecaf160..83344bb5d7 100644 --- a/pkg/server/workspaces/stop.go +++ b/pkg/server/workspaces/stop.go @@ -7,6 +7,7 @@ import ( "context" "time" + "github.com/daytonaio/daytona/pkg/provider" "github.com/daytonaio/daytona/pkg/telemetry" log "github.com/sirupsen/logrus" ) @@ -17,7 +18,7 @@ func (s *WorkspaceService) StopWorkspace(ctx context.Context, workspaceId string return ErrWorkspaceNotFound } - target, err := s.targetStore.Find(workspace.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &workspace.Target}) if err != nil { return err } @@ -70,7 +71,7 @@ func (s *WorkspaceService) StopProject(ctx context.Context, workspaceId, project return ErrProjectNotFound } - target, err := s.targetStore.Find(w.Target) + target, err := s.targetStore.Find(&provider.TargetFilter{Name: &w.Target}) if err != nil { return err } diff --git a/pkg/views/projectconfig/list/view.go b/pkg/views/projectconfig/list/view.go index 012cf5d271..5ca809a929 100644 --- a/pkg/views/projectconfig/list/view.go +++ b/pkg/views/projectconfig/list/view.go @@ -54,7 +54,6 @@ func getRowFromData(projectConfig apiclient.ProjectConfig, apiServerConfig *apic data.Name = projectConfig.Name + views_util.AdditionalPropertyPadding data.Repository = util.GetRepositorySlugFromUrl(projectConfig.RepositoryUrl, specifyGitProviders) data.Prebuilds = "None" - data.IsDefault = "" projectDefaults := &views_util.ProjectConfigDefaults{ Image: &apiServerConfig.DefaultProjectImage, @@ -68,19 +67,15 @@ func getRowFromData(projectConfig apiclient.ProjectConfig, apiServerConfig *apic _, data.Build = views_util.GetProjectBuildChoice(createProjectDto, projectDefaults) if projectConfig.Default { - data.IsDefault = "1" + isDefault = views.ActiveStyle.Render("Yes") + } else { + isDefault = views.InactiveStyle.Render("/") } if len(projectConfig.Prebuilds) > 0 { data.Prebuilds = fmt.Sprintf("%d", len(projectConfig.Prebuilds)) } - if data.IsDefault == "" { - isDefault = views.InactiveStyle.Render("/") - } else { - isDefault = views.ActiveStyle.Render("Yes") - } - return []string{ views.NameStyle.Render(data.Name), views.DefaultRowDataStyle.Render(data.Repository), diff --git a/pkg/views/target/list/view.go b/pkg/views/target/list/view.go index 7a9829cdfa..14bf3ac03d 100644 --- a/pkg/views/target/list/view.go +++ b/pkg/views/target/list/view.go @@ -13,9 +13,10 @@ import ( ) type rowData struct { - Target string - Provider string - Options string + Target string + Provider string + IsDefault string + Options string } func ListTargets(targetList []apiclient.ProviderTarget) { @@ -28,7 +29,7 @@ func ListTargets(targetList []apiclient.ProviderTarget) { } table := util.GetTableView(data, []string{ - "Target", "Provider", "Options", + "Target", "Provider", "Default", "Options", }, nil, func() { renderUnstyledList(targetList) }) @@ -37,15 +38,23 @@ func ListTargets(targetList []apiclient.ProviderTarget) { } func getRowFromRowData(target *apiclient.ProviderTarget) []string { + var isDefault string var data rowData data.Target = target.Name data.Provider = target.ProviderInfo.Name data.Options = target.Options + if target.IsDefault { + isDefault = views.ActiveStyle.Render("Yes") + } else { + isDefault = views.InactiveStyle.Render("/") + } + row := []string{ views.NameStyle.Render(data.Target), views.DefaultRowDataStyle.Render(data.Provider), + isDefault, views.DefaultRowDataStyle.Render(data.Options), } @@ -68,7 +77,11 @@ func renderUnstyledList(targetList []apiclient.ProviderTarget) { output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Provider: "), target.ProviderInfo.Name) + "\n\n" - output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Options: "), target.Options) + "\n" + if target.IsDefault { + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Default: "), "Yes") + "\n\n" + } + + output += fmt.Sprintf("%s %s", views.GetPropertyKey("Target Options: "), target.Options) + "\n\n" if target.Name != targetList[len(targetList)-1].Name { output += views.SeparatorString + "\n\n" diff --git a/pkg/views/target/select.go b/pkg/views/target/select.go index 20c1ce3c0c..d3f9a345b3 100644 --- a/pkg/views/target/select.go +++ b/pkg/views/target/select.go @@ -20,6 +20,7 @@ const NewTargetName = "+ New Target" type TargetView struct { Name string Options string + IsDefault bool ProviderInfo ProviderInfo } @@ -29,7 +30,7 @@ type ProviderInfo struct { Installed *bool } -func GetTargetFromPrompt(targets []apiclient.ProviderTarget, activeProfileName string, providerViewList *[]provider.ProviderView, withNewTarget bool) (*TargetView, error) { +func GetTargetFromPrompt(targets []apiclient.ProviderTarget, activeProfileName string, providerViewList *[]provider.ProviderView, withNewTarget bool, actionVerb string) (*TargetView, error) { items := util.ArrayMap(targets, func(t apiclient.ProviderTarget) list.Item { return item{ target: GetTargetViewFromTarget(t), @@ -76,7 +77,7 @@ func GetTargetFromPrompt(targets []apiclient.ProviderTarget, activeProfileName s l := views.GetStyledSelectList(items) m := model{list: l} - m.list.Title = views.GetStyledMainTitle("Choose a Target") + m.list.Title = views.GetStyledMainTitle("Choose a Target To " + actionVerb) m.footer = views.GetListFooter(activeProfileName, views.DefaultListFooterPadding) p, err := tea.NewProgram(m, tea.WithAltScreen()).Run() @@ -93,8 +94,9 @@ func GetTargetFromPrompt(targets []apiclient.ProviderTarget, activeProfileName s func GetTargetViewFromTarget(target apiclient.ProviderTarget) TargetView { return TargetView{ - Name: target.Name, - Options: target.Options, + Name: target.Name, + Options: target.Options, + IsDefault: target.IsDefault, ProviderInfo: ProviderInfo{ Name: target.ProviderInfo.Name, Version: target.ProviderInfo.Version, diff --git a/pkg/views/target/view.go b/pkg/views/target/view.go index d229b45caf..d63112ef3b 100644 --- a/pkg/views/target/view.go +++ b/pkg/views/target/view.go @@ -16,7 +16,15 @@ type item struct { target TargetView } -func (i item) Title() string { return i.target.Name } +func (i item) Title() string { + title := i.target.Name + + if i.target.IsDefault { + title += " (default)" + } + + return title +} func (i item) Description() string { desc := i.target.ProviderInfo.Name if i.target.ProviderInfo.Installed != nil {