diff --git a/Makefile b/Makefile index dafe34f94..7c430f161 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ dev-extension: build-server build-client ## Run the extension in development mod ##@ Docs .PHONY: docs-build docs-validate docs-clean docs-validate-clean docs-build: init-dist ## Build docs - cd api && $(SWAG) init -o "../dist/docs" -ot "yaml" -g ./http/handler/handler.go --parseDependency --parseInternal --parseDepth 2 -p pascalcase --markdownFiles ./ + cd api && $(SWAG) init -o "../dist/docs" -ot "yaml" -g ./http/handler/handler.go --parseDependency --parseInternal --parseDepth 2 --markdownFiles ./ docs-validate: docs-build ## Validate docs yarn swagger2openapi --warnOnly dist/docs/swagger.yaml -o dist/docs/openapi.yaml diff --git a/api/http/handler/customtemplates/customtemplate_create.go b/api/http/handler/customtemplates/customtemplate_create.go index 82254916b..6a584a914 100644 --- a/api/http/handler/customtemplates/customtemplate_create.go +++ b/api/http/handler/customtemplates/customtemplate_create.go @@ -149,7 +149,7 @@ func isValidNote(note string) bool { // @success 200 {object} portainer.CustomTemplate // @failure 400 "Invalid request" // @failure 500 "Server error" -// @router /custom_templates/create/string [post] +// @router /custom_templates/string [post] func (handler *Handler) createCustomTemplateFromFileContent(r *http.Request) (*portainer.CustomTemplate, error) { var payload customTemplateFromFileContentPayload err := request.DecodeAndValidateJSONPayload(r, &payload) @@ -263,7 +263,7 @@ func (payload *customTemplateFromGitRepositoryPayload) Validate(r *http.Request) // @success 200 {object} portainer.CustomTemplate // @failure 400 "Invalid request" // @failure 500 "Server error" -// @router /custom_templates/create/repository [post] +// @router /custom_templates/repository [post] func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) (*portainer.CustomTemplate, error) { var payload customTemplateFromGitRepositoryPayload err := request.DecodeAndValidateJSONPayload(r, &payload) @@ -443,7 +443,7 @@ func (payload *customTemplateFromFileUploadPayload) Validate(r *http.Request) er // @success 200 {object} portainer.CustomTemplate // @failure 400 "Invalid request" // @failure 500 "Server error" -// @router /custom_templates/create/file [post] +// @router /custom_templates/file [post] func (handler *Handler) createCustomTemplateFromFileUpload(r *http.Request) (*portainer.CustomTemplate, error) { payload := &customTemplateFromFileUploadPayload{} err := payload.Validate(r) diff --git a/api/http/handler/edgejobs/edgejob_tasklogs_clear.go b/api/http/handler/edgejobs/edgejob_tasklogs_clear.go index 4781168ac..e54c59029 100644 --- a/api/http/handler/edgejobs/edgejob_tasklogs_clear.go +++ b/api/http/handler/edgejobs/edgejob_tasklogs_clear.go @@ -110,6 +110,11 @@ func (handler *Handler) clearEdgeJobTaskLogs(tx dataservices.DataStoreTx, edgeJo return httperror.InternalServerError("Unable to persist Edge job changes in the database", err) } + err = handler.FileService.ClearEdgeJobTaskLogs(strconv.Itoa(int(edgeJobID)), strconv.Itoa(int(endpointID))) + if err != nil { + return httperror.InternalServerError("Unable to clear log file from disk", err) + } + endpoint, err := tx.Endpoint().Endpoint(endpointID) if err != nil { return httperror.NotFound("Unable to retrieve environment from the database", err) diff --git a/api/http/handler/endpoints/endpoint_update.go b/api/http/handler/endpoints/endpoint_update.go index eb728bc9c..4d566968c 100644 --- a/api/http/handler/endpoints/endpoint_update.go +++ b/api/http/handler/endpoints/endpoint_update.go @@ -89,8 +89,6 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * return httperror.InternalServerError("Unable to find an environment with the specified identifier inside the database", err) } - updateEndpointProxy := shouldReloadTLSConfiguration(endpoint, &payload) - if payload.Name != nil { name := *payload.Name isUnique, err := handler.isNameUnique(name, endpoint.ID) @@ -106,9 +104,8 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * } - if payload.URL != nil && *payload.URL != endpoint.URL { + if payload.URL != nil { endpoint.URL = *payload.URL - updateEndpointProxy = true } if payload.PublicURL != nil { @@ -182,8 +179,6 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * } if endpoint.Type == portainer.AzureEnvironment { - updateEndpointProxy = true - credentials := endpoint.AzureCredentials if payload.AzureApplicationID != nil { credentials.ApplicationID = *payload.AzureApplicationID @@ -252,7 +247,10 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * } } - if updateEndpointProxy { + if (payload.URL != nil && *payload.URL != endpoint.URL) || + (payload.TLS != nil && endpoint.TLSConfig.TLS != *payload.TLS) || + endpoint.Type == portainer.AzureEnvironment || + shouldReloadTLSConfiguration(endpoint, &payload) { handler.ProxyManager.DeleteEndpointProxy(endpoint.ID) _, err = handler.ProxyManager.CreateAndRegisterEndpointProxy(endpoint) if err != nil { @@ -293,12 +291,6 @@ func (handler *Handler) endpointUpdate(w http.ResponseWriter, r *http.Request) * } func shouldReloadTLSConfiguration(endpoint *portainer.Endpoint, payload *endpointUpdatePayload) bool { - - // If we change anything in the tls config then we need to reload the proxy - if payload.TLS != nil && endpoint.TLSConfig.TLS != *payload.TLS { - return true - } - // When updating Docker API environment, as long as TLS is true and TLSSkipVerify is false, // we assume that new TLS files have been uploaded and we need to reload the TLS configuration. if endpoint.Type != portainer.DockerEnvironment || diff --git a/app/docker/__module.js b/app/docker/__module.js index a5ef94fc9..de09c8719 100644 --- a/app/docker/__module.js +++ b/app/docker/__module.js @@ -34,7 +34,7 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([ endpoint.Status = status; if (status === EnvironmentStatus.Down) { - throw new Error(`The environment named ${endpoint.Name} is unreachable.`); + throw new Error('Environment is unreachable.'); } await StateManager.updateEndpointState(endpoint); diff --git a/app/docker/views/dashboard/dashboard.html b/app/docker/views/dashboard/dashboard.html index 5104a06df..655828adb 100644 --- a/app/docker/views/dashboard/dashboard.html +++ b/app/docker/views/dashboard/dashboard.html @@ -18,7 +18,7 @@

