You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2025/08/28 07:20:07 UTC
(streampipes) 02/02: fix bug in user form
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 <do...@gmail.com>
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> 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> 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[] {