Browse Source

UserInfo

pull/282/head
Sebastian Stehle 8 years ago
parent
commit
763931fa74
  1. 2
      src/Squidex/app/features/administration/pages/users/user-page.component.html
  2. 14
      src/Squidex/app/features/administration/pages/users/user-page.component.ts
  3. 21
      src/Squidex/app/features/administration/pages/users/users-page.component.html
  4. 13
      src/Squidex/app/features/administration/pages/users/users-page.component.ts
  5. 34
      src/Squidex/app/features/administration/state/users.state.spec.ts
  6. 46
      src/Squidex/app/features/administration/state/users.state.ts

2
src/Squidex/app/features/administration/pages/users/user-page.component.html

@ -40,7 +40,7 @@
<input type="text" class="form-control" id="displayName" maxlength="100" formControlName="displayName" autocomplete="false" />
</div>
<div class="form-group form-group-password" [class.hidden]="usersState.isCurrentUser | async">
<div class="form-group form-group-password" [class.hidden]="user.isCurrentUser">
<div class="form-group">
<label for="password">Password</label>

14
src/Squidex/app/features/administration/pages/users/user-page.component.ts

@ -20,7 +20,8 @@ import { UserForm, UsersState } from './../../state/users.state';
})
export class UserPageComponent implements OnDestroy, OnInit {
private selectedUserSubscription: Subscription;
private user?: UserDto;
public user?: { user: UserDto, isCurrentUser: boolean };
public userForm = new UserForm(this.formBuilder);
@ -39,9 +40,12 @@ export class UserPageComponent implements OnDestroy, OnInit {
public ngOnInit() {
this.selectedUserSubscription =
this.usersState.selectedUser
.subscribe(user => {
this.user = user;
this.userForm.load(user);
.subscribe(selectedUser => {
this.user = selectedUser;
if (selectedUser) {
this.userForm.load(selectedUser.user);
}
});
}
@ -50,7 +54,7 @@ export class UserPageComponent implements OnDestroy, OnInit {
if (value) {
if (this.user) {
this.usersState.update(this.user, value)
this.usersState.update(this.user.user, value)
.subscribe(user => {
this.userForm.submitCompleted();
}, error => {

21
src/Squidex/app/features/administration/pages/users/users-page.component.html

@ -6,7 +6,7 @@
</ng-container>
<ng-container menu>
<button class="btn btn-link btn-secondary" (click)="load(true)" title="Refresh Users (CTRL + SHIFT + R)">
<button class="btn btn-link btn-secondary" (click)="reload()" title="Refresh Users (CTRL + SHIFT + R)">
<i class="icon-reset"></i> Refresh
</button>
@ -49,27 +49,28 @@
<div sqxIgnoreScrollbar>
<table class="table table-items table-fixed">
<tbody>
<ng-template ngFor let-user [ngForOf]="usersState.users | async" [ngForTrackBy]="trackByUser">
<tr [routerLink]="user.id" routerLinkActive="active">
<ng-template ngFor let-userInfo [ngForOf]="usersState.users | async" [ngForTrackBy]="trackByUser">
<tr [routerLink]="userInfo.user.id" routerLinkActive="active">
<td class="cell-user">
<img class="user-picture" [attr.title]="user.name" [attr.src]="user | sqxUserDtoPicture" />
<img class="user-picture" [attr.title]="userInfo.user.name" [attr.src]="userInfo.user | sqxUserDtoPicture" />
</td>
<td class="cell-auto">
<span class="user-name table-cell">{{user.displayName}}</span>
<span class="user-name table-cell">{{userInfo.user.displayName}}</span>
</td>
<td class="cell-auto">
<span class="user-email table-cell">{{user.email}}</span>
<span class="user-email table-cell">{{userInfo.user.email}}</span>
</td>
<td class="cell-actions">
<ng-container *ngIf="user.id !== authState.user?.id">
<button class="btn btn-link" (click)="lock(user); $event.stopPropagation();" *ngIf="!user.isLocked" title="Lock User">
<ng-container *ngIf="!userInfo.isCurrentUser">
<button class="btn btn-link" (click)="lock(user); $event.stopPropagation();" *ngIf="!userInfo.user.isLocked" title="Lock User">
<i class="icon icon-unlocked"></i>
</button>
<button class="btn btn-link" (click)="unlock(user); $event.stopPropagation();" *ngIf="user.isLocked" title="Unlock User">
<button class="btn btn-link" (click)="unlock(user); $event.stopPropagation();" *ngIf="userInfo.user.isLocked" title="Unlock User">
<i class="icon icon-lock"></i>
</button>
</ng-container>
<button *ngIf="user.id === authState.user?.id" class="btn btn-link invisible">
<button *ngIf="userInfo.isCurrentUser" class="btn btn-link invisible">
&nbsp;
</button>
</td>

13
src/Squidex/app/features/administration/pages/users/users-page.component.ts

@ -8,8 +8,6 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { AuthService } from '@app/shared';
import { UserDto } from './../../services/users.service';
import { UsersState } from './../../state/users.state';
@ -23,21 +21,20 @@ export class UsersPageComponent implements OnInit {
public usersFilter = new FormControl();
constructor(
public readonly authState: AuthService,
public readonly usersState: UsersState
) {
}
public ngOnInit() {
this.load();
this.usersState.load().onErrorResumeNext().subscribe();
}
public search() {
this.usersState.search(this.usersFilter.value).onErrorResumeNext().subscribe();
public reload() {
this.usersState.load(true).onErrorResumeNext().subscribe();
}
public load(notify = false) {
this.usersState.load(notify).onErrorResumeNext().subscribe();
public search() {
this.usersState.search(this.usersFilter.value).onErrorResumeNext().subscribe();
}
public lock(user: UserDto) {

34
src/Squidex/app/features/administration/state/users.state.spec.ts

@ -51,7 +51,7 @@ describe('UsersState', () => {
});
it('should load users', () => {
expect(usersState.snapshot.users.values).toEqual(oldUsers);
expect(usersState.snapshot.users.values.map(x => x.user)).toEqual(oldUsers);
expect(usersState.snapshot.usersPager.numberOfItems).toEqual(200);
usersService.verifyAll();
@ -70,7 +70,7 @@ describe('UsersState', () => {
usersState.load().subscribe();
expect(usersState.snapshot.selectedUser).toBe(newUsers[0]);
expect(usersState.snapshot.selectedUser!.user).toBe(newUsers[0]);
});
it('should raise notification on load when notify is true', () => {
@ -82,7 +82,7 @@ describe('UsersState', () => {
it('should mark as current user when selected user equals to profile', () => {
usersState.select('id2').subscribe();
expect(usersState.snapshot.isCurrentUser).toBeTruthy();
expect(usersState.snapshot.selectedUser!.isCurrentUser).toBeTruthy();
});
it('should not load user when already loaded', () => {
@ -93,7 +93,7 @@ describe('UsersState', () => {
});
expect(selectedUser!).toEqual(oldUsers[0]);
expect(usersState.snapshot.selectedUser).toBe(oldUsers[0]);
expect(usersState.snapshot.selectedUser!.user).toBe(oldUsers[0]);
usersService.verify(x => x.getUser(It.isAnyString()), Times.never());
});
@ -109,7 +109,7 @@ describe('UsersState', () => {
});
expect(selectedUser!).toEqual(newUser);
expect(usersState.snapshot.selectedUser).toBe(newUser);
expect(usersState.snapshot.selectedUser!.user).toBe(newUser);
});
it('should return null when unselecting user', () => {
@ -146,8 +146,10 @@ describe('UsersState', () => {
usersState.select('id1').subscribe();
usersState.lock(oldUsers[0]).subscribe();
expect(usersState.snapshot.users.at(0).isLocked).toBeTruthy();
expect(usersState.snapshot.selectedUser).toBe(usersState.snapshot.users.at(0));
const user_1 = usersState.snapshot.users.at(0);
expect(user_1.user.isLocked).toBeTruthy();
expect(user_1).toBe(usersState.snapshot.selectedUser);
});
it('should unmark user as locked', () => {
@ -157,8 +159,10 @@ describe('UsersState', () => {
usersState.select('id2').subscribe();
usersState.unlock(oldUsers[1]).subscribe();
expect(usersState.snapshot.users.at(1).isLocked).toBeFalsy();
expect(usersState.snapshot.selectedUser).toBe(usersState.snapshot.users.at(1));
const user_1 = usersState.snapshot.users.at(0);
expect(user_1.user.isLocked).toBeFalsy();
expect(user_1).toBe(usersState.snapshot.selectedUser);
});
it('should update user on update', () => {
@ -170,12 +174,14 @@ describe('UsersState', () => {
usersState.select('id1').subscribe();
usersState.update(oldUsers[0], request).subscribe();
expect(usersState.snapshot.users.at(0).email).toEqual('new@mail.com');
expect(usersState.snapshot.users.at(0).displayName).toEqual('New');
expect(usersState.snapshot.selectedUser).toBe(usersState.snapshot.users.at(0));
const user_1 = usersState.snapshot.users.at(0);
expect(user_1.user.email).toEqual('new@mail.com');
expect(user_1.user.displayName).toEqual('New');
expect(user_1).toBe(usersState.snapshot.selectedUser);
});
it('should add user to state when created', () => {
it('should add user to snapshot when created', () => {
const request = new CreateUserDto(newUser.email, newUser.displayName, 'password');
usersService.setup(x => x.postUser(request))
@ -183,7 +189,7 @@ describe('UsersState', () => {
usersState.create(request).subscribe();
expect(usersState.snapshot.users.at(0)).toBe(newUser);
expect(usersState.snapshot.users.at(0).user).toBe(newUser);
expect(usersState.snapshot.usersPager.numberOfItems).toBe(201);
});

46
src/Squidex/app/features/administration/state/users.state.ts

@ -70,14 +70,18 @@ export class UserForm extends Form<FormGroup> {
}
}
interface Snapshot {
isCurrentUser?: boolean;
interface SnapshotUser {
user: UserDto;
isCurrentUser: boolean;
}
users: ImmutableArray<UserDto>;
interface Snapshot {
users: ImmutableArray<SnapshotUser>;
usersPager: Pager;
usersQuery?: string;
selectedUser?: UserDto;
selectedUser?: SnapshotUser;
}
@Injectable()
@ -94,10 +98,6 @@ export class UsersState extends State<Snapshot> {
this.changes.map(x => x.selectedUser)
.distinctUntilChanged();
public isCurrentUser =
this.changes.map(x => x.isCurrentUser)
.distinctUntilChanged();
constructor(
private readonly authState: AuthService,
private readonly dialogs: DialogService,
@ -109,21 +109,19 @@ export class UsersState extends State<Snapshot> {
public select(id: string | null): Observable<UserDto | null> {
return this.loadUser(id)
.do(selectedUser => {
const isCurrentUser = id === this.authState.user!.id;
this.next(s => ({ ...s, selectedUser, isCurrentUser }));
});
this.next(s => ({ ...s, selectedUser }));
})
.map(x => x && x.user);
}
private loadUser(id: string | null) {
return !id ?
Observable.of(null) :
Observable.of(this.snapshot.users.find(x => x.id === id))
Observable.of(this.snapshot.users.find(x => x.user.id === id))
.switchMap(user => {
if (!user) {
return this.usersService.getUser(id).catch(() => Observable.of(null));
return this.usersService.getUser(id).map(x => this.createUser(x)).catch(() => Observable.of(null));
} else {
return Observable.of(user);
}
});
@ -137,13 +135,13 @@ export class UsersState extends State<Snapshot> {
}
this.next(s => {
const users = ImmutableArray.of(dtos.items);
const users = ImmutableArray.of(dtos.items.map(x => this.createUser(x)));
const usersPager = s.usersPager.setCount(dtos.total);
let selectedUser = s.selectedUser;
if (selectedUser) {
const selectedFromResult = dtos.items.find(x => x.id === selectedUser!.id);
const selectedFromResult = users.find(x => x.user.id === selectedUser!.user.id);
if (selectedFromResult) {
selectedUser = selectedFromResult;
@ -160,7 +158,7 @@ export class UsersState extends State<Snapshot> {
return this.usersService.postUser(request)
.do(dto => {
this.next(s => {
const users = s.users.pushFront(dto);
const users = s.users.pushFront(this.createUser(dto));
const usersPager = s.usersPager.incrementCount();
return { ...s, users, usersPager };
@ -171,8 +169,6 @@ export class UsersState extends State<Snapshot> {
public update(user: UserDto, request: UpdateUserDto): Observable<any> {
return this.usersService.putUser(user.id, request)
.do(() => {
this.dialogs.notifyInfo('User saved successsfull');
this.replaceUser(update(user, request));
});
}
@ -211,14 +207,20 @@ export class UsersState extends State<Snapshot> {
return this.load();
}
private replaceUser(user: UserDto) {
private replaceUser(userDto: UserDto) {
return this.next(s => {
const user = this.createUser(userDto);
const users = s.users.replaceBy('id', user);
const selectedUser = s.selectedUser && s.selectedUser.id === user.id ? user : s.selectedUser;
const selectedUser = s.selectedUser && s.selectedUser.user.id === userDto.id ? user : s.selectedUser;
return { ...s, users, selectedUser };
});
}
private createUser(user: UserDto): SnapshotUser {
return user ? { user, isCurrentUser: user.id === this.authState.user!.id } : null!;
}
}

Loading…
Cancel
Save