This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch add-optional-terms-acknowledgment
in repository https://gitbox.apache.org/repos/asf/streampipes.git

commit fa10c95cd464953b49ddfa6ff0fc7458b41e7f12
Author: Dominik Riemer <[email protected]>
AuthorDate: Thu Aug 28 09:19:43 2025 +0200

    fix bug in user form
---
 .../edit-user-dialog.component.html                | 342 +++++++++++----------
 .../edit-user-dialog/edit-user-dialog.component.ts | 145 ++++++---
 2 files changed, 269 insertions(+), 218 deletions(-)

diff --git 
a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html
 
b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html
index d46527b426..9b057f8c88 100644
--- 
a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html
+++ 
b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.html
@@ -16,185 +16,193 @@
   ~
   -->
 
-<div class="sp-dialog-container">
-    <div class="sp-dialog-content">
-        <div fxFlex="100" fxLayout="column" class="p-15">
-            <sp-warning-box *ngIf="isUserAccount && isExternalProvider">
-                Settings of externally-managed users cannot be changed.
-            </sp-warning-box>
-            <form [formGroup]="parentForm" fxFlex="100" fxLayout="column">
-                <div class="general-options-panel" fxLayout="column">
-                    <span class="general-options-header">Basics</span>
-                    <mat-error *ngIf="registrationError">{{
-                        registrationError
-                    }}</mat-error>
-                    <mat-form-field color="accent" *ngIf="!isUserAccount">
-                        <mat-label>Username</mat-label>
-                        <input
-                            formControlName="username"
-                            fxFlex
-                            matInput
-                            required
-                        />
-                    </mat-form-field>
-                    <mat-form-field color="accent" *ngIf="isUserAccount">
-                        <mat-label>Email</mat-label>
-                        <input
-                            formControlName="username"
-                            fxFlex
-                            type="email"
-                            matInput
-                            data-cy="new-user-email"
-                        />
-                        <mat-error>Must be a valid email address.</mat-error>
-                    </mat-form-field>
-                    <div class="email-changed" *ngIf="emailChanged">
-                        Changing the current user's email will require a
-                        re-login.
+@if (formAvailable) {
+    <div class="sp-dialog-container">
+        <div class="sp-dialog-content">
+            <div fxFlex="100" fxLayout="column" class="p-15">
+                <sp-warning-box *ngIf="isUserAccount && isExternalProvider">
+                    Settings of externally-managed users cannot be changed.
+                </sp-warning-box>
+                <form [formGroup]="parentForm" fxFlex="100" fxLayout="column">
+                    <div class="general-options-panel" fxLayout="column">
+                        <span class="general-options-header">Basics</span>
+                        <mat-error *ngIf="registrationError">{{
+                            registrationError
+                        }}</mat-error>
+                        <mat-form-field color="accent" *ngIf="!isUserAccount">
+                            <mat-label>Username</mat-label>
+                            <input
+                                formControlName="username"
+                                fxFlex
+                                matInput
+                                required
+                            />
+                        </mat-form-field>
+                        <mat-form-field color="accent" *ngIf="isUserAccount">
+                            <mat-label>Email</mat-label>
+                            <input
+                                formControlName="username"
+                                fxFlex
+                                type="email"
+                                matInput
+                                data-cy="new-user-email"
+                            />
+                            <mat-error
+                                >Must be a valid email address.</mat-error
+                            >
+                        </mat-form-field>
+                        <div class="email-changed" *ngIf="emailChanged">
+                            Changing the current user's email will require a
+                            re-login.
+                        </div>
+                        <mat-form-field color="accent" *ngIf="isUserAccount">
+                            <mat-label>Full Name</mat-label>
+                            <input
+                                formControlName="fullName"
+                                fxFlex
+                                matInput
+                                data-cy="new-user-full-name"
+                            />
+                        </mat-form-field>
                     </div>
-                    <mat-form-field color="accent" *ngIf="isUserAccount">
-                        <mat-label>Full Name</mat-label>
-                        <input
-                            formControlName="fullName"
-                            fxFlex
-                            matInput
-                            data-cy="new-user-full-name"
-                        />
-                    </mat-form-field>
-                </div>
-                <div
-                    fxLayout="column"
-                    class="general-options-panel"
-                    *ngIf="!editMode && isUserAccount"
-                >
-                    <span class="general-options-header">Password</span>
-                    <mat-checkbox
-                        formControlName="sendPasswordToUser"
-                        *ngIf="emailConfigured"
-                        >Auto-create password and send to user</mat-checkbox
-                    >
-                    <mat-form-field color="accent" *ngIf="!sendPasswordToUser">
-                        <mat-label>Initial password</mat-label>
-                        <input
-                            formControlName="password"
-                            fxFlex
-                            type="password"
-                            matInput
-                            required
-                            data-cy="new-user-password"
-                        />
-                    </mat-form-field>
-                    <mat-form-field color="accent" *ngIf="!sendPasswordToUser">
-                        <mat-label>Repeat password</mat-label>
-                        <input
-                            formControlName="repeatPassword"
-                            fxFlex
-                            type="password"
-                            matInput
-                            required
-                            data-cy="new-user-password-repeat"
-                        />
-                    </mat-form-field>
-                    <mat-error *ngIf="parentForm.hasError('notMatching')"
-                        >Passwords do not match.</mat-error
-                    >
-                </div>
-                <div
-                    fxLayout="column"
-                    class="general-options-panel"
-                    *ngIf="!isUserAccount"
-                >
-                    <span class="general-options-header">Authentication</span>
-                    <mat-form-field color="accent">
-                        <mat-label>Client Secret</mat-label>
-                        <input
-                            formControlName="clientSecret"
-                            fxFlex
-                            type="password"
-                            matInput
-                            required
-                        />
-                    </mat-form-field>
-                    <mat-error *ngIf="parentForm.controls.clientSecret.errors"
-                        >Minimum length 35 characters.</mat-error
-                    >
-                </div>
-                <div fxLayout="column" class="general-options-panel">
-                    <span class="general-options-header">Groups</span>
-                    <mat-checkbox
-                        *ngFor="let group of availableGroups"
-                        [disabled]="
-                            isExternalProvider && isExternallyManagedRoles
-                        "
-                        [value]="group.groupId"
-                        [checked]="user.groups.indexOf(group.groupId) > -1"
-                        (change)="changeGroupAssignment($event)"
+                    <div
+                        fxLayout="column"
+                        class="general-options-panel"
+                        *ngIf="!editMode && isUserAccount"
                     >
-                        {{ group.groupName }}
-                    </mat-checkbox>
-                </div>
-                <div fxLayout="column" class="general-options-panel">
-                    <span class="general-options-header">Roles</span>
-                    <mat-checkbox
-                        *ngFor="let role of availableRoles$ | async"
-                        [value]="role.elementId"
-                        [disabled]="
-                            isExternalProvider && isExternallyManagedRoles
-                        "
-                        [checked]="user.roles.indexOf(role.elementId) > -1"
-                        (change)="changeRoleAssignment($event)"
-                        [attr.data-cy]="'role-' + role.elementId"
+                        <span class="general-options-header">Password</span>
+                        <mat-checkbox
+                            formControlName="sendPasswordToUser"
+                            *ngIf="emailConfigured"
+                            >Auto-create password and send to 
user</mat-checkbox
+                        >
+                        <mat-form-field color="accent">
+                            <mat-label>Initial password</mat-label>
+                            <input
+                                formControlName="password"
+                                fxFlex
+                                type="password"
+                                matInput
+                                required
+                                data-cy="new-user-password"
+                            />
+                        </mat-form-field>
+                        <mat-form-field color="accent">
+                            <mat-label>Repeat password</mat-label>
+                            <input
+                                formControlName="repeatPassword"
+                                fxFlex
+                                type="password"
+                                matInput
+                                required
+                                data-cy="new-user-password-repeat"
+                            />
+                        </mat-form-field>
+                        <mat-error *ngIf="parentForm.hasError('notMatching')"
+                            >Passwords do not match.</mat-error
+                        >
+                    </div>
+                    <div
+                        fxLayout="column"
+                        class="general-options-panel"
+                        *ngIf="!isUserAccount"
                     >
-                        {{ role.label }}
-                    </mat-checkbox>
-                </div>
-                @if (!isExternalProvider) {
+                        <span class="general-options-header"
+                            >Authentication</span
+                        >
+                        <mat-form-field color="accent">
+                            <mat-label>Client Secret</mat-label>
+                            <input
+                                formControlName="clientSecret"
+                                fxFlex
+                                type="password"
+                                matInput
+                                required
+                            />
+                        </mat-form-field>
+                        <mat-error
+                            *ngIf="parentForm.controls.clientSecret.errors"
+                            >Minimum length 35 characters.</mat-error
+                        >
+                    </div>
                     <div fxLayout="column" class="general-options-panel">
-                        <span class="general-options-header">Account</span>
+                        <span class="general-options-header">Groups</span>
                         <mat-checkbox
-                            formControlName="accountEnabled"
-                            data-cy="new-user-enabled"
+                            *ngFor="let group of availableGroups"
+                            [disabled]="
+                                isExternalProvider && isExternallyManagedRoles
+                            "
+                            [value]="group.groupId"
+                            [checked]="user.groups.indexOf(group.groupId) > -1"
+                            (change)="changeGroupAssignment($event)"
                         >
-                            Enabled
+                            {{ group.groupName }}
                         </mat-checkbox>
+                    </div>
+                    <div fxLayout="column" class="general-options-panel">
+                        <span class="general-options-header">Roles</span>
                         <mat-checkbox
-                            formControlName="accountLocked"
-                            data-cy="new-user-locked"
+                            *ngFor="let role of availableRoles$ | async"
+                            [value]="role.elementId"
+                            [disabled]="
+                                isExternalProvider && isExternallyManagedRoles
+                            "
+                            [checked]="user.roles.indexOf(role.elementId) > -1"
+                            (change)="changeRoleAssignment($event)"
+                            [attr.data-cy]="'role-' + role.elementId"
                         >
-                            Locked
+                            {{ role.label }}
                         </mat-checkbox>
                     </div>
-                }
-            </form>
+                    @if (!isExternalProvider) {
+                        <div fxLayout="column" class="general-options-panel">
+                            <span class="general-options-header">Account</span>
+                            <mat-checkbox
+                                formControlName="accountEnabled"
+                                data-cy="new-user-enabled"
+                            >
+                                Enabled
+                            </mat-checkbox>
+                            <mat-checkbox
+                                formControlName="accountLocked"
+                                data-cy="new-user-locked"
+                            >
+                                Locked
+                            </mat-checkbox>
+                        </div>
+                    }
+                </form>
+            </div>
         </div>
-    </div>
-    <mat-divider></mat-divider>
-    <div class="sp-dialog-actions">
-        <div fxLayout="column">
-            <div fxLayout="row">
-                <button
-                    mat-button
-                    mat-raised-button
-                    color="accent"
-                    (click)="save()"
-                    style="margin-right: 10px"
-                    [disabled]="
-                        parentForm.invalid ||
-                        (isExternalProvider && isExternallyManagedRoles)
-                    "
-                    data-cy="sp-element-edit-user-save"
-                >
-                    <i class="material-icons">save</i><span>&nbsp;Save</span>
-                </button>
-                <button
-                    mat-button
-                    mat-raised-button
-                    class="mat-basic"
-                    (click)="close(false)"
-                >
-                    Cancel
-                </button>
+        <mat-divider></mat-divider>
+        <div class="sp-dialog-actions">
+            <div fxLayout="column">
+                <div fxLayout="row">
+                    <button
+                        mat-button
+                        mat-raised-button
+                        color="accent"
+                        (click)="save()"
+                        style="margin-right: 10px"
+                        [disabled]="
+                            parentForm.invalid ||
+                            (isExternalProvider && isExternallyManagedRoles)
+                        "
+                        data-cy="sp-element-edit-user-save"
+                    >
+                        <i class="material-icons">save</i
+                        ><span>&nbsp;Save</span>
+                    </button>
+                    <button
+                        mat-button
+                        mat-raised-button
+                        class="mat-basic"
+                        (click)="close(false)"
+                    >
+                        Cancel
+                    </button>
+                </div>
             </div>
         </div>
     </div>
-</div>
+}
diff --git 
a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts
 
