diff --git a/api/http/handler/stacks/create_compose_stack.go b/api/http/handler/stacks/create_compose_stack.go index ab039c3e9..5b8fb2d33 100644 --- a/api/http/handler/stacks/create_compose_stack.go +++ b/api/http/handler/stacks/create_compose_stack.go @@ -25,6 +25,8 @@ type composeStackFromFileContentPayload struct { StackFileContent string `example:"version: 3\n services:\n web:\n image:nginx" validate:"required"` // A list of environment(endpoint) variables used during stack deployment Env []portainer.Pair `example:""` + // Whether the stack is from a app template + FromAppTemplate bool `example:"false"` } func (payload *composeStackFromFileContentPayload) Validate(r *http.Request) error { @@ -101,14 +103,15 @@ func (handler *Handler) createComposeStackFromFileContent(w http.ResponseWriter, stackID := handler.DataStore.Stack().GetNextIdentifier() stack := &portainer.Stack{ - ID: portainer.StackID(stackID), - Name: payload.Name, - Type: portainer.DockerComposeStack, - EndpointID: endpoint.ID, - EntryPoint: filesystem.ComposeFileDefaultName, - Env: payload.Env, - Status: portainer.StackStatusActive, - CreationDate: time.Now().Unix(), + ID: portainer.StackID(stackID), + Name: payload.Name, + Type: portainer.DockerComposeStack, + EndpointID: endpoint.ID, + EntryPoint: filesystem.ComposeFileDefaultName, + Env: payload.Env, + Status: portainer.StackStatusActive, + CreationDate: time.Now().Unix(), + FromAppTemplate: payload.FromAppTemplate, } stackFolder := strconv.Itoa(int(stack.ID)) @@ -163,6 +166,8 @@ type composeStackFromGitRepositoryPayload struct { AutoUpdate *portainer.StackAutoUpdate // A list of environment(endpoint) variables used during stack deployment Env []portainer.Pair + // Whether the stack is from a app template + FromAppTemplate bool `example:"false"` } func (payload *composeStackFromGitRepositoryPayload) Validate(r *http.Request) error { @@ -239,6 +244,7 @@ func (handler *Handler) createComposeStackFromGitRepository(w http.ResponseWrite AdditionalFiles: payload.AdditionalFiles, AutoUpdate: payload.AutoUpdate, Env: payload.Env, + FromAppTemplate: payload.FromAppTemplate, GitConfig: &gittypes.RepoConfig{ URL: payload.RepositoryURL, ReferenceName: payload.RepositoryReferenceName, diff --git a/api/http/handler/stacks/create_swarm_stack.go b/api/http/handler/stacks/create_swarm_stack.go index 6e9b8d3c0..3bf269011 100644 --- a/api/http/handler/stacks/create_swarm_stack.go +++ b/api/http/handler/stacks/create_swarm_stack.go @@ -26,6 +26,8 @@ type swarmStackFromFileContentPayload struct { StackFileContent string `example:"version: 3\n services:\n web:\n image:nginx" validate:"required"` // A list of environment(endpoint) variables used during stack deployment Env []portainer.Pair + // Whether the stack is from a app template + FromAppTemplate bool `example:"false"` } func (payload *swarmStackFromFileContentPayload) Validate(r *http.Request) error { @@ -61,15 +63,16 @@ func (handler *Handler) createSwarmStackFromFileContent(w http.ResponseWriter, r stackID := handler.DataStore.Stack().GetNextIdentifier() stack := &portainer.Stack{ - ID: portainer.StackID(stackID), - Name: payload.Name, - Type: portainer.DockerSwarmStack, - SwarmID: payload.SwarmID, - EndpointID: endpoint.ID, - EntryPoint: filesystem.ComposeFileDefaultName, - Env: payload.Env, - Status: portainer.StackStatusActive, - CreationDate: time.Now().Unix(), + ID: portainer.StackID(stackID), + Name: payload.Name, + Type: portainer.DockerSwarmStack, + SwarmID: payload.SwarmID, + EndpointID: endpoint.ID, + EntryPoint: filesystem.ComposeFileDefaultName, + Env: payload.Env, + Status: portainer.StackStatusActive, + CreationDate: time.Now().Unix(), + FromAppTemplate: payload.FromAppTemplate, } stackFolder := strconv.Itoa(int(stack.ID)) @@ -121,6 +124,8 @@ type swarmStackFromGitRepositoryPayload struct { RepositoryUsername string `example:"myGitUsername"` // Password used in basic authentication. Required when RepositoryAuthentication is true. RepositoryPassword string `example:"myGitPassword"` + // Whether the stack is from a app template + FromAppTemplate bool `example:"false"` // Path to the Stack file inside the Git repository ComposeFile string `example:"docker-compose.yml" default:"docker-compose.yml"` // Applicable when deploying with multiple stack files @@ -189,6 +194,7 @@ func (handler *Handler) createSwarmStackFromGitRepository(w http.ResponseWriter, EntryPoint: payload.ComposeFile, AdditionalFiles: payload.AdditionalFiles, AutoUpdate: payload.AutoUpdate, + FromAppTemplate: payload.FromAppTemplate, GitConfig: &gittypes.RepoConfig{ URL: payload.RepositoryURL, ReferenceName: payload.RepositoryReferenceName, diff --git a/api/portainer.go b/api/portainer.go index c2a33ead9..817539a83 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -849,6 +849,8 @@ type ( AutoUpdate *StackAutoUpdate `json:"AutoUpdate"` // The git config of this stack GitConfig *gittypes.RepoConfig + // Whether the stack is from a app template + FromAppTemplate bool `example:"false"` // Kubernetes namespace if stack is a kube application Namespace string `example:"default"` // IsComposeFormat indicates if the Kubernetes stack is created from a Docker Compose file diff --git a/app/portainer/models/stack.js b/app/portainer/models/stack.js index 118174d0a..86ba733d8 100644 --- a/app/portainer/models/stack.js +++ b/app/portainer/models/stack.js @@ -21,6 +21,7 @@ export function StackViewModel(data) { this.Orphaned = false; this.Checked = false; this.GitConfig = data.GitConfig; + this.FromAppTemplate = data.FromAppTemplate; this.AdditionalFiles = data.AdditionalFiles; this.AutoUpdate = data.AutoUpdate; } diff --git a/app/portainer/services/api/stackService.js b/app/portainer/services/api/stackService.js index 08f94065d..87e6ac48b 100644 --- a/app/portainer/services/api/stackService.js +++ b/app/portainer/services/api/stackService.js @@ -363,6 +363,7 @@ angular.module('portainer.app').factory('StackService', [ RepositoryUsername: repositoryOptions.RepositoryUsername, RepositoryPassword: repositoryOptions.RepositoryPassword, Env: env, + FromAppTemplate: repositoryOptions.FromAppTemplate, }; if (repositoryOptions.AutoUpdate) { @@ -389,6 +390,7 @@ angular.module('portainer.app').factory('StackService', [ RepositoryUsername: repositoryOptions.RepositoryUsername, RepositoryPassword: repositoryOptions.RepositoryPassword, Env: env, + FromAppTemplate: repositoryOptions.FromAppTemplate, }; if (repositoryOptions.AutoUpdate) { diff --git a/app/portainer/views/stacks/edit/stack.html b/app/portainer/views/stacks/edit/stack.html index adc1e831e..02a922bb7 100644 --- a/app/portainer/views/stacks/edit/stack.html +++ b/app/portainer/views/stacks/edit/stack.html @@ -110,7 +110,8 @@ - + + - + Editor
diff --git a/app/portainer/views/templates/templatesController.js b/app/portainer/views/templates/templatesController.js index f276b768e..d6da3a689 100644 --- a/app/portainer/views/templates/templatesController.js +++ b/app/portainer/views/templates/templatesController.js @@ -141,6 +141,7 @@ angular.module('portainer.app').controller('TemplatesController', [ var repositoryOptions = { RepositoryURL: template.Repository.url, ComposeFilePathInRepository: template.Repository.stackfile, + FromAppTemplate: true, }; const endpointId = +$state.params.endpointId; @@ -178,6 +179,7 @@ angular.module('portainer.app').controller('TemplatesController', [ var repositoryOptions = { RepositoryURL: template.Repository.url, ComposeFilePathInRepository: template.Repository.stackfile, + FromAppTemplate: true, }; const endpointId = +$state.params.endpointId;