Manage SystemManagers
This commit is contained in:
@@ -19,7 +19,8 @@ export class MockUserRepository {
|
|||||||
},
|
},
|
||||||
isActive: false,
|
isActive: false,
|
||||||
role: null,
|
role: null,
|
||||||
systems: []
|
systems: [],
|
||||||
|
deletedAt: null
|
||||||
}
|
}
|
||||||
|
|
||||||
findByUsername = jest.fn().mockImplementation((username: string) => {
|
findByUsername = jest.fn().mockImplementation((username: string) => {
|
||||||
@@ -42,7 +43,8 @@ export class MockUserRepository {
|
|||||||
},
|
},
|
||||||
isActive: false,
|
isActive: false,
|
||||||
role: null,
|
role: null,
|
||||||
systems: []
|
systems: [],
|
||||||
|
deletedAt: null
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export class SSOUser {
|
|||||||
@PrimaryColumn({ type: 'uuid', unique: true })
|
@PrimaryColumn({ type: 'uuid', unique: true })
|
||||||
externalId: string;
|
externalId: string;
|
||||||
|
|
||||||
@OneToOne(() => User, (user) => user.external)
|
@OneToOne(() => User, (user) => user.external, { onDelete: 'CASCADE'})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
user: User;
|
user: User;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Exclude, Transform } from 'class-transformer';
|
|||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
|
DeleteDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
JoinColumn,
|
JoinColumn,
|
||||||
ManyToMany,
|
ManyToMany,
|
||||||
@@ -21,7 +22,7 @@ export class User implements IUser {
|
|||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
@Column({ unique: true })
|
@Column({ unique: false })
|
||||||
username: string;
|
username: string;
|
||||||
|
|
||||||
@Column({ name: 'first_name', default: '' })
|
@Column({ name: 'first_name', default: '' })
|
||||||
@@ -37,13 +38,13 @@ export class User implements IUser {
|
|||||||
lastLogin: Date;
|
lastLogin: Date;
|
||||||
|
|
||||||
@Exclude()
|
@Exclude()
|
||||||
@OneToOne(() => SSOUser, (sso) => sso.user, { eager: true, cascade: true })
|
@OneToOne(() => SSOUser, (sso) => sso.user, { eager: true, cascade: true, onDelete: 'CASCADE' })
|
||||||
external: SSOUser;
|
external: SSOUser;
|
||||||
|
|
||||||
@Column({ default: true })
|
@Column({ default: true })
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
||||||
@ManyToOne(() => Role, (role) => role.user, { cascade: true, eager: true })
|
@ManyToOne(() => Role, (role) => role.user, { eager: true, onDelete: 'NO ACTION' })
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
@Transform(({ value }) => value.name)
|
@Transform(({ value }) => value.name)
|
||||||
role: Role;
|
role: Role;
|
||||||
@@ -51,6 +52,9 @@ export class User implements IUser {
|
|||||||
@ManyToMany(() => KeySystem, (system) => system.managers)
|
@ManyToMany(() => KeySystem, (system) => system.managers)
|
||||||
systems: KeySystem[];
|
systems: KeySystem[];
|
||||||
|
|
||||||
|
@DeleteDateColumn()
|
||||||
|
deletedAt: Date;
|
||||||
|
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ export interface IUser {
|
|||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
|
|
||||||
|
deletedAt?: Date;
|
||||||
|
|
||||||
role?: string | Role;
|
role?: string | Role;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,4 +61,16 @@ export class UserRepository extends Repository<User> {
|
|||||||
const sso = await this.ssoRepo.findByExternalId(externalId);
|
const sso = await this.ssoRepo.findByExternalId(externalId);
|
||||||
return user == null && sso == null;
|
return user == null && sso == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteUserById(id: string) {
|
||||||
|
const user = await this.findOne({
|
||||||
|
where: { id },
|
||||||
|
relations: ['external']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user.external) {
|
||||||
|
await this.ssoRepo.remove(user.external);
|
||||||
|
}
|
||||||
|
return this.softRemove(user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,4 +52,9 @@ export class SystemController {
|
|||||||
remove(@Param('id') id: string) {
|
remove(@Param('id') id: string) {
|
||||||
return this.systemService.remove(id);
|
return this.systemService.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post(':id/manager')
|
||||||
|
manaManager(@Param('id') id: string, @Body() body: any){
|
||||||
|
return this.systemService.manageManagers(id, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||||
import { CreateSystemDto } from './dto/create-system.dto';
|
import { CreateSystemDto } from './dto/create-system.dto';
|
||||||
import { UpdateSystemDto } from './dto/update-system.dto';
|
import { UpdateSystemDto } from './dto/update-system.dto';
|
||||||
import { KeySystemRepository } from 'src/model/repositories';
|
import { KeySystemRepository, UserRepository } from 'src/model/repositories';
|
||||||
import { User } from 'src/model/entitites';
|
import { User } from 'src/model/entitites';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SystemService {
|
export class SystemService {
|
||||||
constructor(private systemRepo: KeySystemRepository) {}
|
constructor(private systemRepo: KeySystemRepository, private userRepo: UserRepository) {}
|
||||||
|
|
||||||
async create(user: User, createSystemDto: CreateSystemDto) {
|
async create(user: User, createSystemDto: CreateSystemDto) {
|
||||||
const sys = this.systemRepo.create(createSystemDto);
|
const sys = this.systemRepo.create(createSystemDto);
|
||||||
@@ -52,4 +52,36 @@ export class SystemService {
|
|||||||
|
|
||||||
return system.managers;
|
return system.managers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async manageManagers(systemID: string, manageObject: { email: string, action: 'add' | 'remove'}) {
|
||||||
|
const sys = await this.systemRepo.findOne({
|
||||||
|
where: { id: systemID },
|
||||||
|
relations: ['managers']
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!sys) {
|
||||||
|
throw new HttpException('Das System wurde nicht im System gefunden', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manageObject.action == 'remove') {
|
||||||
|
sys.managers = sys.managers.filter( m => m.username != manageObject.email);
|
||||||
|
|
||||||
|
await this.systemRepo.save(sys);
|
||||||
|
return sys.managers;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sys.managers.some(m => m.username == manageObject.email)) {
|
||||||
|
return sys.managers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.userRepo.findOneBy({ username: manageObject.email.trim() });
|
||||||
|
if (!user) {
|
||||||
|
throw new HttpException('Es wurde kein User mit dieser Emailadresse gefunden. Bitte prüfe die Emailadresse und versuche es erneut.', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.managers.push(user);
|
||||||
|
await this.systemRepo.save(sys);
|
||||||
|
return sys.managers;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Delete, Get, HttpException, HttpStatus, Param, Post, Req, UseGuards } from '@nestjs/common';
|
||||||
import { AuthGuard } from 'src/core/guards/auth.guard';
|
import { AuthGuard } from 'src/core/guards/auth.guard';
|
||||||
import { UserService } from './user.service';
|
import { UserService } from './user.service';
|
||||||
import { User } from 'src/model/entitites';
|
import { User } from 'src/model/entitites';
|
||||||
import { IUser } from 'src/model/interface';
|
import { IUser } from 'src/model/interface';
|
||||||
|
import { AuthenticatedRequest } from 'src/model/interface/authenticated-request.interface';
|
||||||
|
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
|
||||||
|
import { HttpStatusCode } from 'axios';
|
||||||
|
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
@Controller('user')
|
@Controller('user')
|
||||||
@@ -18,4 +21,12 @@ export class UserController {
|
|||||||
saveUser(@Body() user: IUser) {
|
saveUser(@Body() user: IUser) {
|
||||||
return this.userService.saveUser(user);
|
return this.userService.saveUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
deleteUserWithId(@Req() req: AuthenticatedRequest, @Param('id') id: string) {
|
||||||
|
if (req.user.role.name != "admin") {
|
||||||
|
throw new HttpException('no admin', HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
return this.userService.deleteUserById(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,4 +23,9 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
return this.userRepo.save(user as any);
|
return this.userRepo.save(user as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteUserById(id: string) {
|
||||||
|
return this.userRepo.deleteUserById(id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
5
client/mocks/services/mock.auth.service.ts
Normal file
5
client/mocks/services/mock.auth.service.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { of } from "rxjs";
|
||||||
|
|
||||||
|
export class MockAuthService {
|
||||||
|
user = { id: '1', username: 'test', role: 'admin' };
|
||||||
|
}
|
||||||
@@ -7,11 +7,12 @@ import { HotToastService } from '@ngxpert/hot-toast';
|
|||||||
import { AuthService } from '../../../core/auth/auth.service';
|
import { AuthService } from '../../../core/auth/auth.service';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
import { AG_GRID_LOCALE_DE } from '@ag-grid-community/locale';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-all-users',
|
selector: 'app-all-users',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [AgGridAngular],
|
imports: [AgGridAngular, MatButtonModule],
|
||||||
providers: [DatePipe],
|
providers: [DatePipe],
|
||||||
templateUrl: './all-users.component.html',
|
templateUrl: './all-users.component.html',
|
||||||
styleUrl: './all-users.component.scss'
|
styleUrl: './all-users.component.scss'
|
||||||
@@ -54,6 +55,25 @@ export class AllUsersComponent {
|
|||||||
, width: 170
|
, width: 170
|
||||||
, type: 'date'
|
, type: 'date'
|
||||||
, cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value), 'medium') : '-'
|
, cellRenderer: (data: any) => data.value ? this.datePipe.transform(new Date(data.value), 'medium') : '-'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'delete',
|
||||||
|
headerName: '',
|
||||||
|
width: 50,
|
||||||
|
cellRenderer: (params: any) => {
|
||||||
|
if (params.data.id == this.authService.user.id || !this.authService.isAdmin) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return `<div class="delete icon icon-btn-xs" (click)="deleteUser(${params.data.id})"></div>`;
|
||||||
|
},
|
||||||
|
onCellClicked: (event: any) => {
|
||||||
|
if (event.data.id == this.authService.user.id || !this.authService.isAdmin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.colDef.field == 'delete') {
|
||||||
|
this.deleteUser(event.data.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
loading: true,
|
loading: true,
|
||||||
@@ -64,12 +84,36 @@ export class AllUsersComponent {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteUser(id: string) {
|
||||||
|
if ( confirm('Soll der Benutzer wirklich gelöscht werden?')) {
|
||||||
|
this.api.deleteUser(id)
|
||||||
|
.pipe(
|
||||||
|
this.toast.observe({
|
||||||
|
loading: 'löschen...',
|
||||||
|
success: 'Benutzer gelöscht',
|
||||||
|
error: 'Benutzer konnte nicht gelöscht werden!'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.loadUsers();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
loadUsers() {
|
loadUsers() {
|
||||||
|
this.gridApi.setGridOption("loading", true);
|
||||||
this.api.getAllUsers().subscribe({
|
this.api.getAllUsers().subscribe({
|
||||||
next: n => {
|
next: n => {
|
||||||
this.gridApi.setGridOption("rowData", n)
|
this.gridApi.setGridOption("rowData", n)
|
||||||
this.gridApi.setGridOption("loading", false);
|
this.gridApi.setGridOption("loading", false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.toast.error('Benutzer konnten nicht geladen werden!')
|
||||||
|
this.gridApi.setGridOption("loading", false);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,17 +31,16 @@ export class SelectKeyCylinderComponent {
|
|||||||
},
|
},
|
||||||
rowSelection: 'multiple',
|
rowSelection: 'multiple',
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
// selected rows
|
|
||||||
{ colId: 'selected', headerName: '', checkboxSelection: true, width: 40, headerCheckboxSelection: true, headerCheckboxSelectionFilteredOnly: true },
|
{ colId: 'selected', headerName: '', checkboxSelection: true, width: 40, headerCheckboxSelection: true, headerCheckboxSelectionFilteredOnly: true },
|
||||||
{ colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true },
|
{ colId: 'name', field: 'name' , headerName: 'Name', flex: 1, editable: true, sort: 'asc', filter: true },
|
||||||
|
{ colId: 'system', field: 'system' , headerName: 'Schließanlage', flex: 1, editable: false, filter: true, cellRenderer: (data: any) => {return data.value?.name} },
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
selectedCylinders: ICylinder[] = [];
|
selectedCylinders: ICylinder[] = [];
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
console.log(this.toast)
|
this.toast.info('Wähle die Zylinder aus, die dem Schlüssel zugeordnet werden sollen.');
|
||||||
this.toast.error('Wähle die Zylinder aus, die dem Schlüssel zugeordnet werden sollen.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onGridReady(params: GridReadyEvent) {
|
onGridReady(params: GridReadyEvent) {
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
|
|
||||||
|
|
||||||
<h2 mat-dialog-title>Manager</h2>
|
<h2 mat-dialog-title>{{ system?.name }} - Manager</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
<div style="display: flex; flex-direction: column; height: calc(100% - 4px);" class="gap-2">
|
||||||
|
<div class="flex-auto">
|
||||||
<ag-grid-angular
|
<ag-grid-angular
|
||||||
style="width: 100%; height: 100%;"
|
style="width: 100%; height: 100%;"
|
||||||
(gridReady)="onGridReady($event)"
|
(gridReady)="onGridReady($event)"
|
||||||
[gridOptions]="gridOptions!"
|
[gridOptions]="gridOptions!"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 items-center">
|
||||||
|
<mat-form-field class="flex-1">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<input matInput [(ngModel)]="email">
|
||||||
|
<mat-hint>Emailadresse des neuen Users eingeben</mat-hint>
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button (click)="addManagerByEmail()" [disabled]="email == '' || email == null">Hinzufügen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button [mat-dialog-close]="true">Schließen</button>
|
<button mat-button [mat-dialog-close]="true">Schließen</button>
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import { ApiService } from '../../../../shared/api.service';
|
|||||||
import { HotToastService } from '@ngxpert/hot-toast';
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
import { MockApiService } from '../../../../../../mocks/services/mock.api.service';
|
import { MockApiService } from '../../../../../../mocks/services/mock.api.service';
|
||||||
import { GridReadyEvent } from 'ag-grid-community';
|
import { GridReadyEvent } from 'ag-grid-community';
|
||||||
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
|
import { MockAuthService } from '../../../../../../mocks/services/mock.auth.service';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -18,7 +21,7 @@ describe('SystemManagerComponent', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [SystemManagerComponent, AgGridAngular, MatDialogModule],
|
imports: [SystemManagerComponent, AgGridAngular, MatDialogModule, NoopAnimationsModule],
|
||||||
providers: [
|
providers: [
|
||||||
HotToastService,
|
HotToastService,
|
||||||
{ provide: ApiService, useClass: MockApiService },
|
{ provide: ApiService, useClass: MockApiService },
|
||||||
@@ -29,7 +32,8 @@ describe('SystemManagerComponent', () => {
|
|||||||
{
|
{
|
||||||
provide: MAT_DIALOG_DATA,
|
provide: MAT_DIALOG_DATA,
|
||||||
useValue: []
|
useValue: []
|
||||||
}
|
},
|
||||||
|
{ provide: AuthService, useClass: MockAuthService }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
|
|||||||
@@ -5,11 +5,18 @@ import { AgGridAngular } from 'ag-grid-angular';
|
|||||||
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
|
||||||
import { HotToastService } from '@ngxpert/hot-toast';
|
import { HotToastService } from '@ngxpert/hot-toast';
|
||||||
import { ApiService } from '../../../../shared/api.service';
|
import { ApiService } from '../../../../shared/api.service';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-system-manager',
|
selector: 'app-system-manager',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [AgGridAngular, MatDialogModule],
|
imports: [AgGridAngular, MatDialogModule, MatButtonModule, MatInputModule, MatFormFieldModule, CommonModule, FormsModule],
|
||||||
templateUrl: './system-manager.component.html',
|
templateUrl: './system-manager.component.html',
|
||||||
styleUrl: './system-manager.component.scss'
|
styleUrl: './system-manager.component.scss'
|
||||||
})
|
})
|
||||||
@@ -24,12 +31,30 @@ export class SystemManagerComponent {
|
|||||||
private api: ApiService = inject(ApiService);
|
private api: ApiService = inject(ApiService);
|
||||||
private dialog: MatDialog = inject(MatDialog);
|
private dialog: MatDialog = inject(MatDialog);
|
||||||
private toast = inject(HotToastService);
|
private toast = inject(HotToastService);
|
||||||
|
private authService = inject(AuthService);
|
||||||
|
|
||||||
|
email = null;
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.gridOptions.columnDefs = [
|
this.gridOptions.columnDefs = [
|
||||||
{ colId: 'name', field: 'firstName', headerName: 'Name', sort: 'asc', flex: 1, cellRenderer: (data: any) => data.data.firstName + ' ' + data.data.lastName, sortable: true, filter: true},
|
{ colId: 'name', field: 'firstName', headerName: 'Name', sort: 'asc', flex: 1, cellRenderer: (data: any) => data.data.firstName + ' ' + data.data.lastName, sortable: true, filter: true},
|
||||||
{ colId: 'mail', field: 'username', headerName: 'E-Mail', flex: 1},
|
{ colId: 'mail', field: 'username', headerName: 'E-Mail', flex: 1},
|
||||||
|
{ colId: 'delete', headerName: '', width: 50,
|
||||||
|
cellRenderer: (params: any) => {
|
||||||
|
if (this.authService.user.username == params.data.username) return '';
|
||||||
|
return `<div class="delete icon icon-btn-xs"></div>`;
|
||||||
|
},
|
||||||
|
onCellClicked: (event: any) => {
|
||||||
|
if (this.authService.user.username == event.data.username) {
|
||||||
|
this.toast.error('Du kannst dich nicht selbst entfernen');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.colDef.colId == 'delete') {
|
||||||
|
this.removeManagerByEmail(event.data.username);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,4 +72,49 @@ export class SystemManagerComponent {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addManagerByEmail() {
|
||||||
|
if (this.email == null) return;
|
||||||
|
this.gridApi.setGridOption("loading", true);
|
||||||
|
this.api.addManager(this.system.id, this.email)
|
||||||
|
.pipe(
|
||||||
|
this.toast.observe({
|
||||||
|
loading: 'Füge Manager hinzu',
|
||||||
|
success: 'Manager hinzugefügt',
|
||||||
|
error: (x: any) => x.error.message || 'Fehler beim Hinzufügen des Managers'
|
||||||
|
})
|
||||||
|
).subscribe({
|
||||||
|
next: n => {
|
||||||
|
this.gridApi.setGridOption("rowData", n);
|
||||||
|
this.email = null;
|
||||||
|
this.gridApi.setGridOption("loading", false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.gridApi.setGridOption("loading", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeManagerByEmail(username: string) {
|
||||||
|
const resume = confirm('Soll der Manager wirklich entfernt werden?');
|
||||||
|
if (!resume) return;
|
||||||
|
|
||||||
|
this.gridApi.setGridOption("loading", true);
|
||||||
|
this.api.removeManager(this.system.id, username)
|
||||||
|
.pipe(
|
||||||
|
this.toast.observe({
|
||||||
|
loading: 'Manager entfernen',
|
||||||
|
success: 'Manager entfernt',
|
||||||
|
error: (x: any) => x.error.message || 'Fehler beim Entfgernen des Managers'
|
||||||
|
})
|
||||||
|
).subscribe({
|
||||||
|
next: (n: any[]) => {
|
||||||
|
this.gridApi.setGridOption("rowData", n);
|
||||||
|
this.gridApi.setGridOption("loading", false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
this.gridApi.setGridOption("loading", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class AgSystemManagerComponent implements ICellRendererAngularComp {
|
|||||||
width: "50vw",
|
width: "50vw",
|
||||||
minWidth: "300px",
|
minWidth: "300px",
|
||||||
height: "70vh",
|
height: "70vh",
|
||||||
disableClose: true
|
disableClose: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// ref.afterClosed().subscribe({
|
// ref.afterClosed().subscribe({
|
||||||
|
|||||||
@@ -85,4 +85,22 @@ export class ApiService {
|
|||||||
deleteCylinder(cylinder: ICylinder): Observable<any> {
|
deleteCylinder(cylinder: ICylinder): Observable<any> {
|
||||||
return this.http.delete(`api/cylinder/${cylinder.id}`)
|
return this.http.delete(`api/cylinder/${cylinder.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteUser(id: string) {
|
||||||
|
return this.http.delete(`api/user/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
addManager(systemID: string, email: string): Observable<IUser[]> {
|
||||||
|
return this.http.post<IUser[]>(`api/system/${systemID}/manager`, {
|
||||||
|
email,
|
||||||
|
action: 'add'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeManager(systemID: string, email: string): Observable<IUser[]> {
|
||||||
|
return this.http.post<IUser[]>(`api/system/${systemID}/manager`, {
|
||||||
|
email,
|
||||||
|
action: 'remove'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,24 @@ html, body {
|
|||||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
border: 1px solid #d0d5dd;
|
||||||
|
background-color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
transition: box-shadow 0.1s ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
// box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11;
|
||||||
|
box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
|
||||||
|
0px 6px 10px 0px rgba(0, 0, 0, 0.14),
|
||||||
|
0px 1px 18px 0px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.icon-btn-sm {
|
.icon-btn-sm {
|
||||||
// box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11;
|
// box-shadow: 0 0 0 4px transparent,0 1px 2px #0c111d11;
|
||||||
|
|||||||
Reference in New Issue
Block a user