Portainer is connected to a node that is part of a Swarm cluster. Some resources located on other nodes in the cluster might not be available for management, have a look at - our agent setup for more details. + our agent setup for more details.

diff --git a/app/edge/views/edge-stacks/editEdgeStackView/editEdgeStackViewController.js b/app/edge/views/edge-stacks/editEdgeStackView/editEdgeStackViewController.js index 02351db9d..503cfa0ec 100644 --- a/app/edge/views/edge-stacks/editEdgeStackView/editEdgeStackViewController.js +++ b/app/edge/views/edge-stacks/editEdgeStackView/editEdgeStackViewController.js @@ -101,7 +101,6 @@ export class EditEdgeStackViewController { edgeGroups: values.edgeGroups, deploymentType: values.deploymentType, updateVersion, - retryDeploy: values.retryDeploy, webhook: values.webhookEnabled ? this.stack.Webhook || createWebhookId() : '', envVars: values.envVars, }); diff --git a/app/kubernetes/__module.js b/app/kubernetes/__module.js index b1f0c01d7..86fc7dc8a 100644 --- a/app/kubernetes/__module.js +++ b/app/kubernetes/__module.js @@ -53,7 +53,7 @@ angular.module('portainer.kubernetes', ['portainer.app', registriesModule, custo try { await getSelfSubjectAccessReview(endpoint.Id, 'default'); } catch (e) { - throw new Error(`The environment named ${endpoint.Name} is unreachable.`); + throw new Error('Environment is unreachable.'); } } catch (e) { let params = {}; diff --git a/app/kubernetes/views/applications/create/createApplication.html b/app/kubernetes/views/applications/create/createApplication.html index 61a0dedac..f088e5b50 100644 --- a/app/kubernetes/views/applications/create/createApplication.html +++ b/app/kubernetes/views/applications/create/createApplication.html @@ -59,94 +59,7 @@

-
-
-
Namespace
- -
- -
- -
-
-
-
- - This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the - namespace. -
-
-
-
- - You do not have access to any namespace. Contact your administrator to get access to a namespace. -
-
- -
- -
- - - -
Actions
-
-
- - - - -
-
- -
+
+ +
- -
Actions
-
-
- - - - +
+
+
Namespace
+ +
+ +
+
+
+
+ + This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of the + namespace. +
+
+
+
+ + You do not have access to any namespace. Contact your administrator to get access to a namespace. +
+
+ +
+ +
+
+ + + + +
Actions
+ +
+
+ + + + +
+
+ diff --git a/app/kubernetes/views/applications/create/createApplicationController.js b/app/kubernetes/views/applications/create/createApplicationController.js index dfe9c6c54..495b151a8 100644 --- a/app/kubernetes/views/applications/create/createApplicationController.js +++ b/app/kubernetes/views/applications/create/createApplicationController.js @@ -1114,10 +1114,10 @@ class KubernetesCreateApplicationController { }); if (this.resourcePools.length) { - this.namespaceWithQuota = await this.KubernetesResourcePoolService.get(this.resourcePools[0].Namespace.Name); - this.formValues.ResourcePool.Quota = this.namespaceWithQuota.Quota; - this.updateNamespaceLimits(this.namespaceWithQuota); - this.updateSliders(this.namespaceWithQuota); + const namespaceWithQuota = await this.KubernetesResourcePoolService.get(this.resourcePools[0].Namespace.Name); + this.formValues.ResourcePool.Quota = namespaceWithQuota.Quota; + this.updateNamespaceLimits(namespaceWithQuota); + this.updateSliders(namespaceWithQuota); } this.formValues.ResourcePool = this.resourcePools[0]; if (!this.formValues.ResourcePool) { @@ -1140,8 +1140,6 @@ class KubernetesCreateApplicationController { this.nodesLabels, this.ingresses ); - - this.formValues.Services = this.formValues.Services || []; this.originalServicePorts = structuredClone(this.formValues.Services.flatMap((service) => service.Ports)); this.originalIngressPaths = structuredClone(this.originalServicePorts.flatMap((port) => port.ingressPaths).filter((ingressPath) => ingressPath.Host)); @@ -1162,8 +1160,6 @@ class KubernetesCreateApplicationController { this.formValues.OriginalIngresses = this.ingresses; this.formValues.ImageModel = await this.parseImageConfiguration(this.formValues.ImageModel); this.savedFormValues = angular.copy(this.formValues); - this.updateNamespaceLimits(this.namespaceWithQuota); - this.updateSliders(this.namespaceWithQuota); delete this.formValues.ApplicationType; if (this.application.ApplicationType !== KubernetesApplicationTypes.STATEFULSET) { diff --git a/app/kubernetes/views/deploy/deployController.js b/app/kubernetes/views/deploy/deployController.js index 4f783cbfc..28414cd24 100644 --- a/app/kubernetes/views/deploy/deployController.js +++ b/app/kubernetes/views/deploy/deployController.js @@ -194,7 +194,7 @@ class KubernetesDeployController { this.state.templateContent = await this.CustomTemplateService.customTemplateFile(templateId, template.GitConfig !== null); this.onChangeFileContent(this.state.templateContent); - this.state.isEditorReadOnly = false; + this.state.isEditorReadOnly = true; } catch (err) { this.state.templateLoadFailed = true; throw err; diff --git a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html index 1625aaccc..b30adf85d 100644 --- a/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html +++ b/app/portainer/components/datatables/stacks-datatable/stacksDatatable.html @@ -144,18 +144,18 @@ diff --git a/app/portainer/components/forms/git-form/git-form-auth-fieldset.controller.ts b/app/portainer/components/forms/git-form/git-form-auth-fieldset.controller.ts index fe3e712aa..84fd23846 100644 --- a/app/portainer/components/forms/git-form/git-form-auth-fieldset.controller.ts +++ b/app/portainer/components/forms/git-form/git-form-auth-fieldset.controller.ts @@ -52,7 +52,7 @@ export default class GitFormAuthFieldsetController { ...newValues, }; this.onChange?.(value); - await this.runGitValidation(value, this.isAuthEdit); + await this.runGitValidation(value, false); } async runGitValidation(value: GitAuthModel, isAuthEdit: boolean) { diff --git a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js index 22e2639e6..2c2146224 100644 --- a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js +++ b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.controller.js @@ -179,14 +179,6 @@ class StackRedeployGitFormController { }); } - disablePullAndRedeployButton() { - return this.isSubmitButtonDisabled() || this.state.hasUnsavedChanges || !this.redeployGitForm.$valid; - } - - disableSaveSettingsButton() { - return this.isSubmitButtonDisabled() || !this.state.hasUnsavedChanges || !this.redeployGitForm.$valid; - } - isSubmitButtonDisabled() { return this.state.inProgress || this.state.redeployInProgress; } diff --git a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.html b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.html index 83ae0521b..cafd75c9b 100644 --- a/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.html +++ b/app/portainer/components/forms/stack-redeploy-git-form/stack-redeploy-git-form.html @@ -75,7 +75,7 @@