@@ -83,7 +87,7 @@
@@ -255,15 +259,7 @@
diff --git a/src/main/webapp/app/admin/user-management/user-management-update.component.ts b/src/main/webapp/app/admin/user-management/user-management-update.component.ts
index 2c4760d74f09..2d7e318f9038 100644
--- a/src/main/webapp/app/admin/user-management/user-management-update.component.ts
+++ b/src/main/webapp/app/admin/user-management/user-management-update.component.ts
@@ -16,7 +16,6 @@ import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { AlertService, AlertType } from 'app/core/util/alert.service';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { AdminUserService } from 'app/core/user/admin-user.service';
-import { CourseManagementService } from 'app/course/manage/course-management.service';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';
import { CourseAdminService } from 'app/course/manage/course-admin.service';
@@ -59,7 +58,6 @@ export class UserManagementUpdateComponent implements OnInit {
constructor(
private languageHelper: JhiLanguageHelper,
private userService: AdminUserService,
- private courseManagementService: CourseManagementService,
private courseAdminService: CourseAdminService,
private route: ActivatedRoute,
private organizationService: OrganizationManagementService,
@@ -232,11 +230,17 @@ export class UserManagementUpdateComponent implements OnInit {
passwordInput: ['', [Validators.minLength(PASSWORD_MIN_LENGTH), Validators.maxLength(PASSWORD_MAX_LENGTH)]],
emailInput: ['', [Validators.required, Validators.minLength(this.EMAIL_MIN_LENGTH), Validators.maxLength(this.EMAIL_MAX_LENGTH)]],
registrationNumberInput: ['', [Validators.maxLength(this.REGISTRATION_NUMBER_MAX_LENGTH)]],
- activatedInput: ['', []],
+ activatedInput: [{ value: this.user.activated }],
langKeyInput: ['', []],
authorityInput: ['', []],
- internalInput: [{ value: this.user.internal, disabled: true }],
+ internalInput: [{ value: this.user.internal, disabled: true }], // initially disabled, will be enabled if user.id is undefined
});
+ // Conditionally enable or disable 'internalInput' based on user.id
+ if (this.user.id !== undefined) {
+ this.editForm.get('internalInput')?.disable(); // Artemis does not support to edit the internal flag for existing users
+ } else {
+ this.editForm.get('internalInput')?.enable(); // New users can either be internal or external
+ }
}
/**
diff --git a/src/main/webapp/app/admin/user-management/user-management.component.html b/src/main/webapp/app/admin/user-management/user-management.component.html
index 129f30d67feb..c8f49ab96a2e 100644
--- a/src/main/webapp/app/admin/user-management/user-management.component.html
+++ b/src/main/webapp/app/admin/user-management/user-management.component.html
@@ -27,13 +27,13 @@
name="searchTerm"
id="field_searchTerm"
formControlName="searchControl"
- [(ngModel)]="searchTerm"
- (focusout)="loadAll()"
+ (blur)="loadAll()"
+ (keydown)="onKeydown($event)"
/>
- @if (searchControl.invalid && (searchControl.dirty || searchControl.touched)) {
+ @if (searchInvalid) {
diff --git a/src/main/webapp/app/admin/user-management/user-management.component.ts b/src/main/webapp/app/admin/user-management/user-management.component.ts
index 5ce57b8d4ed1..f7870f5369cf 100644
--- a/src/main/webapp/app/admin/user-management/user-management.component.ts
+++ b/src/main/webapp/app/admin/user-management/user-management.component.ts
@@ -7,8 +7,8 @@ import { User } from 'app/core/user/user.model';
import { AccountService } from 'app/core/auth/account.service';
import { AlertService } from 'app/core/util/alert.service';
import { SortingOrder } from 'app/shared/table/pageable-table';
-import { debounceTime, switchMap, tap } from 'rxjs/operators';
-import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
+import { switchMap, tap } from 'rxjs/operators';
+import { FormControl, FormGroup } from '@angular/forms';
import { EventManager } from 'app/core/util/event-manager.service';
import { ASC, DESC, ITEMS_PER_PAGE, SORT } from 'app/shared/constants/pagination.constants';
import { faEye, faFilter, faPlus, faSort, faTimes, faWrench } from '@fortawesome/free-solid-svg-icons';
@@ -17,7 +17,6 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { ButtonSize, ButtonType } from 'app/shared/components/button.component';
import { ProfileService } from 'app/shared/layouts/profiles/profile.service';
import { AdminUserService } from 'app/core/user/admin-user.service';
-import { UserService } from 'app/core/user/user.service';
export class UserFilter {
authorityFilter: Set = new Set();
@@ -103,6 +102,7 @@ export class UserManagementComponent implements OnInit, OnDestroy {
predicate!: string;
ascending!: boolean;
searchTermString = '';
+ searchInvalid = false;
isLdapProfileActive: boolean;
// filters
@@ -129,7 +129,6 @@ export class UserManagementComponent implements OnInit, OnDestroy {
constructor(
private adminUserService: AdminUserService,
- private userService: UserService,
private alertService: AlertService,
private accountService: AccountService,
private activatedRoute: ActivatedRoute,
@@ -148,7 +147,6 @@ export class UserManagementComponent implements OnInit, OnDestroy {
this.search
.pipe(
tap(() => (this.loadingSearchResult = true)),
- debounceTime(1000),
switchMap(() =>
this.adminUserService.query(
{
@@ -175,7 +173,7 @@ export class UserManagementComponent implements OnInit, OnDestroy {
});
this.userSearchForm = new FormGroup({
- searchControl: new FormControl('', { validators: [this.validateUserSearch], updateOn: 'blur' }),
+ searchControl: new FormControl('', { updateOn: 'change' }),
});
this.accountService.identity().then((user) => {
this.currentAccount = user!;
@@ -443,17 +441,21 @@ export class UserManagementComponent implements OnInit, OnDestroy {
* Retrieve the list of users from the user service for a single page in the user management based on the page, size and sort configuration
*/
loadAll() {
+ this.searchTerm = this.searchControl.value;
if (this.searchTerm.length >= 3 || this.searchTerm.length === 0) {
+ this.searchInvalid = false;
this.search.next();
+ } else {
+ this.searchInvalid = true;
}
}
/**
* Returns the unique identifier for items in the collection
- * @param index of a user in the collection
+ * @param _index of a user in the collection
* @param item current user
*/
- trackIdentity(index: number, item: User) {
+ trackIdentity(_index: number, item: User) {
return item.id ?? -1;
}
@@ -520,14 +522,14 @@ export class UserManagementComponent implements OnInit, OnDestroy {
return this.searchTermString;
}
- validateUserSearch(control: AbstractControl) {
- if (control.value.length >= 1 && control.value.length <= 2) {
- return { searchControl: true };
- }
- return null;
- }
-
get searchControl() {
return this.userSearchForm.get('searchControl')!;
}
+
+ onKeydown(event: KeyboardEvent) {
+ if (event.key === 'Enter') {
+ event.preventDefault(); // Prevent the default form submission behavior
+ this.loadAll(); // Trigger the search logic
+ }
+ }
}
diff --git a/src/main/webapp/app/admin/user-management/user-management.route.ts b/src/main/webapp/app/admin/user-management/user-management.route.ts
index e98972a5c3f0..df2178c4a68b 100644
--- a/src/main/webapp/app/admin/user-management/user-management.route.ts
+++ b/src/main/webapp/app/admin/user-management/user-management.route.ts
@@ -51,7 +51,7 @@ export const userManagementRoute: Route[] = [
path: 'edit',
component: UserManagementUpdateComponent,
data: {
- pageTitle: 'artemisApp.userManagement.home.createOrEditLabel',
+ pageTitle: 'artemisApp.userManagement.home.editLabel',
},
},
],
diff --git a/src/main/webapp/i18n/de/user-management.json b/src/main/webapp/i18n/de/user-management.json
index 365abf875684..6be2470bd4fd 100644
--- a/src/main/webapp/i18n/de/user-management.json
+++ b/src/main/webapp/i18n/de/user-management.json
@@ -64,7 +64,7 @@
"home": {
"title": "Nutzer:in",
"createLabel": "Nutzer:in erstellen",
- "createOrEditLabel": "Nutzer:in erstellen oder bearbeiten"
+ "editLabel": "Nutzer:in bearbeiten"
},
"created": "Nutzer:in wurde mit ID {{ param }} erstellt",
"updated": "Nutzer:in mit ID {{ param }} wurde geändert",
@@ -93,7 +93,7 @@
"profiles": "Profile",
"langKey": "Sprache",
"internal": "Intern",
- "passwordTooltip": "Du kannst nur Passwörter für interne Nutzer:innen ändern.",
+ "passwordTooltip": "Du kannst diese Einstellung nur für neue Nutzer:innen ändern. Bitte beachte, dass du nur Passwörter für interne Nutzer:innen ändern kannst.",
"createdBy": "Erstellt von",
"createdDate": "Erstellt am",
"lastModifiedBy": "Bearbeitet von",
diff --git a/src/main/webapp/i18n/en/user-management.json b/src/main/webapp/i18n/en/user-management.json
index 689da224ef2d..f730d94045d4 100644
--- a/src/main/webapp/i18n/en/user-management.json
+++ b/src/main/webapp/i18n/en/user-management.json
@@ -64,7 +64,7 @@
"home": {
"title": "Users",
"createLabel": "Create a new user",
- "createOrEditLabel": "Create or edit a user"
+ "editLabel": "Edit user"
},
"created": "Created new user with identifier {{ param }}",
"updated": "Updated User with identifier {{ param }}",
@@ -92,7 +92,7 @@
"deactivated": "Deactivated",
"profiles": "Profiles",
"langKey": "Language",
- "passwordTooltip": "You can only change passwords for internal users.",
+ "passwordTooltip": "This setting can only be changed for new users. Notice, that you can only change passwords for internal users.",
"internal": "Internal",
"createdBy": "Created by",
"createdDate": "Created date",
diff --git a/src/test/javascript/spec/component/admin/user-management.component.spec.ts b/src/test/javascript/spec/component/admin/user-management.component.spec.ts
index 4b2ee62e13a4..a4c5dda88562 100644
--- a/src/test/javascript/spec/component/admin/user-management.component.spec.ts
+++ b/src/test/javascript/spec/component/admin/user-management.component.spec.ts
@@ -14,7 +14,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { HttpHeaders, HttpParams, HttpResponse, provideHttpClient } from '@angular/common/http';
import { User } from 'app/core/user/user.model';
import { Subscription, of } from 'rxjs';
-import { AbstractControl, ReactiveFormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
import { ItemCountComponent } from 'app/shared/pagination/item-count.component';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { ArtemisDatePipe } from 'app/shared/pipes/artemis-date.pipe';
@@ -168,7 +168,7 @@ describe('UserManagementComponent', () => {
// THEN
expect(userService.update).toHaveBeenCalledWith({ ...user, activated: true });
- expect(userService.query).toHaveBeenCalledOnce();
+ expect(userService.query).toHaveBeenCalledTimes(2);
expect(comp.users && comp.users[0]).toEqual(expect.objectContaining({ id: 123 }));
expect(profileSpy).toHaveBeenCalledOnce();
}),
@@ -243,14 +243,17 @@ describe('UserManagementComponent', () => {
jest.restoreAllMocks();
});
- it('should validate user search correctly', () => {
- expect(comp.validateUserSearch({ value: [] } as AbstractControl)).toBeNull();
- expect(comp.validateUserSearch({ value: [0] } as AbstractControl)).toEqual({ searchControl: true });
- expect(comp.validateUserSearch({ value: [0, 0] } as AbstractControl)).toEqual({ searchControl: true });
- expect(comp.validateUserSearch({ value: [0, 0, 0] } as AbstractControl)).toBeNull();
- });
-
it('should call initFilters', () => {
+ const headers = new HttpHeaders().append('link', 'link;link');
+ const user = new User(123);
+ jest.spyOn(userService, 'query').mockReturnValue(
+ of(
+ new HttpResponse({
+ body: [user],
+ headers,
+ }),
+ ),
+ );
const spy = jest.spyOn(comp, 'initFilters');
const initSpy = jest.spyOn(profileService, 'getProfileInfo').mockReturnValue(of(new ProfileInfo()));
@@ -258,6 +261,7 @@ describe('UserManagementComponent', () => {
expect(spy).toHaveBeenCalledOnce();
expect(initSpy).toHaveBeenCalledOnce();
+ expect(userService.query).toHaveBeenCalledTimes(0);
});
it.each`