b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts
index a6ff998ed0..b00a75a65c 100644
--- 
a/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts
+++ 
b/ui/src/app/configuration/security-configuration/edit-user-dialog/edit-user-dialog.component.ts
@@ -29,6 +29,7 @@ import {
 } from '@streampipes/platform-services';
 import {
     AbstractControl,
+    FormControl,
     UntypedFormBuilder,
     UntypedFormControl,
     UntypedFormGroup,
@@ -72,6 +73,7 @@ export class EditUserDialogComponent implements OnInit {
     sendPasswordToUser = false;
     emailChanged = false;
     emailConfigured = false;
+    formAvailable = false;
 
     constructor(
         private dialogRef: DialogRef<EditUserDialogComponent>,
@@ -89,8 +91,6 @@ export class EditUserDialogComponent implements OnInit {
         this.initRoleFilter();
         this.loadInitialData();
         this.cloneUser();
-        this.initForm();
-        this.handleFormChanges();
     }
 
     save() {
@@ -103,6 +103,48 @@ export class EditUserDialogComponent implements OnInit {
                 : 'Unknown error';
         };
 
+        if (!this.isUserAccount || !this.isExternalProvider) {
+            this.clonedUser.username = this.parentForm.get('username').value;
+        }
+
+        if (!this.isExternalProvider) {
+            this.clonedUser.accountLocked =
+                this.parentForm.get('accountLocked').value;
+            this.clonedUser.accountEnabled =
+                this.parentForm.get('accountEnabled').value;
+        }
+
+        if (this.clonedUser instanceof UserAccount) {
+            this.emailChanged =
+                this.clonedUser.username !== this.user.username &&
+                this.user.username ===
+                    this.currentUserService.getCurrentUser().username &&
+                this.editMode;
+
+            if (!this.isExternalProvider) {
+                this.clonedUser.fullName =
+                    this.parentForm.get('fullName').value;
+            }
+            if (!this.editMode) {
+                if (
+                    this.emailConfigured &&
+                    this.parentForm.get('sendPasswordToUser').value
+                ) {
+                    this.sendPasswordToUser =
+                        this.parentForm.get('sendPasswordToUser').value;
+                } else {
+                    this.clonedUser.password =
+                        this.parentForm.get('password').value;
+                }
+            }
+        } else {
+            const clientSecret = this.parentForm.get('clientSecret').value;
+            if (this.user.clientSecret !== clientSecret) {
+                this.clonedUser.clientSecret = clientSecret;
+                this.clonedUser.secretEncrypted = false;
+            }
+        }
+
         if (this.editMode) {
             const update$ = this.isUserAccount
                 ? this.userService.updateUser(this.clonedUser as UserAccount)
@@ -150,6 +192,9 @@ export class EditUserDialogComponent implements OnInit {
     private loadInitialData(): void {
         this.mailConfigService.getMailConfig().subscribe(config => {
             this.emailConfigured = config.emailConfigured;
+            this.initForm();
+            this.handleFormChanges();
+            this.formAvailable = true;
         });
 
         this.userGroupService.getAllUserGroups().subscribe(groups => {
@@ -193,12 +238,6 @@ export class EditUserDialogComponent implements OnInit {
             ];
         }
 
-        if (!this.editMode && this.clonedUser instanceof UserAccount) {
-            form['password'] = [this.clonedUser.password, Validators.required];
-            form['repeatPassword'] = [''];
-            form['sendPasswordToUser'] = [this.sendPasswordToUser];
-        }
-
         this.parentForm = this.fb.group(form, {
             validators:
                 this.editMode || !this.isUserAccount
@@ -206,6 +245,20 @@ export class EditUserDialogComponent implements OnInit {
                     : this.checkPasswords,
         });
 
+        if (!this.editMode && this.clonedUser instanceof UserAccount) {
+            if (this.emailConfigured) {
+                this.parentForm.addControl(
+                    'sendPasswordToUser',
+                    new FormControl(this.sendPasswordToUser),
+                );
+            }
+            this.parentForm.addControl(
+                'password',
+                new FormControl(null, [Validators.required]),
+            );
+            this.parentForm.addControl('repeatPassword', new 
FormControl(null));
+        }
+
         if (this.isExternalProvider) {
             this.parentForm.get('username')?.disable();
             this.parentForm.get('fullName')?.disable();
@@ -214,67 +267,57 @@ export class EditUserDialogComponent implements OnInit {
 
     private handleFormChanges(): void {
         this.parentForm.valueChanges.subscribe(v => {
-            const raw = this.parentForm.getRawValue();
-            if (!this.isUserAccount || !this.isExternalProvider) {
-                this.clonedUser.username = v.username;
-            }
-
-            if (!this.isExternalProvider) {
-                this.clonedUser.accountLocked = raw.accountLocked;
-                this.clonedUser.accountEnabled = raw.accountEnabled;
-            }
-
-            if (this.clonedUser instanceof UserAccount) {
-                this.emailChanged =
-                    this.clonedUser.username !== this.user.username &&
-                    this.user.username ===
-                        this.currentUserService.getCurrentUser().username &&
-                    this.editMode;
-
-                if (!this.isExternalProvider) {
-                    this.clonedUser.fullName = v.fullName;
-                }
-
-                if (!this.editMode) {
+            if (this.clonedUser instanceof UserAccount && !this.editMode) {
+                if (this.sendPasswordToUser !== v.sendPasswordToUser) {
                     this.sendPasswordToUser = v.sendPasswordToUser;
-
                     if (this.sendPasswordToUser) {
                         this.removePasswordControls();
                     } else {
                         this.addPasswordControlsIfMissing();
-                        this.clonedUser.password = v.password;
                     }
                 }
-            } else {
-                if (this.user.clientSecret !== v.clientSecret) {
-                    this.clonedUser.clientSecret = v.clientSecret;
-                    this.clonedUser.secretEncrypted = false;
-                }
             }
         });
     }
 
     private removePasswordControls(): void {
-        this.parentForm.removeControl('password');
-        this.parentForm.removeControl('repeatPassword');
-        this.parentForm.clearValidators();
+        const pw = this.parentForm.get('password');
+        const rp = this.parentForm.get('repeatPassword');
+        pw.setValue(null);
+        rp.setValue(null);
+
+        pw?.clearValidators();
+        rp?.clearValidators();
+
+        pw?.disable({ emitEvent: false });
+        rp?.disable({ emitEvent: false });
+
+        pw?.updateValueAndValidity({ emitEvent: false });
+        rp?.updateValueAndValidity({ emitEvent: false });
+
+        this.parentForm.setValidators(null);
+        this.parentForm.updateValueAndValidity({ emitEvent: false });
+
         if (this.clonedUser instanceof UserAccount) {
             this.clonedUser.password = undefined;
         }
     }
 
     private addPasswordControlsIfMissing(): void {
-        if (!this.parentForm.get('password')) {
-            this.parentForm.addControl(
-                'password',
-                new UntypedFormControl('', Validators.required),
-            );
-            this.parentForm.addControl(
-                'repeatPassword',
-                new UntypedFormControl(),
-            );
-            this.parentForm.setValidators(this.checkPasswords);
-        }
+        const pw = this.parentForm.get('password');
+        const rp = this.parentForm.get('repeatPassword');
+
+        pw?.enable({ emitEvent: false });
+        rp?.enable({ emitEvent: false });
+
+        pw?.setValidators([Validators.required]);
+        rp?.setValidators([Validators.required]);
+
+        this.parentForm.addValidators(this.checkPasswords);
+
+        pw?.updateValueAndValidity({ emitEvent: false });
+        rp?.updateValueAndValidity({ emitEvent: false });
+        this.parentForm.updateValueAndValidity({ emitEvent: false });
     }
 
     private getUsernameValidators(): ValidatorFn[] {

Reply via email to