Pull request #20: Permissions

Merge in RED/ui from permissions to master

* commit 'd23f5264c1ffe7b99a25721c82315c83ae4636f6':
  Hide buttons depending on user role
This commit is contained in:
Timo Bejan 2020-10-27 23:22:12 +01:00
commit da2e8b9335
13 changed files with 373 additions and 290 deletions

View File

@ -59,6 +59,7 @@ import { AssignOwnerDialogComponent } from './dialogs/assign-owner-dialog/assign
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core';
import { MatInputModule } from '@angular/material/input';
import { ProjectMemberGuard } from './auth/project-member-guard.service';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
@ -131,7 +132,12 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
component: ProjectOverviewScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
routeGuards: [
AuthGuard,
RedRoleGuard,
ProjectMemberGuard,
AppStateGuard
]
}
},
{
@ -139,7 +145,12 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
component: FilePreviewScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard]
routeGuards: [
AuthGuard,
RedRoleGuard,
ProjectMemberGuard,
AppStateGuard
]
}
}
]

View File

@ -0,0 +1,53 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { UserService } from '../user/user.service';
import { AppLoadStateService } from '../utils/app-load-state.service';
import { Observable } from 'rxjs';
import { AppStateService } from '../state/app-state.service';
import { NotificationService, NotificationType } from '../notification/notification.service';
import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root'
})
export class ProjectMemberGuard implements CanActivate {
constructor(
private readonly _router: Router,
private readonly _appLoadStateService: AppLoadStateService,
private readonly _appStateService: AppStateService,
private readonly _userService: UserService,
private readonly _notificationService: NotificationService,
private readonly _translateService: TranslateService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return new Observable((obs) => {
if (this._userService.isManager(this._userService.user)) {
obs.next(true);
obs.complete();
return;
}
const projectId = route.params.projectId;
this._appStateService.loadAllProjects().then(() => {
const isProjectMember = this._appStateService.allProjects
.find((pw) => pw.project.projectId === projectId)
?.project.memberIds.includes(this._userService.user.id);
if (!isProjectMember) {
this._router.navigate(['ui', 'projects']);
this._appLoadStateService.pushLoadingEvent(false);
this._notificationService.showToastNotification(
this._translateService.instant('project-member-guard.access-denied.label'),
null,
NotificationType.ERROR
);
obs.next(false);
obs.complete();
} else {
obs.next(true);
obs.complete();
}
});
});
}
}

View File

