diff --git a/src/app/app-root/admin-starter/admin-starter.component.html b/src/app/app-root/admin-starter/admin-starter.component.html index f8c4e18e07e499c3e9a2c8eb87ce5215009004c3..fce919ea22ba017d1904748ca6cffd48a95467e8 100644 --- a/src/app/app-root/admin-starter/admin-starter.component.html +++ b/src/app/app-root/admin-starter/admin-starter.component.html @@ -6,13 +6,13 @@ Sie sind mit Administrator-Funktionen angemeldet. Aktuell sind keine Studien für Sie freigegeben. </p> <button mat-raised-button color="primary" (click)="buttonGotoWorkspaceAdmin(ws)" - *ngFor="let ws of (mds.loginData$ | async)?.workspaces"> + *ngFor="let ws of workspaces"> {{ws.name}} </button> </div> </mat-card-content> <mat-card-actions> - <button mat-raised-button color="foreground" *ngIf="(mds.loginData$ | async)?.isSuperadmin" [routerLink]="['/superadmin']">System-Admin</button> + <button mat-raised-button color="foreground" *ngIf="mds.isSuperAdmin" [routerLink]="['/superadmin']">System-Admin</button> <button mat-raised-button color="foreground" (click)="resetLogin()">Neu anmelden</button> </mat-card-actions> </mat-card> diff --git a/src/app/app-root/admin-starter/admin-starter.component.ts b/src/app/app-root/admin-starter/admin-starter.component.ts index e9904c89f798e6365e333bb13a3957d7ac9c56d1..c49e095507e1d1c9613ef2f5e8c57c646643f96a 100644 --- a/src/app/app-root/admin-starter/admin-starter.component.ts +++ b/src/app/app-root/admin-starter/admin-starter.component.ts @@ -1,18 +1,35 @@ -import { Component } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {MainDataService} from "../../maindata.service"; -import {WorkspaceData} from "../../app.interfaces"; import {Router} from "@angular/router"; +interface WorkspaceData { + id: string; + name: string; +} + @Component({ templateUrl: './admin-starter.component.html', }) -export class AdminStarterComponent { + +export class AdminStarterComponent implements OnInit { + workspaces: WorkspaceData[] = []; + isSuperAdmin = false; constructor( private router: Router, public mds: MainDataService ) { } + ngOnInit() { + const workspaces = this.mds.workspaces; + for (let wsId of Object.keys(workspaces)) { + this.workspaces.push({ + id: wsId, + name: workspaces[wsId], + }) + } + } + buttonGotoWorkspaceAdmin(ws: WorkspaceData) { this.router.navigateByUrl('/admin/' + ws.id.toString() + '/files'); } diff --git a/src/app/app-root/login/login.component.ts b/src/app/app-root/login/login.component.ts index ad34ace69eea024a697400bb2e826b0cef261bbf..28a6356d4c07d8f7d5587939065e1629ee3410c9 100644 --- a/src/app/app-root/login/login.component.ts +++ b/src/app/app-root/login/login.component.ts @@ -59,17 +59,16 @@ export class LoginComponent implements OnInit, OnDestroy { if ((loginData as LoginData).customTexts) { this.cts.addCustomTexts((loginData as LoginData).customTexts); } - this.mds.setNewLoginData(loginData as LoginData); + this.mds.setAuthData(loginData as LoginData); if (this.returnTo) { this.router.navigateByUrl(this.returnTo); } else { - const loginDataCleaned = this.mds.loginData$.getValue(); - if (loginDataCleaned.adminToken.length > 0) { + if (this.mds.adminToken) { this.router.navigate(['../admin-starter'], {relativeTo: this.route}); - } else if (loginDataCleaned.loginToken.length > 0) { + } else if (this.mds.loginToken) { this.router.navigate(['../code-input'], {relativeTo: this.route}); - } else if (loginDataCleaned.personToken.length > 0) { + } else if (this.mds.personToken) { this.router.navigate(['../test-starter'], {relativeTo: this.route}); } else { this.mds.appError$.next({ diff --git a/src/app/app-routing-guards.ts b/src/app/app-routing-guards.ts index 2ba5fb0d6e004049db3cc032ed34a40328ad51d6..2faef97ab733f09c360b5d726a6832b8ba3647c6 100644 --- a/src/app/app-routing-guards.ts +++ b/src/app/app-routing-guards.ts @@ -14,5 +14,6 @@ export class AdminRouteActivateGuard implements CanActivate { next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean { + return true; } } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 812657c438ab17e7a0ffa78aeab09787b485fb0c..8952f27ee6410be62940c8d7ad8d91d1adee13af 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -13,6 +13,7 @@ const routes: Routes = [ {path: '', redirectTo: 'r', pathMatch: 'full'}, {path: 'r', component: AppRootComponent, children: [ + {path: '', redirectTo: 'login', pathMatch: 'full'}, {path: 'login/:returnTo', component: LoginComponent}, {path: 'about', component: AboutComponent}, {path: 'check-starter', component: SysCheckStarterComponent}, diff --git a/src/app/app.interceptor.ts b/src/app/app.interceptor.ts index fce9c80aa618271ae5a4d0f4fcb084a7823705f5..063f8c2c19016f73436f2eaa1c00e3d7885a7d87 100644 --- a/src/app/app.interceptor.ts +++ b/src/app/app.interceptor.ts @@ -11,25 +11,14 @@ export class AuthInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { if (request.headers.get('AuthToken') !== null) { - return next.handle(request); + return next.handle(request); } - const loginData = this.mds.loginData$.getValue(); - - let authData; - if (loginData === null) { - authData = { - l: '', - p: '', - at: '' - }; - } else { - authData = { - l: loginData.loginToken, - p: loginData.personToken, - at: loginData.adminToken - }; - } + const authData = { + l: this.mds.loginToken, + p: this.mds.personToken, + at: this.mds.adminToken + }; const requestA = request.clone({ setHeaders: { AuthToken: JSON.stringify(authData) diff --git a/src/app/app.interfaces.ts b/src/app/app.interfaces.ts index fddbc07419beeb9be4c3067fe58138107548ce01..000c661825b4308340d8299dd2bb94c6583e1d4f 100644 --- a/src/app/app.interfaces.ts +++ b/src/app/app.interfaces.ts @@ -20,7 +20,7 @@ export enum AuthType { } export interface AccessRightList { - [key: string]: string[]; + [key: string]: string; } export interface AuthData { diff --git a/src/app/maindata.service.ts b/src/app/maindata.service.ts index 8f5326227a3d85f31dcb3d684994f6b447b4c1db..d46841f8af716f45d0265dec249cfe9077d61e1b 100644 --- a/src/app/maindata.service.ts +++ b/src/app/maindata.service.ts @@ -1,13 +1,16 @@ -import { BackendService } from './backend.service'; -import { BehaviorSubject, Subject, forkJoin } from 'rxjs'; -import { Injectable } from '@angular/core'; -import {AppError, LoginData} from './app.interfaces'; -import { CustomtextService, ServerError } from 'iqb-components'; -import { appconfig, customtextKeySeparator, CustomTextsDefList } from './app.config'; +import {BackendService} from './backend.service'; +import {BehaviorSubject, forkJoin, Subject} from 'rxjs'; +import {Injectable} from '@angular/core'; +import {AccessRightList, AppError, AuthData, AuthType, LoginData} from './app.interfaces'; +import {CustomtextService, ServerError} from 'iqb-components'; +import {appconfig, customtextKeySeparator, CustomTextsDefList} from './app.config'; + +const localStorageAuthDataKey = 'iqb-tc'; @Injectable({ providedIn: 'root' }) + export class MainDataService { private static get defaultLoginData(): LoginData { return { @@ -37,11 +40,77 @@ export class MainDataService { public postMessage$ = new Subject<MessageEvent>(); public get adminToken(): string { - const myLoginData = this.loginData$.getValue(); - if (myLoginData) { - return myLoginData.adminToken; + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.authTypes.indexOf(AuthType.ADMIN) >= 0) { + return authData.token; + } + } + } + return ''; + } + public get isSuperAdmin(): boolean { + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.authTypes.indexOf(AuthType.SUPERADMIN) >= 0) { + return true; + } + } + } + return false; + } + public get loginToken(): string { + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.authTypes.indexOf(AuthType.LOGIN) >= 0) { + return authData.token; + } + } + } + return ''; + } + public get personToken(): string { + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.authTypes.indexOf(AuthType.PERSON) >= 0) { + return authData.token; + } + } + } + return ''; + } + + public get workspaces(): AccessRightList { + const authData = MainDataService.getAuthDataFromLocalStorage(); + if (authData) { + if (authData.token) { + if (authData.authTypes.indexOf(AuthType.ADMIN) >= 0) { + return authData.accessRights; + } + } + } + return {}; + } + + private static getAuthDataFromLocalStorage(): AuthData { + const storageEntry = localStorage.getItem(localStorageAuthDataKey); + if (storageEntry !== null) { + if (storageEntry.length > 0) { + return JSON.parse(storageEntry as string); + } + } + return null; + } + + private static setAuthDataToLocalStorage(authData: AuthData = null) { + if (authData) { + localStorage.setItem(localStorageAuthDataKey, JSON.stringify(authData)); } else { - return ''; + localStorage.removeItem(localStorageAuthDataKey); } } @@ -55,10 +124,60 @@ export class MainDataService { } decrementDelayedProcessesCount() { - this.delayedProcessesCount$.next(this.delayedProcessesCount$.getValue() - 1); + const dpc = this.delayedProcessesCount$.getValue(); + if (dpc > 0) { + this.delayedProcessesCount$.next(dpc - 1); + } } - + setAuthData(loginData: LoginData = null) { + if (loginData) { + const authData = <AuthData>{ + token: '', + authTypes: [], + displayName: '', + accessRights: {} + }; + if (loginData.adminToken) { + authData.token = loginData.adminToken; + authData.displayName = loginData.name; + authData.authTypes.push(AuthType.ADMIN); + if (loginData.isSuperadmin) { + authData.authTypes.push(AuthType.SUPERADMIN); + } + for (let ws of loginData.workspaces) { + authData.accessRights[ws.id.toString()] = ws.name; + } + MainDataService.setAuthDataToLocalStorage(authData); + } else if (loginData.loginToken) { + authData.token = loginData.loginToken; + authData.displayName = loginData.name; + authData.authTypes.push(AuthType.LOGIN); + MainDataService.setAuthDataToLocalStorage(authData); + } else if (loginData.personToken) { + authData.token = loginData.personToken; + authData.displayName = loginData.name; + authData.authTypes.push(AuthType.PERSON); + if (loginData.code) { + const bookletList = loginData.booklets[loginData.code]; + if (bookletList) { + for (let b of bookletList) { + authData.accessRights[b] = b; + } + } + } else { + for (let b of loginData.booklets[0]) { + authData.accessRights[b] = b; + } + } + MainDataService.setAuthDataToLocalStorage(authData); + } else { + MainDataService.setAuthDataToLocalStorage(); + } + } else { + MainDataService.setAuthDataToLocalStorage(); + } + } // ensures consistency setNewLoginData(logindata?: LoginData) { @@ -163,12 +282,6 @@ export class MainDataService { return myLoginData.bookletLabel; } - // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - getPersonToken(): string { - const myLoginData = this.loginData$.getValue(); - return myLoginData.personToken; - } - public addCustomtextsFromDefList(customtextList: CustomTextsDefList) { const myCustomTexts: {[key: string]: string} = {}; for (const ct of Object.keys(customtextList.defList)) { diff --git a/src/app/superadmin/users/users.component.html b/src/app/superadmin/users/users.component.html index 8fb6918e50d2e2c64195e33dbbf57924cb1a19da..7650653c7e6e95690b7f2546e835205c12114bd3 100644 --- a/src/app/superadmin/users/users.component.html +++ b/src/app/superadmin/users/users.component.html @@ -1,8 +1,4 @@ <div class="columnhost" fxLayout="row" fxLayoutAlign="space-between start"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> - <!-- ============================================= --> <div class="objectlist" fxLayout="column" fxFlex="50"> <div fxLayout="row"> @@ -23,7 +19,7 @@ </button> </div> - <mat-table *ngIf="isSuperadmin" [dataSource]="objectsDatasource" matSort> + <mat-table [dataSource]="objectsDatasource" matSort> <ng-container matColumnDef="selectCheckbox"> <mat-header-cell *matHeaderCellDef fxFlex="70px"> <mat-checkbox (change)="$event ? masterToggle() : null" @@ -51,7 +47,7 @@ </div> <!-- ============================================= --> - <div *ngIf="isSuperadmin" fxLayout="column" fxFlex="40"> + <div fxLayout="column" fxFlex="40"> <div *ngIf="selectedUser < 0"> <div>Zugriffsrechte für Arbeitsbereich(e):</div> diff --git a/src/app/superadmin/users/users.component.ts b/src/app/superadmin/users/users.component.ts index 196cb9057e8a55031576805cbbaaf2cb5d418a3d..5cc1cff63a818d50e7944ac963afdbe28242f893 100644 --- a/src/app/superadmin/users/users.component.ts +++ b/src/app/superadmin/users/users.component.ts @@ -2,7 +2,7 @@ import { NewpasswordComponent } from './newpassword/newpassword.component'; import { NewuserComponent } from './newuser/newuser.component'; import { BackendService } from '../backend.service'; import { MatTableDataSource } from '@angular/material/table'; -import { ViewChild, OnDestroy } from '@angular/core'; +import { ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; @@ -12,9 +12,8 @@ import { FormGroup } from '@angular/forms'; import { SelectionModel } from '@angular/cdk/collections'; import { ConfirmDialogComponent, ConfirmDialogData, MessageDialogComponent, - MessageDialogData, MessageType + MessageDialogData, MessageType, ServerError } from 'iqb-components'; -import { Subscription } from 'rxjs'; import { MainDataService } from 'src/app/maindata.service'; import {IdRoleData, UserData} from "../superadmin.interfaces"; import {SuperadminPasswordRequestComponent} from "../superadmin-password-request/superadmin-password-request.component"; @@ -24,20 +23,17 @@ import {SuperadminPasswordRequestComponent} from "../superadmin-password-request templateUrl: './users.component.html', styleUrls: ['./users.component.css'] }) -export class UsersComponent implements OnInit, OnDestroy { - public isSuperadmin = false; - public dataLoading = false; +export class UsersComponent implements OnInit { public objectsDatasource: MatTableDataSource<UserData>; public displayedColumns = ['selectCheckbox', 'name']; private tableselectionCheckbox = new SelectionModel<UserData>(true, []); private tableselectionRow = new SelectionModel<UserData>(false, []); - private selectedUser = -1; + public selectedUser = -1; private selectedUserName = ''; private pendingWorkspaceChanges = false; public WorkspacelistDatasource: MatTableDataSource<IdRoleData>; public displayedWorkspaceColumns = ['selectCheckbox', 'label']; - private logindataSubscription: Subscription = null; @ViewChild(MatSort) sort: MatSort; @@ -65,10 +61,7 @@ export class UsersComponent implements OnInit, OnDestroy { } ngOnInit() { - this.logindataSubscription = this.mds.loginData$.subscribe(ld => { - this.isSuperadmin = ld.isSuperadmin; - this.updateObjectList(); - }); + this.updateObjectList(); } // *********************************************************************************** @@ -80,6 +73,7 @@ export class UsersComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (typeof result !== 'undefined') { if (result !== false) { + this.mds.incrementDelayedProcessesCount(); this.bs.addUser((<FormGroup>result).get('name').value, (<FormGroup>result).get('pw').value).subscribe( respOk => { @@ -89,6 +83,7 @@ export class UsersComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Nutzer nicht hinzufügen', 'Fehler', {duration: 1000}); } + this.mds.decrementDelayedProcessesCount(); }); } } @@ -131,7 +126,7 @@ export class UsersComponent implements OnInit, OnDestroy { passwdDialogRef.afterClosed().subscribe(result => { if (typeof result !== 'undefined') { if (result !== false) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.setSuperUserStatus( selectedRows[0]['id'], userObject.is_superadmin === '0', @@ -142,7 +137,7 @@ export class UsersComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Status nicht ändern', 'Fehler', {duration: 1000}); } - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }); } } @@ -175,7 +170,7 @@ export class UsersComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (typeof result !== 'undefined') { if (result !== false) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.changePassword(selectedRows[0]['id'], (<FormGroup>result).get('pw').value).subscribe( respOk => { @@ -184,7 +179,7 @@ export class UsersComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Kennwort nicht ändern', 'Fehler', {duration: 1000}); } - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }); } } @@ -226,7 +221,7 @@ export class UsersComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (result !== false) { // ========================================================= - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const usersToDelete = []; selectedRows.forEach((r: UserData) => usersToDelete.push(r.id)); this.bs.deleteUsers(usersToDelete).subscribe( @@ -234,12 +229,11 @@ export class UsersComponent implements OnInit, OnDestroy { if (respOk !== false) { this.snackBar.open('Nutzer gelöscht', '', {duration: 1000}); this.updateObjectList(); - this.dataLoading = false; } else { this.snackBar.open('Konnte Nutzer nicht löschen', 'Fehler', {duration: 2000}); - this.dataLoading = false; } - }); + this.mds.decrementDelayedProcessesCount(); + }); } }); } @@ -249,11 +243,19 @@ export class UsersComponent implements OnInit, OnDestroy { updateWorkspaceList() { this.pendingWorkspaceChanges = false; if (this.selectedUser > -1) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.getWorkspacesByUser(this.selectedUser).subscribe(dataresponse => { + if (dataresponse instanceof ServerError) { + this.mds.appError$.next({ + label: (dataresponse as ServerError).labelNice, + description: (dataresponse as ServerError).labelSystem, + category: "PROBLEM" + }); + } else { this.WorkspacelistDatasource = new MatTableDataSource(dataresponse); - this.dataLoading = false; - }); + } + this.mds.decrementDelayedProcessesCount() + }) } else { this.WorkspacelistDatasource = null; } @@ -271,7 +273,7 @@ export class UsersComponent implements OnInit, OnDestroy { saveWorkspaces() { this.pendingWorkspaceChanges = false; if (this.selectedUser > -1) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.setWorkspacesByUser(this.selectedUser, this.WorkspacelistDatasource.data).subscribe( respOk => { if (respOk !== false) { @@ -279,7 +281,7 @@ export class UsersComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Zugriffsrechte nicht ändern', 'Fehler', {duration: 2000}); } - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }); } else { this.WorkspacelistDatasource = null; @@ -288,18 +290,22 @@ export class UsersComponent implements OnInit, OnDestroy { // *********************************************************************************** updateObjectList() { - if (this.isSuperadmin) { - this.dataLoading = true; - this.tableselectionCheckbox.clear(); - this.tableselectionRow.clear(); - this.bs.getUsers().subscribe(dataresponse => { - console.log(dataresponse); - this.objectsDatasource = new MatTableDataSource(dataresponse); - this.objectsDatasource.sort = this.sort; - this.dataLoading = false; - } - ); - } + this.mds.incrementDelayedProcessesCount(); + this.tableselectionCheckbox.clear(); + this.tableselectionRow.clear(); + this.bs.getUsers().subscribe(dataresponse => { + if (dataresponse instanceof ServerError) { + this.mds.appError$.next({ + label: (dataresponse as ServerError).labelNice, + description: (dataresponse as ServerError).labelSystem, + category: "PROBLEM" + }); + } else { + this.objectsDatasource = new MatTableDataSource(dataresponse); + this.objectsDatasource.sort = this.sort; + } + this.mds.decrementDelayedProcessesCount(); + }); } isAllSelected() { @@ -317,11 +323,4 @@ export class UsersComponent implements OnInit, OnDestroy { selectRow(row) { this.tableselectionRow.select(row); } - - // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - ngOnDestroy() { - if (this.logindataSubscription !== null) { - this.logindataSubscription.unsubscribe(); - } - } } diff --git a/src/app/superadmin/workspaces/workspaces.component.html b/src/app/superadmin/workspaces/workspaces.component.html index 42e9e3cf8b132892820d0bc71cce327c08b327d4..9c62182bc765904d40e8495d7f555dedab121f29 100644 --- a/src/app/superadmin/workspaces/workspaces.component.html +++ b/src/app/superadmin/workspaces/workspaces.component.html @@ -1,9 +1,4 @@ <div class="columnhost" fxLayout="row" fxLayoutAlign="space-between start"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> - - <!-- ============================================= --> <div class="objectlist" fxLayout="column" fxFlex="50"> <div fxLayout="row"> <button mat-raised-button (click)="addObject()" matTooltip="Arbeitsbereich hinzufügen" matTooltipPosition="above"> @@ -18,7 +13,7 @@ </button> </div> - <mat-table *ngIf="isSuperadmin" [dataSource]="objectsDatasource" matSort> + <mat-table [dataSource]="objectsDatasource" matSort> <ng-container matColumnDef="selectCheckbox"> <mat-header-cell *matHeaderCellDef fxFlex="70px"> <mat-checkbox (change)="$event ? masterToggle() : null" @@ -46,7 +41,7 @@ </div> <!-- ============================================= --> - <div *ngIf="isSuperadmin" fxLayout="column" fxFlex="40"> + <div fxLayout="column" fxFlex="40"> <div *ngIf="selectedWorkspaceId == 0"> <div>Zugriffsberechtigte für Arbeitsbereich:</div> diff --git a/src/app/superadmin/workspaces/workspaces.component.ts b/src/app/superadmin/workspaces/workspaces.component.ts index 885f1168f9a362a5bbf8e21066f1a2a66f56da5a..6f3c29c140b569d17ed71839635728c7fbd66166 100644 --- a/src/app/superadmin/workspaces/workspaces.component.ts +++ b/src/app/superadmin/workspaces/workspaces.component.ts @@ -2,8 +2,7 @@ import { EditworkspaceComponent } from './editworkspace/editworkspace.component' import { NewworkspaceComponent } from './newworkspace/newworkspace.component'; import { BackendService } from '../backend.service'; import { MatTableDataSource } from '@angular/material/table'; -import { ViewChild, OnDestroy } from '@angular/core'; - +import { ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -14,7 +13,6 @@ import { ConfirmDialogComponent, ConfirmDialogData, MessageDialogComponent, MessageDialogData, MessageType } from 'iqb-components'; -import { Subscription } from 'rxjs'; import { MainDataService } from 'src/app/maindata.service'; import {IdAndName, IdRoleData} from "../superadmin.interfaces"; @@ -22,17 +20,13 @@ import {IdAndName, IdRoleData} from "../superadmin.interfaces"; templateUrl: './workspaces.component.html', styleUrls: ['./workspaces.component.css'] }) -export class WorkspacesComponent implements OnInit, OnDestroy { - public isSuperadmin = false; - public dataLoading = false; +export class WorkspacesComponent implements OnInit { public objectsDatasource: MatTableDataSource<IdAndName>; public displayedColumns = ['selectCheckbox', 'name']; private tableselectionCheckbox = new SelectionModel <IdAndName>(true, []); private tableselectionRow = new SelectionModel <IdAndName>(false, []); - private selectedWorkspaceId = 0; + public selectedWorkspaceId = 0; private selectedWorkspaceName = ''; - private logindataSubscription: Subscription = null; - private pendingUserChanges = false; public UserlistDatasource: MatTableDataSource<IdRoleData>; public displayedUserColumns = ['selectCheckbox', 'name']; @@ -62,10 +56,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { } ngOnInit() { - this.logindataSubscription = this.mds.loginData$.subscribe(ld => { - this.isSuperadmin = ld.isSuperadmin; - this.updateObjectList(); - }); + this.updateObjectList(); } // *********************************************************************************** @@ -80,17 +71,17 @@ export class WorkspacesComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (typeof result !== 'undefined') { if (result !== false) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.addWorkspace((<FormGroup>result).get('name').value).subscribe( - respOk => { - if (respOk !== false) { - this.snackBar.open('Arbeitsbereich hinzugefügt', '', {duration: 1000}); - this.updateObjectList(); - } else { - this.snackBar.open('Konnte Arbeitsbereich nicht hinzufügen', 'Fehler', {duration: 1000}); - } - this.dataLoading = false; - }); + respOk => { + if (respOk !== false) { + this.snackBar.open('Arbeitsbereich hinzugefügt', '', {duration: 1000}); + this.updateObjectList(); + } else { + this.snackBar.open('Konnte Arbeitsbereich nicht hinzufügen', 'Fehler', {duration: 1000}); + } + this.mds.decrementDelayedProcessesCount(); + }); } } }); @@ -119,7 +110,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (typeof result !== 'undefined') { if (result !== false) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.renameWorkspace(selectedRows[0].id, (<FormGroup>result).get('name').value).subscribe( respOk => { @@ -129,7 +120,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Arbeitsbereich nicht ändern', 'Fehler', {duration: 2000}); } - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }); } } @@ -171,7 +162,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (result !== false) { // ========================================================= - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const workspacesToDelete = []; selectedRows.forEach((r: IdAndName) => workspacesToDelete.push(r.id)); this.bs.deleteWorkspaces(workspacesToDelete).subscribe( @@ -179,11 +170,10 @@ export class WorkspacesComponent implements OnInit, OnDestroy { if (respOk !== false) { this.snackBar.open('Arbeitsbereich/e gelöscht', '', {duration: 1000}); this.updateObjectList(); - this.dataLoading = false; } else { this.snackBar.open('Konnte Arbeitsbereich/e nicht löschen', 'Fehler', {duration: 1000}); - this.dataLoading = false; } + this.mds.decrementDelayedProcessesCount(); }); } }); @@ -194,11 +184,11 @@ export class WorkspacesComponent implements OnInit, OnDestroy { updateUserList() { this.pendingUserChanges = false; if (this.selectedWorkspaceId > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.getUsersByWorkspace(this.selectedWorkspaceId).subscribe(dataresponse => { - this.UserlistDatasource = new MatTableDataSource(dataresponse); - this.dataLoading = false; - }); + this.UserlistDatasource = new MatTableDataSource(dataresponse); + this.mds.decrementDelayedProcessesCount(); + }); } else { this.UserlistDatasource = null; } @@ -216,7 +206,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { saveUsers() { this.pendingUserChanges = false; if (this.selectedWorkspaceId > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.bs.setUsersByWorkspace(this.selectedWorkspaceId, this.UserlistDatasource.data).subscribe( respOk => { if (respOk !== false) { @@ -224,7 +214,7 @@ export class WorkspacesComponent implements OnInit, OnDestroy { } else { this.snackBar.open('Konnte Zugriffsrechte nicht ändern', 'Fehler', {duration: 2000}); } - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }); } else { this.UserlistDatasource = null; @@ -233,17 +223,14 @@ export class WorkspacesComponent implements OnInit, OnDestroy { // *********************************************************************************** updateObjectList() { - if (this.isSuperadmin) { - this.dataLoading = true; - this.bs.getWorkspaces().subscribe(dataresponse => { - this.objectsDatasource = new MatTableDataSource(dataresponse); - this.objectsDatasource.sort = this.sort; - this.tableselectionCheckbox.clear(); - this.tableselectionRow.clear(); - this.dataLoading = false; - } - ); - } + this.mds.incrementDelayedProcessesCount(); + this.bs.getWorkspaces().subscribe(dataresponse => { + this.objectsDatasource = new MatTableDataSource(dataresponse); + this.objectsDatasource.sort = this.sort; + this.tableselectionCheckbox.clear(); + this.tableselectionRow.clear(); + this.mds.decrementDelayedProcessesCount(); + }); } isAllSelected() { @@ -261,11 +248,4 @@ export class WorkspacesComponent implements OnInit, OnDestroy { selectRow(row) { this.tableselectionRow.select(row); } - - // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - ngOnDestroy() { - if (this.logindataSubscription !== null) { - this.logindataSubscription.unsubscribe(); - } - } } diff --git a/src/app/workspace-admin/backend.service.ts b/src/app/workspace-admin/backend.service.ts index d092983c3ade64497b8e6ac382efceba6f9c623a..cafe10923b55d06c2095fb53528b7de62c7eb88e 100644 --- a/src/app/workspace-admin/backend.service.ts +++ b/src/app/workspace-admin/backend.service.ts @@ -5,6 +5,7 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { ErrorHandler, ServerError } from 'iqb-components'; +import {WorkspaceDataService} from "./workspacedata.service"; @Injectable({ providedIn: 'root' @@ -14,79 +15,80 @@ export class BackendService { constructor( @Inject('SERVER_URL') private readonly serverUrl: string, + private wds: WorkspaceDataService, private http: HttpClient ) { } - getFiles(workspaceId: number): Observable<GetFileResponseData[] | ServerError> { + getFiles(): Observable<GetFileResponseData[] | ServerError> { return this.http - .get<GetFileResponseData[]>(this.serverUrl + `workspace/${workspaceId}/files`) + .get<GetFileResponseData[]>(this.serverUrl + `workspace/${this.wds.wsId}/files`) .pipe(catchError(ErrorHandler.handle)); } - deleteFiles(workspaceId: number, filesToDelete: Array<string>): Observable<FileDeletionReport | ServerError> { + deleteFiles(filesToDelete: Array<string>): Observable<FileDeletionReport | ServerError> { return this.http - .request<FileDeletionReport>('delete', this.serverUrl + `workspace/${workspaceId}/files`, {body: {f: filesToDelete}}) + .request<FileDeletionReport>('delete', this.serverUrl + `workspace/${this.wds.wsId}/files`, {body: {f: filesToDelete}}) .pipe(catchError(ErrorHandler.handle)); } - checkWorkspace(workspaceId: number): Observable<CheckWorkspaceResponseData | ServerError> { + checkWorkspace(): Observable<CheckWorkspaceResponseData | ServerError> { return this.http - .get<CheckWorkspaceResponseData>(this.serverUrl + `workspace/${workspaceId}/validation`, {}) + .get<CheckWorkspaceResponseData>(this.serverUrl + `workspace/${this.wds.wsId}/validation`, {}) .pipe(catchError(ErrorHandler.handle)); } - getResultData(workspaceId: number): Observable<ResultData[]> { + getResultData(): Observable<ResultData[]> { return this.http - .get<ResultData[]>(this.serverUrl + `workspace/${workspaceId}/results`, {}) + .get<ResultData[]>(this.serverUrl + `workspace/${this.wds.wsId}/results`, {}) .pipe(catchError(() => [])); } - getResponses(workspaceId: number, groups: string[]): Observable<UnitResponse[]> { + getResponses(groups: string[]): Observable<UnitResponse[]> { return this.http - .get<UnitResponse[]>(this.serverUrl + `workspace/${workspaceId}/responses`, {params: {groups: groups.join(',')}}) + .get<UnitResponse[]>(this.serverUrl + `workspace/${this.wds.wsId}/responses`, {params: {groups: groups.join(',')}}) .pipe(catchError(() => [])); } - getLogs(workspaceId: number, groups: string[]): Observable<LogData[]> { + getLogs(groups: string[]): Observable<LogData[]> { return this.http - .get<LogData[]>(this.serverUrl + `workspace/${workspaceId}/logs`, {params: {groups: groups.join(',')}}) + .get<LogData[]>(this.serverUrl + `workspace/${this.wds.wsId}/logs`, {params: {groups: groups.join(',')}}) .pipe(catchError(() => [])); } - getReviews(workspaceId: number, groups: string[]): Observable<ReviewData[]> { + getReviews(groups: string[]): Observable<ReviewData[]> { return this.http - .get<ReviewData[]>(this.serverUrl + `workspace/${workspaceId}/reviews`, {params: {groups: groups.join(',')}}) + .get<ReviewData[]>(this.serverUrl + `workspace/${this.wds.wsId}/reviews`, {params: {groups: groups.join(',')}}) .pipe(catchError(() => [])); } - deleteData(workspaceId: number, groups: string[]): Observable<boolean | ServerError> { + deleteData(groups: string[]): Observable<boolean | ServerError> { return this.http - .request<boolean>('delete', this.serverUrl + `workspace/${workspaceId}/responses`, {body: {groups: groups}}) + .request<boolean>('delete', this.serverUrl + `workspace/${this.wds.wsId}/responses`, {body: {groups: groups}}) .pipe(catchError(ErrorHandler.handle)); } - getSysCheckReportList(workspaceId: number): Observable<SysCheckStatistics[] | ServerError> { + getSysCheckReportList(): Observable<SysCheckStatistics[] | ServerError> { return this.http - .get<ReviewData[]>(this.serverUrl + `workspace/${workspaceId}/sys-check/reports/overview`) + .get<ReviewData[]>(this.serverUrl + `workspace/${this.wds.wsId}/sys-check/reports/overview`) .pipe(catchError(() => [])); } - getSysCheckReport(workspaceId: number, reports: string[], enclosure: string, columnDelimiter: string, lineEnding: string) + getSysCheckReport(reports: string[], enclosure: string, columnDelimiter: string, lineEnding: string) : Observable<Blob|ServerError> { return this.http - .get(this.serverUrl + `workspace/${workspaceId}/sys-check/reports`, + .get(this.serverUrl + `workspace/${this.wds.wsId}/sys-check/reports`, { params: { checkIds: reports.join(','), @@ -102,17 +104,17 @@ export class BackendService { .pipe(catchError(ErrorHandler.handle)); } - deleteSysCheckReports(workspaceId: number, checkIds: string[]): Observable <FileDeletionReport|ServerError> { + deleteSysCheckReports(checkIds: string[]): Observable <FileDeletionReport|ServerError> { return this.http - .request<FileDeletionReport>('delete', this.serverUrl + `workspace/${workspaceId}/sys-check/reports`, {body: {checkIds: checkIds}}) + .request<FileDeletionReport>('delete', this.serverUrl + `workspace/${this.wds.wsId}/sys-check/reports`, {body: {checkIds: checkIds}}) .pipe(catchError(ErrorHandler.handle)); } - downloadFile(workspaceId: number, fileType: string, fileName: string): Observable<Blob|ServerError> { + downloadFile(fileType: string, fileName: string): Observable<Blob|ServerError> { return this.http - .get(this.serverUrl + `workspace/${workspaceId}/file/${fileType}/${fileName}`, {responseType: 'blob'}) + .get(this.serverUrl + `workspace/${this.wds.wsId}/file/${fileType}/${fileName}`, {responseType: 'blob'}) .pipe(catchError(ErrorHandler.handle)); } } diff --git a/src/app/workspace-admin/files/files.component.html b/src/app/workspace-admin/files/files.component.html index 34fa536f5628895698c06c40cf71877d4d4dedb4..dc91133db8451b90ad7fbc0d8274dd22ffe90467 100644 --- a/src/app/workspace-admin/files/files.component.html +++ b/src/app/workspace-admin/files/files.component.html @@ -1,8 +1,4 @@ <div class="columnhost"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> - <!-- ============================================= --> <div class="filelist"> <mat-table #table [dataSource]="serverfiles" matSort> diff --git a/src/app/workspace-admin/files/files.component.ts b/src/app/workspace-admin/files/files.component.ts index 06ced970feba139dffbcfabf5535e2b66962ad7a..d0d011979861def380271fe9d2ed67471e9565a8 100644 --- a/src/app/workspace-admin/files/files.component.ts +++ b/src/app/workspace-admin/files/files.component.ts @@ -3,11 +3,10 @@ import { WorkspaceDataService } from '../workspacedata.service'; import { GetFileResponseData, CheckWorkspaceResponseData } from '../workspace.interfaces'; import { ConfirmDialogComponent, ConfirmDialogData, MessageDialogComponent, MessageDialogData, MessageType, ServerError } from 'iqb-components'; -import { Subscription } from 'rxjs'; import { MatTableDataSource } from '@angular/material/table'; import { MatSnackBar } from '@angular/material/snack-bar'; import {BackendService, FileDeletionReport} from '../backend.service'; -import { Component, OnInit, Inject, OnDestroy } from '@angular/core'; +import { Component, OnInit, Inject } from '@angular/core'; import { ViewChild } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatSort } from '@angular/material/sort'; @@ -17,11 +16,9 @@ import { saveAs } from 'file-saver'; templateUrl: './files.component.html', styleUrls: ['./files.component.css'] }) -export class FilesComponent implements OnInit, OnDestroy { +export class FilesComponent implements OnInit { public serverfiles: MatTableDataSource<GetFileResponseData>; public displayedColumns = ['checked', 'filename', 'typelabel', 'filesize', 'filedatetime']; - public dataLoading = false; - private workspaceIdSubscription: Subscription = null; // for fileupload public uploadUrl = ''; @@ -42,17 +39,11 @@ export class FilesComponent implements OnInit, OnDestroy { public confirmDialog: MatDialog, public messsageDialog: MatDialog, public snackBar: MatSnackBar - ) { - this.wds.workspaceId$.subscribe(workspaceId => { - this.uploadUrl = this.serverUrl + `workspace/${workspaceId}/file`; - }); - this.uploadUrl = this.serverUrl + "workspace/" + this.wds.ws + '/file'; - } + ) { } ngOnInit() { - this.workspaceIdSubscription = this.wds.workspaceId$.subscribe(() => { - this.updateFileList((this.wds.ws <= 0) || (this.mds.adminToken.length === 0)); - }); + this.uploadUrl = `${this.serverUrl}workspace/${this.wds.wsId}/file`; + this.updateFileList(); } // *********************************************************************************** @@ -96,12 +87,15 @@ export class FilesComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (result !== false) { // ========================================================= - this.dataLoading = true; - this.bs.deleteFiles(this.wds.ws, filesToDelete).subscribe((fileDeletionReport: FileDeletionReport|ServerError) => { + this.mds.incrementDelayedProcessesCount(); + this.bs.deleteFiles(filesToDelete).subscribe((fileDeletionReport: FileDeletionReport|ServerError) => { if (fileDeletionReport instanceof ServerError) { - this.wds.setNewErrorMsg(fileDeletionReport as ServerError); + this.mds.appError$.next({ + label: (fileDeletionReport as ServerError).labelNice, + description: (fileDeletionReport as ServerError).labelSystem, + category: "PROBLEM" + }); } else { - const message = []; if (fileDeletionReport.deleted.length > 0) { message.push(fileDeletionReport.deleted.length + ' Dateien erfolgreich gelöscht.'); @@ -109,12 +103,10 @@ export class FilesComponent implements OnInit, OnDestroy { if (fileDeletionReport.not_allowed.length > 0) { message.push(fileDeletionReport.not_allowed.length + ' Dateien konnten nicht gelöscht werden.'); } - this.snackBar.open(message.join('<br>'), message.length > 1 ? 'Achtung' : '', {duration: 1000}); - this.updateFileList(); - this.wds.setNewErrorMsg(); } + this.mds.decrementDelayedProcessesCount(); }); // ========================================================= } @@ -141,16 +133,19 @@ export class FilesComponent implements OnInit, OnDestroy { if (empty || this.wds.wsRole === 'MO') { this.serverfiles = new MatTableDataSource([]); } else { - this.dataLoading = true; - this.bs.getFiles(this.wds.ws).subscribe( + this.mds.incrementDelayedProcessesCount(); + this.bs.getFiles().subscribe( (filedataresponse: GetFileResponseData[]) => { this.serverfiles = new MatTableDataSource(filedataresponse); this.serverfiles.sort = this.sort; - this.dataLoading = false; - this.wds.setNewErrorMsg(); + this.mds.decrementDelayedProcessesCount(); }, (err: ServerError) => { - this.wds.setNewErrorMsg(err); - this.dataLoading = false; + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } ); } @@ -159,17 +154,20 @@ export class FilesComponent implements OnInit, OnDestroy { download(element: GetFileResponseData): void { - this.dataLoading = true; - this.bs.downloadFile(this.wds.ws, element.type, element.filename) + this.mds.incrementDelayedProcessesCount(); + this.bs.downloadFile(element.type, element.filename) .subscribe( (fileData: Blob|ServerError) => { if (fileData instanceof ServerError) { - this.wds.setNewErrorMsg(fileData); - this.dataLoading = false; + this.mds.appError$.next({ + label: (fileData as ServerError).labelNice, + description: (fileData as ServerError).labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } else { saveAs(fileData, element.filename); - this.wds.setNewErrorMsg(); - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); } } ); @@ -181,26 +179,21 @@ export class FilesComponent implements OnInit, OnDestroy { this.checkWarnings = []; this.checkInfos = []; - this.dataLoading = true; - this.bs.checkWorkspace(this.wds.ws).subscribe( + this.mds.incrementDelayedProcessesCount(); + this.bs.checkWorkspace().subscribe( (checkResponse: CheckWorkspaceResponseData) => { this.checkErrors = checkResponse.errors; this.checkWarnings = checkResponse.warnings; this.checkInfos = checkResponse.infos; - this.wds.setNewErrorMsg(); - - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); }, (err: ServerError) => { - this.wds.setNewErrorMsg(err); - this.dataLoading = false; + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } ); } - - // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - ngOnDestroy() { - if (this.workspaceIdSubscription !== null) { - this.workspaceIdSubscription.unsubscribe(); - } - } } diff --git a/src/app/workspace-admin/results/results.component.html b/src/app/workspace-admin/results/results.component.html index 6f5c106a753c2a320b11b1f176d2b8b19da3d702..ab74cc95766ec2979e32c87b058c627596f7b054 100644 --- a/src/app/workspace-admin/results/results.component.html +++ b/src/app/workspace-admin/results/results.component.html @@ -1,7 +1,4 @@ <div class="columnhost" fxLayout="column"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> <div fxLayout="row"> <button mat-raised-button (click)="downloadResponsesCSV()" [disabled]="!tableselectionCheckbox.hasValue()" matTooltip="Download markierte Gruppen als CSV für Excel" matTooltipPosition="above"> diff --git a/src/app/workspace-admin/results/results.component.ts b/src/app/workspace-admin/results/results.component.ts index ee8e19cc464427d310f928bef24ff4d9f60f3e04..8ff72ef4a318a43bd648aee3681cec3641a8ba4f 100644 --- a/src/app/workspace-admin/results/results.component.ts +++ b/src/app/workspace-admin/results/results.component.ts @@ -1,7 +1,7 @@ import { LogData } from '../workspace.interfaces'; import { WorkspaceDataService } from '../workspacedata.service'; -import { ConfirmDialogComponent, ConfirmDialogData } from 'iqb-components'; -import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; +import {ConfirmDialogComponent, ConfirmDialogData, ServerError} from 'iqb-components'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { BackendService } from '../backend.service'; import { MatDialog } from '@angular/material/dialog'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -10,20 +10,18 @@ import { MatTableDataSource } from '@angular/material/table'; import { SelectionModel } from '@angular/cdk/collections'; import { saveAs } from 'file-saver'; import { ResultData, UnitResponse, ReviewData } from '../workspace.interfaces'; -import { Subscription } from 'rxjs'; +import {MainDataService} from "../../maindata.service"; @Component({ templateUrl: './results.component.html', styleUrls: ['./results.component.css'] }) -export class ResultsComponent implements OnInit, OnDestroy { +export class ResultsComponent implements OnInit { displayedColumns: string[] = ['selectCheckbox', 'groupname', 'bookletsStarted', 'num_units_min', 'num_units_max', 'num_units_mean', 'lastchange']; public resultDataSource = new MatTableDataSource<ResultData>([]); // prepared for selection if needed sometime public tableselectionCheckbox = new SelectionModel<ResultData>(true, []); - public dataLoading = false; - private workspaceIdSubscription: Subscription = null; @ViewChild(MatSort, { static: true }) sort: MatSort; @@ -31,13 +29,12 @@ export class ResultsComponent implements OnInit, OnDestroy { private bs: BackendService, public wds: WorkspaceDataService, private deleteConfirmDialog: MatDialog, + private mds: MainDataService, public snackBar: MatSnackBar ) { } ngOnInit() { - this.workspaceIdSubscription = this.wds.workspaceId$.subscribe(() => { - this.updateTable(); - }); + this.updateTable(); } updateTable() { @@ -45,12 +42,19 @@ export class ResultsComponent implements OnInit, OnDestroy { if (this.wds.wsRole === 'MO') { this.resultDataSource = new MatTableDataSource<ResultData>([]); } else { - this.dataLoading = true; - this.bs.getResultData(this.wds.ws).subscribe( + this.mds.incrementDelayedProcessesCount(); + this.bs.getResultData().subscribe( (resultData: ResultData[]) => { - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); this.resultDataSource = new MatTableDataSource<ResultData>(resultData); this.resultDataSource.sort = this.sort; + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } ); } @@ -71,12 +75,12 @@ export class ResultsComponent implements OnInit, OnDestroy { // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 downloadResponsesCSV() { if (this.tableselectionCheckbox.selected.length > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const selectedGroups: string[] = []; this.tableselectionCheckbox.selected.forEach(element => { selectedGroups.push(element.groupname); }); - this.bs.getResponses(this.wds.ws, selectedGroups).subscribe( + this.bs.getResponses(selectedGroups).subscribe( (responseData: UnitResponse[]) => { if (responseData.length > 0) { const columnDelimiter = ';'; @@ -126,20 +130,27 @@ export class ResultsComponent implements OnInit, OnDestroy { this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000}); } this.tableselectionCheckbox.clear(); - this.dataLoading = false; - }); + this.mds.decrementDelayedProcessesCount(); + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); + }); } } // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 downloadReviewsCSV() { if (this.tableselectionCheckbox.selected.length > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const selectedGroups: string[] = []; this.tableselectionCheckbox.selected.forEach(element => { selectedGroups.push(element.groupname); }); - this.bs.getReviews(this.wds.ws, selectedGroups).subscribe( + this.bs.getReviews(selectedGroups).subscribe( (responseData: ReviewData[]) => { if (responseData.length > 0) { // collect categories @@ -188,7 +199,14 @@ export class ResultsComponent implements OnInit, OnDestroy { this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000}); } this.tableselectionCheckbox.clear(); - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); }); } } @@ -196,12 +214,12 @@ export class ResultsComponent implements OnInit, OnDestroy { // 444444444444444444444444444444444444444444444444444444444444444444444444444444444444444 downloadLogsCSV() { if (this.tableselectionCheckbox.selected.length > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const selectedGroups: string[] = []; this.tableselectionCheckbox.selected.forEach(element => { selectedGroups.push(element.groupname); }); - this.bs.getLogs(this.wds.ws, selectedGroups).subscribe( + this.bs.getLogs(selectedGroups).subscribe( (responseData: LogData[]) => { if (responseData.length > 0) { const columnDelimiter = ';'; @@ -222,7 +240,14 @@ export class ResultsComponent implements OnInit, OnDestroy { this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000}); } this.tableselectionCheckbox.clear(); - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); }); } } @@ -254,21 +279,21 @@ export class ResultsComponent implements OnInit, OnDestroy { dialogRef.afterClosed().subscribe(result => { if (result !== false) { // ========================================================= - this.dataLoading = true; - this.bs.deleteData(this.wds.ws, selectedGroups).subscribe(() => { + this.mds.incrementDelayedProcessesCount(); + this.bs.deleteData(selectedGroups).subscribe(() => { this.tableselectionCheckbox.clear(); - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); // TODO refresh list! + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" }); - } - }); - } - } - - // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % - ngOnDestroy() { - if (this.workspaceIdSubscription !== null) { - this.workspaceIdSubscription.unsubscribe(); + this.mds.decrementDelayedProcessesCount(); + }); + } + }); } } } diff --git a/src/app/workspace-admin/syscheck/syscheck.component.html b/src/app/workspace-admin/syscheck/syscheck.component.html index efec8749ba166abf4e3abf465ac7c1893b66a9f2..37712264c7f206a43da0861a27c3312400718163 100644 --- a/src/app/workspace-admin/syscheck/syscheck.component.html +++ b/src/app/workspace-admin/syscheck/syscheck.component.html @@ -1,7 +1,4 @@ <div class="columnhost" fxLayout="column"> - <div class="spinner" *ngIf="dataLoading"> - <mat-spinner></mat-spinner> - </div> <div fxLayout="row" fxLayoutGap="10px"> <button mat-raised-button (click)="downloadReportsCSV()" [disabled]="!tableselectionCheckbox.hasValue()" matTooltip="Download Berichte als CSV für Excel" matTooltipPosition="above"> diff --git a/src/app/workspace-admin/syscheck/syscheck.component.ts b/src/app/workspace-admin/syscheck/syscheck.component.ts index b075f597791043cfabd84f9409064164afe5f253..960d7b1cb03cf35e981400ae9f34ad8d942aa292 100644 --- a/src/app/workspace-admin/syscheck/syscheck.component.ts +++ b/src/app/workspace-admin/syscheck/syscheck.component.ts @@ -8,7 +8,7 @@ import { MatTableDataSource } from '@angular/material/table'; import { SelectionModel } from '@angular/cdk/collections'; import { saveAs } from 'file-saver'; import { SysCheckStatistics } from '../workspace.interfaces'; -import { WorkspaceDataService } from '../workspacedata.service'; +import {MainDataService} from "../../maindata.service"; @Component({ @@ -20,14 +20,13 @@ export class SyscheckComponent implements OnInit { public resultDataSource = new MatTableDataSource<SysCheckStatistics>([]); // prepared for selection if needed sometime public tableselectionCheckbox = new SelectionModel<SysCheckStatistics>(true, []); - public dataLoading = false; @ViewChild(MatSort, { static: true }) sort: MatSort; constructor( private bs: BackendService, private deleteConfirmDialog: MatDialog, - public wds: WorkspaceDataService, + private mds: MainDataService, public snackBar: MatSnackBar ) { } @@ -37,13 +36,20 @@ export class SyscheckComponent implements OnInit { } updateTable() { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); this.tableselectionCheckbox.clear(); - this.bs.getSysCheckReportList(this.wds.ws).subscribe( + this.bs.getSysCheckReportList().subscribe( (resultData: SysCheckStatistics[]) => { - this.dataLoading = false; + this.mds.decrementDelayedProcessesCount(); this.resultDataSource = new MatTableDataSource<SysCheckStatistics>(resultData); this.resultDataSource.sort = this.sort; + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } ); } @@ -62,15 +68,14 @@ export class SyscheckComponent implements OnInit { downloadReportsCSV() { - if (this.tableselectionCheckbox.selected.length > 0) { - this.dataLoading = true; + this.mds.incrementDelayedProcessesCount(); const selectedReports: string[] = []; this.tableselectionCheckbox.selected.forEach(element => { selectedReports.push(element.id); }); // TODO determine OS dependent line ending char and use this - this.bs.getSysCheckReport(this.wds.ws, selectedReports, ';', '"', '\n').subscribe( + this.bs.getSysCheckReport(selectedReports, ';', '"', '\n').subscribe( (reportData: Blob) => { if (reportData.size > 0) { saveAs(reportData, 'iqb-testcenter-syscheckreports.csv'); @@ -78,8 +83,15 @@ export class SyscheckComponent implements OnInit { this.snackBar.open('Keine Daten verfügbar.', 'Fehler', {duration: 3000}); } this.tableselectionCheckbox.clear(); - this.dataLoading = false; - }); + this.mds.decrementDelayedProcessesCount(); + }, (err: ServerError) => { + this.mds.appError$.next({ + label: err.labelNice, + description: err.labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); + }); } } @@ -108,16 +120,17 @@ export class SyscheckComponent implements OnInit { }); dialogRef.afterClosed().subscribe(result => { - if (result !== false) { - - this.dataLoading = true; - this.bs.deleteSysCheckReports(this.wds.ws, selectedReports).subscribe((fileDeletionReport) => { - + this.mds.incrementDelayedProcessesCount(); + this.bs.deleteSysCheckReports(selectedReports).subscribe((fileDeletionReport) => { if (fileDeletionReport instanceof ServerError) { - this.wds.setNewErrorMsg(fileDeletionReport as ServerError); + this.mds.appError$.next({ + label: (fileDeletionReport as ServerError).labelNice, + description: (fileDeletionReport as ServerError).labelSystem, + category: "PROBLEM" + }); + this.mds.decrementDelayedProcessesCount(); } else { - const message = []; if (fileDeletionReport.deleted.length > 0) { message.push(fileDeletionReport.deleted.length + ' Dateien erfolgreich gelöscht.'); @@ -125,11 +138,9 @@ export class SyscheckComponent implements OnInit { if (fileDeletionReport.not_allowed.length > 0) { message.push(fileDeletionReport.not_allowed.length + ' Dateien konnten nicht gelöscht werden.'); } - this.snackBar.open(message.join('<br>'), message.length > 1 ? 'Achtung' : '', {duration: 1000}); - this.updateTable(); - this.wds.setNewErrorMsg(); + this.mds.decrementDelayedProcessesCount(); } }); } diff --git a/src/app/workspace-admin/workspace.component.ts b/src/app/workspace-admin/workspace.component.ts index 3958ab13f6ac91b3d8f3915e181c4d71ae02594c..78d2fbb04c760084d163a296195d8759fa144ccc 100644 --- a/src/app/workspace-admin/workspace.component.ts +++ b/src/app/workspace-admin/workspace.component.ts @@ -11,7 +11,6 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; }) export class WorkspaceComponent implements OnInit, OnDestroy { private routingSubscription: Subscription = null; - private logindataSubscription: Subscription = null; constructor( private route: ActivatedRoute, @@ -21,22 +20,17 @@ export class WorkspaceComponent implements OnInit, OnDestroy { ngOnInit() { this.routingSubscription = this.route.params.subscribe(params => { - const ws = Number(params['ws']); - this.wds.setWorkspace(ws); - }); - - this.logindataSubscription = this.mds.loginData$.subscribe(() => { - this.wds.setWorkspace(this.wds.ws); + this.wds.wsId = params['ws']; + const wsList = this.mds.workspaces; + if (wsList && wsList[this.wds.wsId]) { + this.wds.wsName = wsList[this.wds.wsId]; + } }); } - ngOnDestroy() { if (this.routingSubscription !== null) { this.routingSubscription.unsubscribe(); } - if (this.logindataSubscription !== null) { - this.logindataSubscription.unsubscribe(); - } } } diff --git a/src/app/workspace-admin/workspacedata.service.ts b/src/app/workspace-admin/workspacedata.service.ts index 1ad6f0061db1c0b221e74806862009147d89211e..e9b641ddb12fc40edda26414aaa8e62678c3f7b4 100644 --- a/src/app/workspace-admin/workspacedata.service.ts +++ b/src/app/workspace-admin/workspacedata.service.ts @@ -1,7 +1,4 @@ -import { BehaviorSubject } from 'rxjs'; import { Injectable } from '@angular/core'; -import { ServerError } from 'iqb-components'; -import { MainDataService } from "../maindata.service"; @Injectable({ providedIn: 'root' @@ -9,50 +6,13 @@ import { MainDataService } from "../maindata.service"; @Injectable() export class WorkspaceDataService { - public workspaceId$ = new BehaviorSubject<number>(-1); - public globalErrorMsg$ = new BehaviorSubject<ServerError>(null); + public wsId = ''; + public wsRole = 'RW'; + public wsName = ''; - public get ws(): number { - return this.workspaceId$.getValue(); - } - private _wsRole = ''; - public get wsRole(): string { - return this._wsRole; - } - private _wsName = ''; - public get wsName(): string { - return this._wsName; - } public navLinks = [ {path: 'files', label: 'Dateien'}, {path: 'syscheck', label: 'System-Check Berichte'}, {path: 'results', label: 'Ergebnisse/Antworten'} ]; - - constructor( - private mds: MainDataService - ) {} - - setNewErrorMsg(err: ServerError = null) { - this.globalErrorMsg$.next(err); - } - - setWorkspace(newId: number) { - this._wsName = ''; - this._wsRole = ''; - if (newId > 0) { - const myLoginData = this.mds.loginData$.getValue(); - if ((myLoginData !== null) && (myLoginData.workspaces.length > 0)) { - for (let i = 0; i < myLoginData.workspaces.length; i++) { - if (myLoginData.workspaces[i].id == newId) { - this._wsName = myLoginData.workspaces[i].name; - this._wsRole = myLoginData.workspaces[i].role; - break; - } - } - } - } - - this.workspaceId$.next(newId); - } }