diff --git a/api/http/handler/stacks/stack_update_git.go b/api/http/handler/stacks/stack_update_git.go index 12bae9bc0..7a56f7278 100644 --- a/api/http/handler/stacks/stack_update_git.go +++ b/api/http/handler/stacks/stack_update_git.go @@ -151,6 +151,9 @@ func (handler *Handler) stackUpdateGit(w http.ResponseWriter, r *http.Request) * if payload.RepositoryAuthentication { password := payload.RepositoryPassword + + // When the existing stack is using the custom username/password and the password is not updated, + // the stack should keep using the saved username/password if password == "" && stack.GitConfig != nil && stack.GitConfig.Authentication != nil { password = stack.GitConfig.Authentication.Password } diff --git a/api/http/handler/stacks/stack_update_git_redeploy.go b/api/http/handler/stacks/stack_update_git_redeploy.go index 9c33401b3..b30085156 100644 --- a/api/http/handler/stacks/stack_update_git_redeploy.go +++ b/api/http/handler/stacks/stack_update_git_redeploy.go @@ -139,6 +139,9 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request) repositoryPassword := "" if payload.RepositoryAuthentication { repositoryPassword = payload.RepositoryPassword + + // When the existing stack is using the custom username/password and the password is not updated, + // the stack should keep using the saved username/password if repositoryPassword == "" && stack.GitConfig != nil && stack.GitConfig.Authentication != nil { repositoryPassword = stack.GitConfig.Authentication.Password } 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 1c8350c85..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 @@ -7,6 +7,7 @@ import { GitAuthModel } from '@/react/portainer/gitops/types'; import { gitAuthValidation } from '@/react/portainer/gitops/AuthFieldset'; import { GitCredential } from '@/react/portainer/account/git-credentials/types'; import { getGitCredentials } from '@/react/portainer/account/git-credentials/git-credentials.service'; +import { isBE } from '@/react/portainer/feature-flags/feature-flags.service'; import { validateForm } from '@@/form-components/validate-form'; @@ -23,6 +24,8 @@ export default class GitFormAuthFieldsetController { value?: GitAuthModel; + isAuthEdit: boolean; + onChange?: (value: GitAuthModel) => void; /* @ngInject */ @@ -33,6 +36,7 @@ export default class GitFormAuthFieldsetController { this.$async = $async; this.Authentication = Authentication; + this.isAuthEdit = false; this.handleChange = this.handleChange.bind(this); this.runGitValidation = this.runGitValidation.bind(this); } @@ -48,10 +52,10 @@ export default class GitFormAuthFieldsetController { ...newValues, }; this.onChange?.(value); - await this.runGitValidation(value); + await this.runGitValidation(value, false); } - async runGitValidation(value: GitAuthModel) { + async runGitValidation(value: GitAuthModel, isAuthEdit: boolean) { return this.$async(async () => { this.errors = {}; this.gitFormAuthFieldset?.$setValidity( @@ -61,7 +65,7 @@ export default class GitFormAuthFieldsetController { ); this.errors = await validateForm( - () => gitAuthValidation(this.gitCredentials), + () => gitAuthValidation(this.gitCredentials, isAuthEdit), value ); if (this.errors && Object.keys(this.errors).length > 0) { @@ -75,23 +79,24 @@ export default class GitFormAuthFieldsetController { } async $onInit() { - try { - this.gitCredentials = await getGitCredentials( - this.Authentication.getUserDetails().ID - ); - } catch (err) { - notifyError( - 'Failure', - err as Error, - 'Unable to retrieve user saved git credentials' - ); + if (isBE) { + try { + // Only BE version support /gitcredentials + this.gitCredentials = await getGitCredentials( + this.Authentication.getUserDetails().ID + ); + } catch (err) { + notifyError( + 'Failure', + err as Error, + 'Unable to retrieve user saved git credentials' + ); + } } - // this should never happen, but just in case if (!this.value) { throw new Error('GitFormController: value is required'); } - - await this.runGitValidation(this.value); + await this.runGitValidation(this.value, this.isAuthEdit); } } diff --git a/app/portainer/components/forms/git-form/git-form-auth-fieldset.ts b/app/portainer/components/forms/git-form/git-form-auth-fieldset.ts index c0713dae7..702b74f3a 100644 --- a/app/portainer/components/forms/git-form/git-form-auth-fieldset.ts +++ b/app/portainer/components/forms/git-form/git-form-auth-fieldset.ts @@ -9,13 +9,15 @@ export const gitFormAuthFieldset: IComponentOptions = { + is-auth-explanation-visible="$ctrl.isAuthExplanationVisible" + errors="$ctrl.errors" + is-auth-edit="$ctrl.isAuthEdit"> `, bindings: { value: '<', onChange: '<', - isExplanationVisible: '<', + isAuthExplanationVisible: '<', + isAuthEdit: '<', }, }; diff --git a/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.controller.js b/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.controller.js index d040fa015..bb636b9e9 100644 --- a/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.controller.js +++ b/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.controller.js @@ -18,6 +18,15 @@ class KubernetesRedeployAppGitFormController { redeployInProgress: false, showConfig: false, isEdit: false, + + // isAuthEdit is used to preserve the editing state of the AuthFieldset component. + // Within the stack editing page, users have the option to turn the AuthFieldset on or off + // and save the stack setting. If the user enables the AuthFieldset, it implies that they + // must input new Git authentication, rather than edit existing authentication. Thus, + // a dedicated state tracker is required to differentiate between the editing state of + // AuthFieldset component and the whole stack + // When isAuthEdit is true, PAT field needs to be validated. + isAuthEdit: false, hasUnsavedChanges: false, baseWebhookUrl: baseStackWebhookUrl(), webhookId: createWebhookId(), @@ -121,6 +130,13 @@ class KubernetesRedeployAppGitFormController { await this.StackService.updateKubeStack({ EndpointId: this.stack.EndpointId, Id: this.stack.Id }, { gitConfig: this.formValues, webhookId: this.state.webhookId }); this.savedFormValues = angular.copy(this.formValues); this.state.hasUnsavedChanges = false; + + if (!(this.stack.GitConfig && this.stack.GitConfig.Authentication)) { + // update the AuthFieldset setting + this.state.isAuthEdit = false; + this.formValues.RepositoryUsername = ''; + this.formValues.RepositoryPassword = ''; + } this.Notifications.success('Success', 'Save stack settings successfully'); } catch (err) { this.Notifications.error('Failure', err, 'Unable to save application settings'); @@ -139,14 +155,17 @@ class KubernetesRedeployAppGitFormController { this.formValues.AutoUpdate = parseAutoUpdateResponse(this.stack.AutoUpdate); - if (this.stack.AutoUpdate.Webhook) { + if (this.stack.AutoUpdate && this.stack.AutoUpdate.Webhook) { this.state.webhookId = this.stack.AutoUpdate.Webhook; } if (this.stack.GitConfig && this.stack.GitConfig.Authentication) { this.formValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username; + this.formValues.RepositoryPassword = this.stack.GitConfig.Authentication.Password; + this.formValues.RepositoryAuthentication = true; this.state.isEdit = true; + this.state.isAuthEdit = true; } this.savedFormValues = angular.copy(this.formValues); diff --git a/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.html b/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.html index e2939dfc9..a149d9c9c 100644 --- a/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.html +++ b/app/portainer/components/forms/kubernetes-redeploy-app-git-form/kubernetes-redeploy-app-git-form.html @@ -35,6 +35,14 @@ is-url-valid="true" > + +
Actions