@ -231,7 +231,7 @@ export class DialogService {
return ref;
}
public openAssignFileOwnerDialog(
public openAssignFileReviewerDialog(
$event: MouseEvent,
file: FileStatus,
cb?: Function

View File

@ -12,13 +12,21 @@
<div class="flex-1 actions-container">
<div class="actions-row">
<button mat-icon-button (click)="openDeleteFileDialog($event)">
<button
mat-icon-button
(click)="openDeleteFileDialog($event)"
*ngIf="userService.isManager(this.user) || appStateService.isActiveProjectOwner"
>
<mat-icon svgIcon="red:trash"></mat-icon>
</button>
<button mat-icon-button>
<mat-icon svgIcon="red:report"></mat-icon>
</button>
<button mat-icon-button (click)="openAssignFileOwnerDialog($event)">
<button
mat-icon-button
(click)="openAssignFileReviewerDialog($event)"
*ngIf="appStateService.isActiveProjectMember"
>
<mat-icon svgIcon="red:assign"></mat-icon>
</button>
<button mat-icon-button (click)="reanalyseFile($event)">
@ -30,6 +38,7 @@
</div>
<button
*ngIf="userService.isManager(user) || appStateService.isActiveProjectOwner"
color="primary"
mat-flat-button
class="arrow-button"

View File

@ -1,33 +1,20 @@
import {
ChangeDetectorRef,
Component,
ElementRef,
HostListener,
NgZone,
OnInit,
ViewChild,
EventEmitter
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import {
DictionaryControllerService,
ManualRedactionEntry,
ReanalysisControllerService
} from '@redaction/red-ui-http';
import { AppStateService } from '../../../state/app-state.service';
import { Annotations, WebViewerInstance } from '@pdftron/webviewer';
import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component';
import { AnnotationUtils } from '../../../utils/annotation-utils';
import { UserService } from '../../../user/user.service';
import { debounce } from '../../../utils/debounce';
import {ChangeDetectorRef, Component, ElementRef, HostListener, NgZone, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {ManualRedactionEntry, ReanalysisControllerService} from '@redaction/red-ui-http';
import {AppStateService} from '../../../state/app-state.service';
import {Annotations, WebViewerInstance} from '@pdftron/webviewer';
import {PdfViewerComponent} from '../pdf-viewer/pdf-viewer.component';
import {AnnotationUtils} from '../../../utils/annotation-utils';
import {UserService} from '../../../user/user.service';
import {debounce} from '../../../utils/debounce';
import scrollIntoView from 'scroll-into-view-if-needed';
import { AnnotationFilters } from '../../../utils/types';
import { FiltersService } from '../service/filters.service';
import { FileDownloadService } from '../service/file-download.service';
import { saveAs } from 'file-saver';
import { FileType } from '../model/file-type';
import { DialogService } from '../../../dialogs/dialog.service';
import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
import {AnnotationFilters} from '../../../utils/types';
import {FiltersService} from '../service/filters.service';
import {FileDownloadService} from '../service/file-download.service';
import {saveAs} from 'file-saver';
import {FileType} from '../model/file-type';
import {DialogService} from '../../../dialogs/dialog.service';
import {MatDialogRef, MatDialogState} from '@angular/material/dialog';
@Component({
selector: 'redaction-file-preview-screen',
@ -57,12 +44,11 @@ export class FilePreviewScreenComponent implements OnInit {
constructor(
public readonly appStateService: AppStateService,
public readonly userService: UserService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _activatedRoute: ActivatedRoute,
private readonly _dialogService: DialogService,
private readonly _router: Router,
private readonly _dictionaryControllerService: DictionaryControllerService,
private readonly _userService: UserService,
private readonly _fileDownloadService: FileDownloadService,
private readonly _reanalysisControllerService: ReanalysisControllerService,
private readonly _filtersService: FiltersService,
@ -76,7 +62,7 @@ export class FilePreviewScreenComponent implements OnInit {
}
public get user() {
return this._userService.user;
return this.userService.user;
}
public filterKeys(key?: string) {
@ -145,9 +131,9 @@ export class FilePreviewScreenComponent implements OnInit {
);
}
public openAssignFileOwnerDialog($event: MouseEvent) {
public openAssignFileReviewerDialog($event: MouseEvent) {
const file = this.appStateService.getFileById(this.projectId, this.fileId);
this._dialogRef = this._dialogService.openAssignFileOwnerDialog($event, file);
this._dialogRef = this._dialogService.openAssignFileReviewerDialog($event, file);
}
public get activeViewer() {

View File

@ -22,11 +22,12 @@
</div>
<button
(click)="openAddProjectDialog()"
*ngIf="userService.isManager(user)"
class="add-project-btn"
color="primary"
mat-flat-button
class="add-project-btn"
>
<mat-icon svgIcon="red:plus"> </mat-icon>
<mat-icon svgIcon="red:plus"></mat-icon>
<span translate="project-listing.add-new.label"></span>
</button>
</div>
@ -73,18 +74,19 @@
</div>
<div
class="no-data"
*ngIf="appStateService.allProjects?.length === 0"
class="no-data"
translate="project-listing.no-projects.label"
></div>
<div
class="table-item pointer"
[routerLink]="'/ui/projects/' + pw.project.projectId"
*ngFor="
let pw of appStateService.allProjects
| sortBy: sortingOption.order:sortingOption.column
"
[routerLink]="[canOpenProject(pw) ? '/ui/projects/' + pw.project.projectId : []]"
class="table-item"
[class.pointer]="canOpenProject(pw)"
>
<div>
<div class="table-item-title table-item-title--large">
@ -122,26 +124,28 @@
<div class="action-buttons">
<button
mat-icon-button
color="accent"
(click)="openDeleteProjectDialog($event, pw.project)"
[matTooltip]="'project-listing.delete.action.label' | translate"
*ngIf="userService.isManager(user)"
color="accent"
mat-icon-button
>
<mat-icon svgIcon="red:trash"></mat-icon>
</button>
<button
mat-icon-button
color="accent"
(click)="downloadRedactionReport($event, pw.project)"
[matTooltip]="'project-listing.report.action.label' | translate"
color="accent"
>
<mat-icon svgIcon="red:report"></mat-icon>
</button>
<button
color="accent"
(click)="openAssignProjectOwnerDialog($event, pw.project)"
mat-icon-button
[matTooltip]="'project-listing.assign.action.label' | translate"
*ngIf="userService.isManager(user)"
color="accent"
mat-icon-button
>
<mat-icon svgIcon="red:assign"></mat-icon>
</button>

View File

@ -1,12 +1,11 @@
import { Component, OnInit } from '@angular/core';
import { FileUploadControllerService, Project } from '@redaction/red-ui-http';
import { AppStateService, ProjectWrapper } from '../../state/app-state.service';
import { UserService } from '../../user/user.service';
import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
import { SortingOption } from '../../utils/types';
import { groupBy } from '../../utils/functions';
import { DialogService } from '../../dialogs/dialog.service';
import { download } from '../../utils/file-download-utils';
import {Component, OnInit} from '@angular/core';
import {Project} from '@redaction/red-ui-http';
import {AppStateService, ProjectWrapper} from '../../state/app-state.service';
import {UserService} from '../../user/user.service';
import {DoughnutChartConfig} from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
import {SortingOption} from '../../utils/types';
import {groupBy} from '../../utils/functions';
import {DialogService} from '../../dialogs/dialog.service';
@Component({
selector: 'redaction-project-listing-screen',
@ -28,8 +27,7 @@ export class ProjectListingScreenComponent implements OnInit {
constructor(
public readonly appStateService: AppStateService,
private readonly _fileUploadControllerService: FileUploadControllerService,
private readonly _userService: UserService,
public readonly userService: UserService,
private readonly _dialogService: DialogService
) {}
@ -54,7 +52,7 @@ export class ProjectListingScreenComponent implements OnInit {
}
public get user() {
return this._userService.user;
return this.userService.user;
}
public get totalPages() {
@ -84,6 +82,10 @@ export class ProjectListingScreenComponent implements OnInit {
return 1;
}
public canOpenProject(pw: ProjectWrapper): boolean {
return this.userService.isManager(this.user) || pw.project.memberIds.includes(this.user.id);
}
public openAddProjectDialog(): void {
this._dialogService.openAddProjectDialog(() => {
this._calculateData();

View File

@ -194,6 +194,9 @@
<button
(click)="openDeleteFileDialog($event, fileStatus)"
color="accent"
*ngIf="
userService.isManager(user) || appStateService.isActiveProjectOwner
"
mat-icon-button
[matTooltip]="'project-overview.delete.action.label' | translate"
>
@ -208,8 +211,9 @@
<mat-icon svgIcon="red:report"></mat-icon>
</button>
<button
(click)="openAssignFileOwnerDialog($event, fileStatus)"
(click)="openAssignFileReviewerDialog($event, fileStatus)"
color="accent"
*ngIf="appStateService.isActiveProjectMember"
mat-icon-button
[matTooltip]="'project-overview.assign.action.label' | translate"
>
@ -231,10 +235,18 @@
<div class="project-details-container right-fixed-container">
<div class="actions-row">
<button mat-icon-button (click)="openDeleteProjectDialog($event)">
<button
mat-icon-button
*ngIf="userService.isManager(user)"
(click)="openDeleteProjectDialog($event)"
>
<mat-icon svgIcon="red:trash"></mat-icon>
</button>
<button mat-icon-button (click)="openEditProjectDialog($event)">
<button
mat-icon-button
*ngIf="userService.isManager(user)"
(click)="openEditProjectDialog($event)"
>
<mat-icon svgIcon="red:edit"></mat-icon>
</button>
<button mat-icon-button (click)="downloadRedactionReport($event)">
@ -292,7 +304,11 @@
<div class="member" *ngIf="overflowCount">
<div class="oval large white-dark">+{{ overflowCount }}</div>
</div>
<div class="member pointer" (click)="openAssignProjectMembersDialog()">
<div
class="member pointer"
(click)="openAssignProjectMembersDialog()"
*ngIf="userService.isManager(user)"
>
<div class="oval red-white large">+</div>
</div>
</div>

View File

@ -1,235 +1,234 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import {Component, OnDestroy, OnInit} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {
FileStatus,
FileUploadControllerService,
ReanalysisControllerService,
StatusControllerService
FileStatus,
FileUploadControllerService,
ReanalysisControllerService,
StatusControllerService
} from '@redaction/red-ui-http';
import { NotificationService } from '../../notification/notification.service';
import { AppStateService } from '../../state/app-state.service';
import { FileDropOverlayService } from '../../upload/file-drop/service/file-drop-overlay.service';
import { FileUploadModel } from '../../upload/model/file-upload.model';
import { FileUploadService } from '../../upload/file-upload.service';
import { UploadStatusOverlayService } from '../../upload/upload-status-dialog/service/upload-status-overlay.service';
import { UserService } from '../../user/user.service';
import { SortingOption } from '../../utils/types';
import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
import { groupBy } from '../../utils/functions';
import { DialogService } from '../../dialogs/dialog.service';
import { download } from '../../utils/file-download-utils';
import {NotificationService} from '../../notification/notification.service';
import {AppStateService} from '../../state/app-state.service';
import {FileDropOverlayService} from '../../upload/file-drop/service/file-drop-overlay.service';
import {FileUploadModel} from '../../upload/model/file-upload.model';
import {FileUploadService} from '../../upload/file-upload.service';
import {UploadStatusOverlayService} from '../../upload/upload-status-dialog/service/upload-status-overlay.service';
import {UserService} from '../../user/user.service';
import {SortingOption} from '../../utils/types';
import {DoughnutChartConfig} from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
import {groupBy} from '../../utils/functions';
import {DialogService} from '../../dialogs/dialog.service';
@Component({
selector: 'redaction-project-overview-screen',
templateUrl: './project-overview-screen.component.html',
styleUrls: ['./project-overview-screen.component.scss']
selector: 'redaction-project-overview-screen',
templateUrl: './project-overview-screen.component.html',
styleUrls: ['./project-overview-screen.component.scss']
})
export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
private _selectedFileIds: string[] = [];
private _selectedFileIds: string[] = [];
public sortingOptions: SortingOption[] = [
{ label: 'project-overview.sorting.recent.label', order: 'desc', column: 'lastUpdated' },
{ label: 'project-overview.sorting.oldest.label', order: 'asc', column: 'lastUpdated' },
{
label: 'project-overview.sorting.alphabetically.label',
order: 'asc',
column: 'filename'
},
{
label: 'project-overview.sorting.number-of-pages.label',
order: 'asc',
column: 'numberOfPages'
},
{
label: 'project-overview.sorting.number-of-analyses.label',
order: 'desc',
column: 'numberOfAnalyses'
}
];
public sortingOption: SortingOption = this.sortingOptions[0];
public documentsChartData: DoughnutChartConfig[] = [];
constructor(
public readonly appStateService: AppStateService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _fileUploadControllerService: FileUploadControllerService,
private readonly _statusControllerService: StatusControllerService,
private readonly _notificationService: NotificationService,
private readonly _dialogService: DialogService,
private readonly _fileUploadService: FileUploadService,
private readonly _uploadStatusOverlayService: UploadStatusOverlayService,
private readonly _reanalysisControllerService: ReanalysisControllerService,
private readonly _router: Router,
private readonly _userService: UserService,
private readonly _fileDropOverlayService: FileDropOverlayService
) {
this._activatedRoute.params.subscribe((params) => {
this.appStateService.activateProject(params.projectId);
});
this.appStateService.fileStatusChanged.subscribe(() => {
this._calculateChartConfig();
});
public sortingOptions: SortingOption[] = [
{label: 'project-overview.sorting.recent.label', order: 'desc', column: 'lastUpdated'},
{label: 'project-overview.sorting.oldest.label', order: 'asc', column: 'lastUpdated'},
{
label: 'project-overview.sorting.alphabetically.label',
order: 'asc',
column: 'filename'
},
{
label: 'project-overview.sorting.number-of-pages.label',
order: 'asc',
column: 'numberOfPages'
},
{
label: 'project-overview.sorting.number-of-analyses.label',
order: 'desc',
column: 'numberOfAnalyses'
}
];
public sortingOption: SortingOption = this.sortingOptions[0];
public documentsChartData: DoughnutChartConfig[] = [];
ngOnInit(): void {
this._fileDropOverlayService.initFileDropHandling();
constructor(
public readonly appStateService: AppStateService,
public readonly userService: UserService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _fileUploadControllerService: FileUploadControllerService,
private readonly _statusControllerService: StatusControllerService,
private readonly _notificationService: NotificationService,
private readonly _dialogService: DialogService,
private readonly _fileUploadService: FileUploadService,
private readonly _uploadStatusOverlayService: UploadStatusOverlayService,
private readonly _reanalysisControllerService: ReanalysisControllerService,
private readonly _router: Router,
private readonly _fileDropOverlayService: FileDropOverlayService
) {
this._activatedRoute.params.subscribe((params) => {
this.appStateService.activateProject(params.projectId);
});
this.appStateService.fileStatusChanged.subscribe(() => {
this._calculateChartConfig();
});
}
ngOnInit(): void {
this._fileDropOverlayService.initFileDropHandling();
this._calculateChartConfig();
}
ngOnDestroy(): void {
this._fileDropOverlayService.cleanupFileDropHandling();
}
public get activeProject() {
return this.appStateService.activeProject.project;
}
public get user() {
return this.userService.user;
}
public get displayMembers() {
return this.activeProject.memberIds.slice(0, 6);
}
public get overflowCount() {
return this.activeProject.memberIds.length > 6
? this.activeProject.memberIds.length - 6
: 0;
}
private _reloadProjects() {
this.appStateService.loadAllProjects().then(() => {
this._calculateChartConfig();
});
}
private _calculateChartConfig() {
const groups = groupBy(this.appStateService.activeProject.files, 'status');
this.documentsChartData = [];
for (const key of Object.keys(groups)) {
this.documentsChartData.push({value: groups[key].length, color: key, label: key});
}
}
public toggleFileSelected($event: MouseEvent, file: FileStatus) {
$event.stopPropagation();
const idx = this._selectedFileIds.indexOf(file.fileId);
if (idx === -1) {
this._selectedFileIds.push(file.fileId);
} else {
this._selectedFileIds.splice(idx, 1);
}
}
public toggleSelectAll() {
if (this.areAllFilesSelected()) {
this._selectedFileIds = [];
} else {
this._selectedFileIds = this.appStateService.activeProject.files.map(
(file) => file.fileId
);
}
}
public areAllFilesSelected() {
return (
this.appStateService.activeProject.files.length !== 0 &&
this._selectedFileIds.length === this.appStateService.activeProject.files.length
);
}
public isFileSelected(file: FileStatus) {
return this._selectedFileIds.indexOf(file.fileId) !== -1;
}
public openDeleteFileDialog($event: MouseEvent, fileStatus: FileStatus) {
this._dialogService.openDeleteFileDialog(
$event,
fileStatus.projectId,
fileStatus.fileId,
() => {
this._calculateChartConfig();
}
);
}
downloadFileRedactionReport($event: MouseEvent, file: FileStatus) {
$event.stopPropagation();
this.appStateService.downloadFileRedactionReport(file);
}
downloadRedactionReport($event: MouseEvent) {
$event.stopPropagation();
this.appStateService.downloadRedactionReport();
}
public openEditProjectDialog($event: MouseEvent) {
this._dialogService.openEditProjectDialog(
$event,
this.appStateService.activeProject.project
);
}
public openDeleteProjectDialog($event: MouseEvent) {
this._dialogService.openDeleteProjectDialog(
$event,
this.appStateService.activeProject.project,
() => {
this._router.navigate(['/ui/projects']);
}
);
}
public openAssignProjectMembersDialog() {
this._dialogService.openAssignProjectMembersAndOwnerDialog(null, this.activeProject, () => {
this._reloadProjects();
});
}
public openAssignFileReviewerDialog($event: MouseEvent, file: FileStatus) {
this._dialogService.openAssignFileReviewerDialog($event, file, () => {
this._reloadProjects();
});
}
public reanalyseFile($event: MouseEvent, fileStatus: FileStatus) {
$event.stopPropagation();
this._reanalysisControllerService
.reanalyzeFile(this.appStateService.activeProject.project.projectId, fileStatus.fileId)
.subscribe(() => {
this._reloadProjects();
});
}
public fileId(index, item) {
return item.fileId;
}
public uploadFiles(files: FileList | File[]) {
const uploadFiles: FileUploadModel[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
uploadFiles.push({
file: file,
progress: 0,
completed: false,
error: null
});
}
ngOnDestroy(): void {
this._fileDropOverlayService.cleanupFileDropHandling();
}
this._fileUploadService.uploadFiles(uploadFiles);
this._uploadStatusOverlayService.openStatusOverlay();
}
public get activeProject() {
return this.appStateService.activeProject.project;
}
public canOpenFile(fileStatus: FileStatus): boolean {
// TODO check correct condition for this
return fileStatus === 'PROCESSING' || fileStatus === 'REVIEWED' || true;
}
public get user() {
return this._userService.user;
}
public get displayMembers() {
return this.activeProject.memberIds.slice(0, 6);
}
public get overflowCount() {
return this.activeProject.memberIds.length > 6
? this.activeProject.memberIds.length - 6
: 0;
}
private _getFileStatus() {
this.appStateService.reloadActiveProjectFiles().then(() => {
this._calculateChartConfig();
});
}
private _calculateChartConfig() {
const groups = groupBy(this.appStateService.activeProject.files, 'status');
this.documentsChartData = [];
for (const key of Object.keys(groups)) {
this.documentsChartData.push({ value: groups[key].length, color: key, label: key });
}
}
public toggleFileSelected($event: MouseEvent, file: FileStatus) {
$event.stopPropagation();
const idx = this._selectedFileIds.indexOf(file.fileId);
if (idx === -1) {
this._selectedFileIds.push(file.fileId);
} else {
this._selectedFileIds.splice(idx, 1);
}
}
public toggleSelectAll() {
if (this.areAllFilesSelected()) {
this._selectedFileIds = [];
} else {
this._selectedFileIds = this.appStateService.activeProject.files.map(
(file) => file.fileId
);
}
}
public areAllFilesSelected() {
return (
this.appStateService.activeProject.files.length !== 0 &&
this._selectedFileIds.length === this.appStateService.activeProject.files.length
);
}
public isFileSelected(file: FileStatus) {
return this._selectedFileIds.indexOf(file.fileId) !== -1;
}
public openDeleteFileDialog($event: MouseEvent, fileStatus: FileStatus) {
this._dialogService.openDeleteFileDialog(
$event,
fileStatus.projectId,
fileStatus.fileId,
() => {
this._calculateChartConfig();
}
);
}
downloadFileRedactionReport($event: MouseEvent, file: FileStatus) {
$event.stopPropagation();
this.appStateService.downloadFileRedactionReport(file);
}
downloadRedactionReport($event: MouseEvent) {
$event.stopPropagation();
this.appStateService.downloadRedactionReport();
}
public openEditProjectDialog($event: MouseEvent) {
this._dialogService.openEditProjectDialog(
$event,
this.appStateService.activeProject.project
);
}
public openDeleteProjectDialog($event: MouseEvent) {
this._dialogService.openDeleteProjectDialog(
$event,
this.appStateService.activeProject.project,
() => {
this._router.navigate(['/ui/projects']);
}
);
}
public openAssignProjectMembersDialog() {
this._dialogService.openAssignProjectMembersAndOwnerDialog(null, this.activeProject, () => {
this._getFileStatus();
});
}
public openAssignFileOwnerDialog($event: MouseEvent, file: FileStatus) {
this._dialogService.openAssignFileOwnerDialog($event, file, () => {
this._getFileStatus();
});
}
public reanalyseFile($event: MouseEvent, fileStatus: FileStatus) {
$event.stopPropagation();
this._reanalysisControllerService
.reanalyzeFile(this.appStateService.activeProject.project.projectId, fileStatus.fileId)
.subscribe(() => {
this._getFileStatus();
});
}
public fileId(index, item) {
return item.fileId;
}
public uploadFiles(files: FileList | File[]) {
const uploadFiles: FileUploadModel[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
uploadFiles.push({
file: file,
progress: 0,
completed: false,
error: null
});
}
this._fileUploadService.uploadFiles(uploadFiles);
this._uploadStatusOverlayService.openStatusOverlay();
}
public canOpenFile(fileStatus: FileStatus): boolean {
// TODO check correct condition for this
return fileStatus === 'PROCESSING' || fileStatus === 'REVIEWED' || true;
}
public toggleSortByAddedOn() {
const sortedByRecent: boolean = this.sortingOption === this.sortingOptions[0];
this.sortingOption = sortedByRecent ? this.sortingOptions[1] : this.sortingOptions[0];
}
public toggleSortByAddedOn() {
const sortedByRecent: boolean = this.sortingOption === this.sortingOptions[0];
this.sortingOption = sortedByRecent ? this.sortingOptions[1] : this.sortingOptions[0];
}
}

View File

@ -90,9 +90,7 @@ export class AppStateService {
}
get isActiveProjectMember() {
return (
this._appState.activeProject?.project?.memberIds?.indexOf(this._userService.userId) >= 0
);
return this._appState.activeProject?.project?.memberIds?.includes(this._userService.userId);
}
get dictionaryData() {

View File

@ -99,11 +99,11 @@ export class UserService {
: undefined;
}
isManager(user: User) {
isManager(user: User): boolean {
return user.roles.indexOf('RED_MANAGER') >= 0;
}
isUser(user: User) {
isUser(user: User): boolean {
return user.roles.indexOf('RED_USER') >= 0;
}

View File

@ -527,6 +527,11 @@
}
}
},
"project-member-guard": {
"access-denied": {
"label": "You are not allowed to access that page."
}
},
"unassigned": "Unassigned",
"under-review": "Under review",
"under-approval": "Under approval",

0
package-lock.json generated
View File