Pull request #15: [WIP] Assign members
Merge in RED/ui from assign-members to master * commit '6bebc5409d073ef09e08826d110f1b51d97a1e03': Assign project owner Fix clearInterval Assign project members
This commit is contained in:
commit
deffdc7d80
@ -1,60 +1,63 @@
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {APP_INITIALIZER, NgModule} from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||
|
||||
import {AppComponent} from './app.component';
|
||||
import {ActivatedRoute, Router, RouterModule} from '@angular/router';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import {BaseScreenComponent} from './screens/base-screen/base-screen.component';
|
||||
import {ProjectListingScreenComponent} from './screens/project-listing-screen/project-listing-screen.component';
|
||||
import {ProjectOverviewScreenComponent} from './screens/project-overview-screen/project-overview-screen.component';
|
||||
import {MatToolbarModule} from '@angular/material/toolbar';
|
||||
import {ApiModule} from '@redaction/red-ui-http';
|
||||
import {ApiPathInterceptorService} from './interceptor/api-path-interceptor.service';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
|
||||
import {MatMenuModule} from '@angular/material/menu';
|
||||
import {languageInitializer} from './i18n/language.initializer';
|
||||
import {LanguageService} from './i18n/language.service';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {IconsModule} from './icons/icons.module';
|
||||
import {AddEditProjectDialogComponent} from './screens/project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import {MatDialogModule} from '@angular/material/dialog';
|
||||
import {MatSnackBarModule} from '@angular/material/snack-bar';
|
||||
import {MatTooltipModule} from '@angular/material/tooltip';
|
||||
import {ConfirmationDialogComponent} from './common/confirmation-dialog/confirmation-dialog.component';
|
||||
import {FilePreviewScreenComponent} from './screens/file/file-preview-screen/file-preview-screen.component';
|
||||
import {PdfViewerComponent} from './screens/file/pdf-viewer/pdf-viewer.component';
|
||||
import {MatTabsModule} from '@angular/material/tabs';
|
||||
import {MatButtonToggleModule} from '@angular/material/button-toggle';
|
||||
import {NgpSortModule} from 'ngp-sort-pipe';
|
||||
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatSelectModule} from '@angular/material/select';
|
||||
import {MatSidenavModule} from '@angular/material/sidenav';
|
||||
import {FileDetailsDialogComponent} from './screens/file/file-preview-screen/file-details-dialog/file-details-dialog.component';
|
||||
import {ToastrModule} from 'ngx-toastr';
|
||||
import {ServiceWorkerModule} from '@angular/service-worker';
|
||||
import {environment} from '../environments/environment';
|
||||
import {ProjectDetailsDialogComponent} from './screens/project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import {AuthModule} from './auth/auth.module';
|
||||
import {FileUploadModule} from './upload/file-upload.module';
|
||||
import {FullPageLoadingIndicatorComponent} from './utils/full-page-loading-indicator/full-page-loading-indicator.component';
|
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||
import {InitialsAvatarComponent} from './common/initials-avatar/initials-avatar.component';
|
||||
import {StatusBarComponent} from './components/status-bar/status-bar.component';
|
||||
import {LogoComponent} from './logo/logo.component';
|
||||
import {CompositeRouteGuard} from './utils/composite-route.guard';
|
||||
import {AppStateGuard} from './state/app-state.guard';
|
||||
import {SimpleDoughnutChartComponent} from './components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import {ManualRedactionDialogComponent} from './screens/file/manual-redaction-dialog/manual-redaction-dialog.component';
|
||||
import {MatCheckboxModule} from '@angular/material/checkbox';
|
||||
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
|
||||
import {AnnotationIconComponent} from './components/annotation-icon/annotation-icon.component';
|
||||
import {AuthGuard} from "./auth/auth.guard";
|
||||
import {AuthErrorComponent} from './screens/auth-error/auth-error.component';
|
||||
import {RedRoleGuard} from "./auth/red-role.guard";
|
||||
import { AppComponent } from './app.component';
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { BaseScreenComponent } from './screens/base-screen/base-screen.component';
|
||||
import { ProjectListingScreenComponent } from './screens/project-listing-screen/project-listing-screen.component';
|
||||
import { ProjectOverviewScreenComponent } from './screens/project-overview-screen/project-overview-screen.component';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { ApiModule } from '@redaction/red-ui-http';
|
||||
import { ApiPathInterceptorService } from './interceptor/api-path-interceptor.service';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { languageInitializer } from './i18n/language.initializer';
|
||||
import { LanguageService } from './i18n/language.service';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { IconsModule } from './icons/icons.module';
|
||||
import { AddEditProjectDialogComponent } from './screens/project-listing-screen/add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ConfirmationDialogComponent } from './common/confirmation-dialog/confirmation-dialog.component';
|
||||
import { FilePreviewScreenComponent } from './screens/file/file-preview-screen/file-preview-screen.component';
|
||||
import { PdfViewerComponent } from './screens/file/pdf-viewer/pdf-viewer.component';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { NgpSortModule } from 'ngp-sort-pipe';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { FileDetailsDialogComponent } from './screens/file/file-preview-screen/file-details-dialog/file-details-dialog.component';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
import { environment } from '../environments/environment';
|
||||
import { ProjectDetailsDialogComponent } from './screens/project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { FileUploadModule } from './upload/file-upload.module';
|
||||
import { FullPageLoadingIndicatorComponent } from './utils/full-page-loading-indicator/full-page-loading-indicator.component';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { InitialsAvatarComponent } from './common/initials-avatar/initials-avatar.component';
|
||||
import { StatusBarComponent } from './components/status-bar/status-bar.component';
|
||||
import { LogoComponent } from './logo/logo.component';
|
||||
import { CompositeRouteGuard } from './utils/composite-route.guard';
|
||||
import { AppStateGuard } from './state/app-state.guard';
|
||||
import { SimpleDoughnutChartComponent } from './components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import { ManualRedactionDialogComponent } from './screens/file/manual-redaction-dialog/manual-redaction-dialog.component';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { AnnotationIconComponent } from './components/annotation-icon/annotation-icon.component';
|
||||
import { AuthGuard } from './auth/auth.guard';
|
||||
import { AuthErrorComponent } from './screens/auth-error/auth-error.component';
|
||||
import { RedRoleGuard } from './auth/red-role.guard';
|
||||
import { AssignProjectMembersDialogComponent } from './screens/project-overview-screen/project-members-dialog/assign-project-members-dialog.component';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { AssignOwnerDialogComponent } from './components/project-members-dialog/assign-owner-dialog.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
@ -72,6 +75,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
PdfViewerComponent,
|
||||
FileDetailsDialogComponent,
|
||||
ProjectDetailsDialogComponent,
|
||||
AssignProjectMembersDialogComponent,
|
||||
AssignOwnerDialogComponent,
|
||||
FullPageLoadingIndicatorComponent,
|
||||
InitialsAvatarComponent,
|
||||
StatusBarComponent,
|
||||
@ -79,7 +84,7 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
SimpleDoughnutChartComponent,
|
||||
ManualRedactionDialogComponent,
|
||||
AnnotationIconComponent,
|
||||
AuthErrorComponent,
|
||||
AuthErrorComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@ -156,9 +161,10 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
MatSelectModule,
|
||||
MatSidenavModule,
|
||||
FileUploadModule,
|
||||
ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}),
|
||||
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
||||
MatProgressSpinnerModule,
|
||||
MatCheckboxModule
|
||||
MatCheckboxModule,
|
||||
MatListModule
|
||||
],
|
||||
providers: [{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
@ -181,12 +187,12 @@ export class AppModule {
|
||||
queryParams: {
|
||||
'state': null,
|
||||
'session_state': null,
|
||||
'code': null,
|
||||
'code': null
|
||||
},
|
||||
queryParamsHandling: 'merge'
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
<section class="dialog">
|
||||
<div [translate]="'assign-' + data.type + '-owner.dialog.title.label'"
|
||||
class="dialog-header heading-l">
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<mat-list class="list-50vh">
|
||||
<ng-container *ngFor="let user of userService.allUsers">
|
||||
<mat-list-item class="pointer" [class.owner]="isOwner(user)"
|
||||
(click)="assignOwner(user)"
|
||||
*ngIf="userService.isManager(user)">
|
||||
{{ userService.getNameForId(user.userId) }}
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
</mat-list>
|
||||
</div>
|
||||
|
||||
<button (click)="dialogRef.close()" class="dialog-close" mat-icon-button>
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</button>
|
||||
</section>
|
||||
@ -0,0 +1,5 @@
|
||||
@import "../../../assets/styles/red-variables";
|
||||
|
||||
.owner {
|
||||
background-color: rgba($primary, 0.1);
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Project, ProjectControllerService, User } from '@redaction/red-ui-http';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { NotificationService, NotificationType } from '../../notification/notification.service';
|
||||
|
||||
class DialogData {
|
||||
type: 'file' | 'project';
|
||||
projectId?: string;
|
||||
fileId?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-details-dialog',
|
||||
templateUrl: './assign-owner-dialog.component.html',
|
||||
styleUrls: ['./assign-owner-dialog.component.scss']
|
||||
})
|
||||
export class AssignOwnerDialogComponent {
|
||||
private project: Project;
|
||||
public memberIds: string[];
|
||||
|
||||
constructor(private readonly _projectControllerService: ProjectControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
public readonly userService: UserService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
public dialogRef: MatDialogRef<AssignOwnerDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: DialogData) {
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
public isOwner(user: User) {
|
||||
return this.data.type === 'project' ? this.project.ownerId === user.userId : false;
|
||||
}
|
||||
|
||||
public assignOwner(user: User) {
|
||||
if (this.data.type === 'project') {
|
||||
this._projectControllerService.assignProjectOwner(this.project.projectId, user.userId).subscribe(() => {
|
||||
this._notificationService.showToastNotification('Successfully assigned ' + this.userService.getNameForId(user.userId) + ' to project: ' + this.project.projectName);
|
||||
}, error => {
|
||||
this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR);
|
||||
}).add(() => this._reloadProject());
|
||||
} else if (this.data.type === 'file') {
|
||||
console.log('not implemented yet');
|
||||
}
|
||||
}
|
||||
|
||||
private _loadData() {
|
||||
if (this.data.type === 'project') {
|
||||
this.project = this._appStateService.getProjectById(this.data.projectId).project;
|
||||
}
|
||||
}
|
||||
|
||||
private _reloadProject() {
|
||||
this._appStateService.addOrUpdateProject(this.project).then(() => {
|
||||
this._loadData();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -69,7 +69,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<redaction-initials-avatar [username]="user.name"
|
||||
<redaction-initials-avatar [username]="_userService.getNameForId(pw.project.ownerId)"
|
||||
color="lightgray-red"
|
||||
withName="true"
|
||||
></redaction-initials-avatar>
|
||||
@ -81,18 +81,18 @@
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button mat-icon-button color="accent" (click)="deleteProject($event,pw.project)"
|
||||
<button mat-icon-button color="accent" (click)="openDeleteProjectDialog($event,pw.project)"
|
||||
[matTooltip]="'project-listing.delete.action.label'|translate">
|
||||
<mat-icon svgIcon="red:trash"></mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="accent" (click)="showDetailsDialog($event,pw)"
|
||||
<button mat-icon-button color="accent" (click)="openDetailsDialog($event,pw)"
|
||||
[matTooltip]="'project-listing.report.action.label'|translate">
|
||||
<mat-icon svgIcon="red:report"></mat-icon>
|
||||
</button>
|
||||
<!-- <button mat-icon-button (click)="editProject($event,pw.project)">-->
|
||||
<!-- <mat-icon svgIcon="red:edit"></mat-icon>-->
|
||||
<!-- </button>-->
|
||||
<button color="accent" (click)="assignProjectPeople($event,pw.project)" mat-icon-button
|
||||
<button color="accent" (click)="openAssignProjectOwnerDialog($event,pw.project)" mat-icon-button
|
||||
[matTooltip]="'project-listing.assign.action.label'|translate">
|
||||
<mat-icon svgIcon="red:assign"></mat-icon>
|
||||
</button>
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Project, ProjectControllerService} from '@redaction/red-ui-http';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {AddEditProjectDialogComponent} from './add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import {ConfirmationDialogComponent} from '../../common/confirmation-dialog/confirmation-dialog.component';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {NotificationService} from '../../notification/notification.service';
|
||||
import {AppStateService, ProjectWrapper} from '../../state/app-state.service';
|
||||
import {UserService} from '../../user/user.service';
|
||||
import {ProjectDetailsDialogComponent} from '../project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import {DoughnutChartConfig} from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import {SortingOption} from '../../utils/types';
|
||||
import {groupBy} from "../../utils/functions";
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Project, ProjectControllerService } from '@redaction/red-ui-http';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AddEditProjectDialogComponent } from './add-edit-project-dialog/add-edit-project-dialog.component';
|
||||
import { ConfirmationDialogComponent } from '../../common/confirmation-dialog/confirmation-dialog.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NotificationService } from '../../notification/notification.service';
|
||||
import { AppStateService, ProjectWrapper } from '../../state/app-state.service';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { ProjectDetailsDialogComponent } from '../project-overview-screen/project-details-dialog/project-details-dialog.component';
|
||||
import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import { SortingOption } from '../../utils/types';
|
||||
import { groupBy } from '../../utils/functions';
|
||||
import { AssignOwnerDialogComponent } from '../../components/project-members-dialog/assign-owner-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-listing-screen',
|
||||
@ -21,8 +22,8 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
public projectsChartData: DoughnutChartConfig [] = [];
|
||||
public documentsChartData: DoughnutChartConfig [] = [];
|
||||
public sortingOptions: SortingOption[] = [
|
||||
{label: 'project-listing.sorting.recent.label', order: 'desc', column: 'projectDate'},
|
||||
{label: 'project-listing.sorting.alphabetically.label', order: 'asc', column: 'project.projectName'}
|
||||
{ label: 'project-listing.sorting.recent.label', order: 'desc', column: 'projectDate' },
|
||||
{ label: 'project-listing.sorting.alphabetically.label', order: 'asc', column: 'project.projectName' }
|
||||
];
|
||||
public sortingOption: SortingOption = this.sortingOptions[0];
|
||||
|
||||
@ -35,25 +36,49 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
private readonly _dialog: MatDialog) {
|
||||
}
|
||||
|
||||
get user() {
|
||||
return this._userService.user;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.appStateService.reset();
|
||||
this.projectsChartData = [
|
||||
{value: this.activeProjects, color: 'ACTIVE', label: 'active'},
|
||||
{value: this.inactiveProjects, color: 'DELETED', label: 'archived'}
|
||||
{ value: this.activeProjects, color: 'ACTIVE', label: 'active' },
|
||||
{ value: this.inactiveProjects, color: 'DELETED', label: 'archived' }
|
||||
];
|
||||
const groups = groupBy(this.appStateService.aggregatedFiles, 'status');
|
||||
this.documentsChartData = [];
|
||||
for (const key of Object.keys(groups)) {
|
||||
this.documentsChartData.push({value: groups[key].length, color: key, label: key});
|
||||
this.documentsChartData.push({ value: groups[key].length, color: key, label: key });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
openAddProjectDialog(project?: Project): void {
|
||||
public get user() {
|
||||
return this._userService.user;
|
||||
}
|
||||
|
||||
public get totalPages() {
|
||||
return this.appStateService.totalAnalysedPages;
|
||||
}
|
||||
|
||||
public get totalPeople() {
|
||||
return this.appStateService.totalPeople;
|
||||
}
|
||||
|
||||
public get activeProjects() {
|
||||
return this.appStateService.allProjects.reduce((i, p) => i + (p.project.status === Project.StatusEnum.ACTIVE ? 1 : 0), 0);
|
||||
}
|
||||
|
||||
public get inactiveProjects() {
|
||||
return this.appStateService.allProjects.length - this.activeProjects;
|
||||
}
|
||||
|
||||
public documentCount(project: ProjectWrapper) {
|
||||
return project.files.length;
|
||||
}
|
||||
|
||||
public userCount(project: ProjectWrapper) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public openAddProjectDialog(project?: Project): void {
|
||||
this._dialog.open(AddEditProjectDialogComponent, {
|
||||
width: '400px',
|
||||
maxWidth: '90vw',
|
||||
@ -61,12 +86,7 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
editProject($event: MouseEvent, project: Project) {
|
||||
$event.stopPropagation();
|
||||
this.openAddProjectDialog(project);
|
||||
}
|
||||
|
||||
deleteProject($event: MouseEvent, project: Project) {
|
||||
public openDeleteProjectDialog($event: MouseEvent, project: Project) {
|
||||
$event.stopPropagation();
|
||||
const dialogRef = this._dialog.open(ConfirmationDialogComponent, {
|
||||
width: '400px',
|
||||
@ -80,7 +100,7 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
showDetailsDialog($event: MouseEvent, project: ProjectWrapper) {
|
||||
public openDetailsDialog($event: MouseEvent, project: ProjectWrapper) {
|
||||
$event.stopPropagation();
|
||||
this._dialog.open(ProjectDetailsDialogComponent, {
|
||||
width: '600px',
|
||||
@ -89,34 +109,12 @@ export class ProjectListingScreenComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
get totalPages() {
|
||||
return this.appStateService.totalAnalysedPages;
|
||||
}
|
||||
|
||||
get totalPeople(){
|
||||
return this.appStateService.totalPeople;
|
||||
}
|
||||
|
||||
documentCount(project: ProjectWrapper) {
|
||||
return project.files.length;
|
||||
}
|
||||
|
||||
userCount(project: ProjectWrapper) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
get activeProjects() {
|
||||
return this.appStateService.allProjects.reduce((i, p) => i + (p.project.status === Project.StatusEnum.ACTIVE ? 1 : 0), 0);
|
||||
}
|
||||
|
||||
get inactiveProjects() {
|
||||
return this.appStateService.allProjects.length - this.activeProjects;
|
||||
}
|
||||
|
||||
assignProjectPeople($event: MouseEvent, project: Project) {
|
||||
public openAssignProjectOwnerDialog($event: MouseEvent, project: Project) {
|
||||
$event.stopPropagation();
|
||||
this._projectControllerService.assignProjectOwner(project.projectId, this._userService.user.id).subscribe(() => {
|
||||
this._notificationService.showToastNotification("Successfully assigned " + this.user.name + " to project: " + project.projectName);
|
||||
})
|
||||
this._dialog.open(AssignOwnerDialogComponent, {
|
||||
width: '400px',
|
||||
maxWidth: '90vw',
|
||||
data: { type: 'project', projectId: project.projectId }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
<section class="dialog">
|
||||
<div [translate]="'project-members.dialog.title.label'"
|
||||
class="dialog-header heading-l">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<mat-selection-list class="list-50vh" color="primary"
|
||||
[(ngModel)]="memberIds"
|
||||
(selectionChange)="selectionChange($event)">
|
||||
<ng-container *ngFor="let user of userService.allUsers">
|
||||
<mat-list-option *ngIf="userService.isManager(user) || userService.isUser(user)" [value]="user.userId" checkboxPosition="before">
|
||||
{{ userService.getNameForId(user.userId) }}
|
||||
</mat-list-option>
|
||||
</ng-container>
|
||||
</mat-selection-list>
|
||||
</div>
|
||||
|
||||
<button (click)="dialogRef.close()" class="dialog-close" mat-icon-button>
|
||||
<mat-icon svgIcon="red:close"></mat-icon>
|
||||
</button>
|
||||
</section>
|
||||
@ -0,0 +1,56 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { Project, ProjectControllerService } from '@redaction/red-ui-http';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { AppStateService, ProjectWrapper } from '../../../state/app-state.service';
|
||||
import { UserService } from '../../../user/user.service';
|
||||
import { MatSelectionListChange } from '@angular/material/list';
|
||||
import { NotificationService, NotificationType } from '../../../notification/notification.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-project-details-dialog',
|
||||
templateUrl: './assign-project-members-dialog.component.html',
|
||||
styleUrls: ['./assign-project-members-dialog.component.scss']
|
||||
})
|
||||
export class AssignProjectMembersDialogComponent {
|
||||
private _project: Project;
|
||||
public memberIds: string[];
|
||||
|
||||
constructor(private readonly _projectControllerService: ProjectControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
public readonly userService: UserService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
public dialogRef: MatDialogRef<AssignProjectMembersDialogComponent>) {
|
||||
this._loadProject();
|
||||
}
|
||||
|
||||
private _loadProject() {
|
||||
this._project = this._appStateService.activeProject.project;
|
||||
this.memberIds = [...this._project.memberIds];
|
||||
}
|
||||
|
||||
private _reloadProject() {
|
||||
this._appStateService.addOrUpdateProject(this._project).then(() => {
|
||||
this._loadProject();
|
||||
});
|
||||
}
|
||||
|
||||
public selectionChange($event: MatSelectionListChange) {
|
||||
const userId = $event.option.value;
|
||||
const selected = $event.option.selected;
|
||||
const userName = this.userService.getNameForId(userId);
|
||||
|
||||
if (selected) {
|
||||
this._projectControllerService.addMembersToProject({ memberIds: [userId] }, this._project.projectId).subscribe(() => {
|
||||
this._notificationService.showToastNotification('Successfully assigned ' + userName + ' to project: ' + this._project.projectName);
|
||||
}, error => {
|
||||
this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR);
|
||||
}).add(() => this._reloadProject());
|
||||
} else {
|
||||
this._projectControllerService.deleteMembersToProject({ memberIds: [userId] }, this._project.projectId).subscribe(() => {
|
||||
this._notificationService.showToastNotification('Successfully removed ' + userName + ' from project: ' + this._project.projectName);
|
||||
}, error => {
|
||||
this._notificationService.showToastNotification('Failed: ' + error.error.message, null, NotificationType.ERROR);
|
||||
}).add(() => this._reloadProject());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
<div *ngIf="!appStateService.activeProject"
|
||||
[innerHTML]="'project-overview.no-project.label' | translate:{projectId: projectId}"
|
||||
[innerHTML]="'project-overview.no-project.label' | translate:{projectId: activeProject.projectId}"
|
||||
class="heading-l"></div>
|
||||
|
||||
<div *ngIf="appStateService.activeProject" class="page-header">
|
||||
@ -53,14 +53,14 @@
|
||||
<div class="flex-4 small-label min-width" translate="project-overview.table-col-names.added-on.label"></div>
|
||||
<div class="flex-2 small-label min-width" translate="project-overview.table-col-names.needs-work.label"></div>
|
||||
<div class="flex-2 small-label min-width" translate="project-overview.table-col-names.assigned-to.label"></div>
|
||||
<div class="flex-1 small-label status-container min-width"
|
||||
<div class="flex-1 small-label header-flex-end min-width"
|
||||
translate="project-overview.table-col-names.status.label"></div>
|
||||
</div>
|
||||
|
||||
<div class="table-item"
|
||||
[class.pointer]="canOpenFile(fileStatus.status)"
|
||||
*ngFor="let fileStatus of appStateService.activeProject.files | sortBy: sortingOption.order:sortingOption.column; trackBy:fileId"
|
||||
[routerLink]="canOpenFile(fileStatus.status) ? ['/ui/projects/'+projectId+'/file/'+fileStatus.fileId] : []">
|
||||
[routerLink]="canOpenFile(fileStatus.status) ? ['/ui/projects/'+activeProject.projectId+'/file/'+fileStatus.fileId] : []">
|
||||
<div class="flex-6 table-item-title min-width" [matTooltip]="'['+fileStatus.status+'] '+fileStatus.filename ">
|
||||
{{ fileStatus.filename }}
|
||||
</div>
|
||||
@ -77,7 +77,7 @@
|
||||
<div class="small-label flex-2 assigned-to min-width">
|
||||
<redaction-initials-avatar
|
||||
withName="true"
|
||||
[username]="getUsername(fileStatus)"
|
||||
[username]="getFileOwnerUsername(fileStatus)"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
@ -88,7 +88,7 @@
|
||||
</div>
|
||||
|
||||
<div class="action-buttons flex-3 min-width">
|
||||
<button (click)="deleteFile($event,fileStatus)" color="accent" mat-icon-button
|
||||
<button (click)="openDeleteFileDialog($event,fileStatus)" color="accent" mat-icon-button
|
||||
[matTooltip]="'project-overview.delete.action.label'|translate">
|
||||
<mat-icon svgIcon="red:trash"></mat-icon>
|
||||
</button>
|
||||
@ -110,13 +110,13 @@
|
||||
|
||||
<div class="project-details-container right-fixed-container">
|
||||
<div class="actions-row">
|
||||
<button mat-icon-button (click)="deleteProject($event)">
|
||||
<button mat-icon-button (click)="openDeleteProjectDialog($event)">
|
||||
<mat-icon svgIcon="red:trash"></mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="editProject($event)">
|
||||
<button mat-icon-button (click)="openEditProjectDialog($event)">
|
||||
<mat-icon svgIcon="red:edit"></mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="showDetailsDialog($event)">
|
||||
<button mat-icon-button (click)="openDetailsDialog($event)">
|
||||
<mat-icon svgIcon="red:report"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
@ -141,7 +141,7 @@
|
||||
</div>
|
||||
|
||||
<div class="owner flex-row mt-20">
|
||||
<redaction-initials-avatar [username]="user.name"
|
||||
<redaction-initials-avatar [username]="ownerName"
|
||||
size="large"
|
||||
color="lightgray-red"
|
||||
withName="true"
|
||||
@ -155,16 +155,17 @@
|
||||
<div class="project-team mt-20">
|
||||
<div class="all-caps-label" translate="project-overview.project-details.project-team.label"></div>
|
||||
<div class="flex mt-20 members-container">
|
||||
<div *ngFor="let username of getMembers()" class="member">
|
||||
<div *ngFor="let username of members" class="member">
|
||||
<redaction-initials-avatar [username]="username" size="large"></redaction-initials-avatar>
|
||||
</div>
|
||||
<!-- TODO THIS IS OVERFLOW-->
|
||||
<!-- <div class="member">-->
|
||||
<!-- <div class="oval large white-dark">+2</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="member">-->
|
||||
<!-- <div class="oval red-white large">+</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="member pointer" (click)="openAssignProjectMembersDialog()">
|
||||
<div class="oval red-white large">+</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -8,6 +8,11 @@
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.header-flex-end {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.table-item {
|
||||
.needs-work {
|
||||
display: flex;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import {
|
||||
FileStatus,
|
||||
@ -21,7 +21,8 @@ import { AddEditProjectDialogComponent } from '../project-listing-screen/add-edi
|
||||
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 { groupBy } from '../../utils/functions';
|
||||
import { AssignProjectMembersDialogComponent } from './project-members-dialog/assign-project-members-dialog.component';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -30,10 +31,7 @@ import {groupBy} from "../../utils/functions";
|
||||
styleUrls: ['./project-overview-screen.component.scss']
|
||||
})
|
||||
export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('dropzoneComponent', { static: true })
|
||||
dropZoneComponent;
|
||||
|
||||
dragActive = false;
|
||||
private _fileStatusInterval;
|
||||
|
||||
public sortingOptions: SortingOption[] = [
|
||||
{ label: 'project-overview.sorting.recent.label', order: 'desc', column: 'lastUpdated' },
|
||||
@ -42,12 +40,8 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
{ label: 'project-overview.sorting.number-of-analyses.label', order: 'desc', column: 'numberOfAnalyses' }
|
||||
];
|
||||
public sortingOption: SortingOption = this.sortingOptions[0];
|
||||
|
||||
public documentsChartData: DoughnutChartConfig[] = [];
|
||||
|
||||
projectId: string;
|
||||
private _fileStatusInterval;
|
||||
|
||||
constructor(public readonly appStateService: AppStateService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
@ -64,15 +58,10 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
private readonly _fileUploadControllerService: FileUploadControllerService,
|
||||
private readonly _projectControllerService: ProjectControllerService) {
|
||||
this._activatedRoute.params.subscribe(params => {
|
||||
this.projectId = params.projectId;
|
||||
this.appStateService.activateProject(this.projectId);
|
||||
this.appStateService.activateProject(params.projectId);
|
||||
});
|
||||
}
|
||||
|
||||
get user() {
|
||||
return this._userService.user;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._fileDropOverlayService.initFileDropHandling();
|
||||
this._calculateChartConfig();
|
||||
@ -81,7 +70,45 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
deleteFile($event: MouseEvent, fileStatus: FileStatus) {
|
||||
ngOnDestroy(): void {
|
||||
this._fileDropOverlayService.cleanupFileDropHandling();
|
||||
if (this._fileStatusInterval) {
|
||||
clearInterval(this._fileStatusInterval);
|
||||
this._fileStatusInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
public get activeProject() {
|
||||
return this.appStateService.activeProject.project;
|
||||
}
|
||||
|
||||
public get user() {
|
||||
return this._userService.user;
|
||||
}
|
||||
|
||||
public get members() {
|
||||
return this.activeProject.memberIds.map(m => this._userService.getName(this._userService.getUserById(m)));
|
||||
}
|
||||
|
||||
public get ownerName() {
|
||||
return this._userService.getNameForId(this.activeProject.ownerId);
|
||||
}
|
||||
|
||||
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 openDeleteFileDialog($event: MouseEvent, fileStatus: FileStatus) {
|
||||
$event.stopPropagation();
|
||||
const dialogRef = this._dialog.open(ConfirmationDialogComponent, {
|
||||
width: '400px',
|
||||
@ -100,7 +127,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
showDetailsDialog($event: MouseEvent) {
|
||||
public openDetailsDialog($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this._dialog.open(ProjectDetailsDialogComponent, {
|
||||
width: '600px',
|
||||
@ -109,57 +136,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this._fileDropOverlayService.cleanupFileDropHandling();
|
||||
if (this._fileStatusInterval) {
|
||||
this._fileStatusInterval = null;
|
||||
clearInterval(this._fileStatusInterval);
|
||||
}
|
||||
}
|
||||
|
||||
reanalyseFile($event: MouseEvent, fileStatus: FileStatus) {
|
||||
$event.stopPropagation();
|
||||
this._reanalysisControllerService.reanalyzeFile(this.appStateService.activeProject.project.projectId, fileStatus.fileId).subscribe(() => {
|
||||
this._getFileStatus();
|
||||
});
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
}
|
||||
|
||||
fileId(index, item) {
|
||||
return item.fileId;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
editProject($event: MouseEvent) {
|
||||
public openEditProjectDialog($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
this._dialog.open(AddEditProjectDialogComponent, {
|
||||
width: '400px',
|
||||
@ -168,7 +145,7 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
deleteProject($event: MouseEvent) {
|
||||
public openDeleteProjectDialog($event: MouseEvent) {
|
||||
$event.stopPropagation();
|
||||
const dialogRef = this._dialog.open(ConfirmationDialogComponent, {
|
||||
width: '400px',
|
||||
@ -184,24 +161,54 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
public openAssignProjectMembersDialog() {
|
||||
this._dialog.open(AssignProjectMembersDialogComponent, {
|
||||
width: '400px',
|
||||
maxWidth: '90vw',
|
||||
autoFocus: false
|
||||
});
|
||||
}
|
||||
|
||||
canOpenFile(fileStatus: FileStatus): boolean {
|
||||
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;
|
||||
}
|
||||
|
||||
assignPeopleToFile($event: MouseEvent, fileStatus: FileStatus) {
|
||||
public assignPeopleToFile($event: MouseEvent, fileStatus: FileStatus) {
|
||||
$event.stopPropagation();
|
||||
this._statusControllerService.assignProjectOwner1(this.appStateService.activeProjectId, fileStatus.fileId, this.user.id).subscribe(()=>{
|
||||
this._notificationService.showToastNotification("Successfully assigned " + this.user.name + " to file: " + fileStatus.filename);
|
||||
this._statusControllerService.assignProjectOwner1(this.appStateService.activeProjectId, fileStatus.fileId, this.user.id).subscribe(() => {
|
||||
this._notificationService.showToastNotification('Successfully assigned ' + this.user.name + ' to file: ' + fileStatus.filename);
|
||||
});
|
||||
}
|
||||
|
||||
getMembers(){
|
||||
return this.appStateService.activeProject.project.memberIds.map(m => this._userService.getName(this._userService.getUserById(m)))
|
||||
}
|
||||
|
||||
getUsername(fileStatus: FileStatus) {
|
||||
public getFileOwnerUsername(fileStatus: FileStatus) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,10 @@ export class AppStateService {
|
||||
return this._appState.totalDocuments;
|
||||
}
|
||||
|
||||
public getProjectById(id: string) {
|
||||
return this.allProjects.find(project => project.project.projectId === id);
|
||||
}
|
||||
|
||||
async loadAllProjects() {
|
||||
const projects = await this._projectControllerService.getProjects().toPromise();
|
||||
if (projects) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {KeycloakService} from "keycloak-angular";
|
||||
import {KeycloakProfile} from "keycloak-js";
|
||||
import jwt_decode from "jwt-decode";
|
||||
import {User, UserControllerService} from "@redaction/red-ui-http";
|
||||
import { Injectable } from '@angular/core';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { KeycloakProfile } from 'keycloak-js';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import { User, UserControllerService } from '@redaction/red-ui-http';
|
||||
|
||||
export class UserWrapper {
|
||||
|
||||
@ -10,21 +10,21 @@ export class UserWrapper {
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._currentUser.firstName + " " + this._currentUser.lastName;
|
||||
return this._currentUser.firstName + ' ' + this._currentUser.lastName;
|
||||
}
|
||||
|
||||
get isManager() {
|
||||
return this.roles.indexOf("RED_MANAGER") >= 0;
|
||||
return this.roles.indexOf('RED_MANAGER') >= 0;
|
||||
}
|
||||
|
||||
|
||||
get isUser() {
|
||||
return this.roles.indexOf("RED_USER") >= 0;
|
||||
return this.roles.indexOf('RED_USER') >= 0;
|
||||
}
|
||||
|
||||
|
||||
get isAdmin() {
|
||||
return this.roles.indexOf("RED_ADMIn") >= 0;
|
||||
return this.roles.indexOf('RED_ADMIN') >= 0;
|
||||
}
|
||||
|
||||
get hasAnyREDRoles() {
|
||||
@ -37,11 +37,11 @@ export class UserWrapper {
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService {
|
||||
|
||||
private _currentUser: UserWrapper;
|
||||
private _allUsers: User[];
|
||||
|
||||
constructor(private readonly _keycloakService: KeycloakService, private readonly _userControllerService: UserControllerService) {
|
||||
constructor(private readonly _keycloakService: KeycloakService,
|
||||
private readonly _userControllerService: UserControllerService) {
|
||||
}
|
||||
|
||||
logout() {
|
||||
@ -65,7 +65,6 @@ export class UserService {
|
||||
return allUsers;
|
||||
}
|
||||
|
||||
|
||||
async loadCurrentUser() {
|
||||
const token = await this._keycloakService.getToken();
|
||||
const decoded = jwt_decode(token);
|
||||
@ -77,15 +76,25 @@ export class UserService {
|
||||
return this._currentUser;
|
||||
}
|
||||
|
||||
|
||||
getUserById(id: string) {
|
||||
return this._allUsers.find(u => u.userId === id);
|
||||
}
|
||||
|
||||
getNameForId(userId: string) {
|
||||
return this.getName(this.getUserById(userId));
|
||||
}
|
||||
|
||||
getName(user?: User) {
|
||||
if (user) {
|
||||
return user.firstName + " " + user.lastName;
|
||||
}
|
||||
return undefined;
|
||||
return user ?
|
||||
(user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : user.username) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
isManager(user: User) {
|
||||
return user.roles.indexOf('RED_MANAGER') >= 0;
|
||||
}
|
||||
|
||||
isUser(user: User) {
|
||||
return user.roles.indexOf('RED_USER') >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
13
apps/red-ui/src/assets/styles/red-list.scss
Normal file
13
apps/red-ui/src/assets/styles/red-list.scss
Normal file
@ -0,0 +1,13 @@
|
||||
@import "red-variables";
|
||||
|
||||
.mat-list-item {
|
||||
font-family: Inter, sans-serif;
|
||||
color: $grey-1 !important;
|
||||
font-size: 13px !important;
|
||||
line-height: 16px !important;
|
||||
}
|
||||
|
||||
.list-50vh {
|
||||
overflow-y: scroll;
|
||||
max-height: 50vh;
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
@import "red-input";
|
||||
@import "red-button";
|
||||
@import "red-select";
|
||||
@import "red-list";
|
||||
@import "red-checkbox";
|
||||
@import "red-toggle";
|
||||
@import "red-menu";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user