Pull request #188: RED-1493
Merge in RED/ui from RED-1493 to master * commit 'aa31aef765c8678e7f3f0ca470433a1352b58731': fix en.json Merge branch 'master' into fix-conflicts Edit project team members Can edit project dictionary Edit project dictionary New edit project dialog WIP
This commit is contained in:
commit
35b60e0f11
@ -0,0 +1,17 @@
|
|||||||
|
<redaction-side-nav title="type">
|
||||||
|
<ng-container *ngFor="let item of items[type]">
|
||||||
|
<div
|
||||||
|
*ngIf="
|
||||||
|
(!item.onlyAdmin || permissionsService.isAdmin()) &&
|
||||||
|
(!item.onlyDevMode || userPreferenceService.areDevFeaturesEnabled) &&
|
||||||
|
(!item.userManagerOnly || permissionsService.canManageUsers())
|
||||||
|
"
|
||||||
|
[routerLinkActiveOptions]="{ exact: false }"
|
||||||
|
[routerLink]="prefix + item.screen"
|
||||||
|
class="item"
|
||||||
|
routerLinkActive="active"
|
||||||
|
>
|
||||||
|
{{ item.label || item.screen | translate }}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</redaction-side-nav>
|
||||||
@ -4,11 +4,11 @@ import { UserPreferenceService } from '@services/user-preference.service';
|
|||||||
import { AppStateService } from '@state/app-state.service';
|
import { AppStateService } from '@state/app-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-side-nav',
|
selector: 'redaction-admin-side-nav',
|
||||||
templateUrl: './side-nav.component.html',
|
templateUrl: './admin-side-nav.component.html',
|
||||||
styleUrls: ['./side-nav.component.scss']
|
styleUrls: ['./admin-side-nav.component.scss']
|
||||||
})
|
})
|
||||||
export class SideNavComponent {
|
export class AdminSideNavComponent {
|
||||||
@Input() type: 'settings' | 'project-templates';
|
@Input() type: 'settings' | 'project-templates';
|
||||||
|
|
||||||
items: {
|
items: {
|
||||||
@ -32,7 +32,7 @@ import { UsersStatsComponent } from './components/users-stats/users-stats.compon
|
|||||||
import { ConfirmDeleteUsersDialogComponent } from './dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component';
|
import { ConfirmDeleteUsersDialogComponent } from './dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component';
|
||||||
import { FileAttributesCsvImportDialogComponent } from './dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component';
|
import { FileAttributesCsvImportDialogComponent } from './dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component';
|
||||||
import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component';
|
import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component';
|
||||||
import { SideNavComponent } from './components/side-nav/side-nav.component';
|
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||||
|
|
||||||
const dialogs = [
|
const dialogs = [
|
||||||
AddEditRuleSetDialogComponent,
|
AddEditRuleSetDialogComponent,
|
||||||
@ -43,7 +43,8 @@ const dialogs = [
|
|||||||
SmtpAuthDialogComponent,
|
SmtpAuthDialogComponent,
|
||||||
AddEditUserDialogComponent,
|
AddEditUserDialogComponent,
|
||||||
ConfirmDeleteUsersDialogComponent,
|
ConfirmDeleteUsersDialogComponent,
|
||||||
FileAttributesCsvImportDialogComponent
|
FileAttributesCsvImportDialogComponent,
|
||||||
|
AdminSideNavComponent
|
||||||
];
|
];
|
||||||
|
|
||||||
const screens = [
|
const screens = [
|
||||||
@ -68,7 +69,6 @@ const components = [
|
|||||||
ComboSeriesVerticalComponent,
|
ComboSeriesVerticalComponent,
|
||||||
UsersStatsComponent,
|
UsersStatsComponent,
|
||||||
ActiveFieldsListingComponent,
|
ActiveFieldsListingComponent,
|
||||||
SideNavComponent,
|
|
||||||
|
|
||||||
...dialogs,
|
...dialogs,
|
||||||
...screens
|
...screens
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
<div [translate]="type" class="all-caps-label"></div>
|
|
||||||
|
|
||||||
<ng-container *ngFor="let item of items[type]">
|
|
||||||
<div
|
|
||||||
*ngIf="
|
|
||||||
(!item.onlyAdmin || permissionsService.isAdmin()) &&
|
|
||||||
(!item.onlyDevMode || userPreferenceService.areDevFeaturesEnabled) &&
|
|
||||||
(!item.userManagerOnly || permissionsService.canManageUsers())
|
|
||||||
"
|
|
||||||
[routerLinkActiveOptions]="{ exact: false }"
|
|
||||||
[routerLink]="prefix + item.screen"
|
|
||||||
class="item"
|
|
||||||
routerLinkActive="active"
|
|
||||||
>
|
|
||||||
{{ item.label || item.screen | translate }}
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
@ -88,7 +88,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
||||||
<div class="space-between">
|
<div class="d-flex">
|
||||||
<redaction-select
|
<redaction-select
|
||||||
[label]="
|
[label]="
|
||||||
'report-type.label'
|
'report-type.label'
|
||||||
@ -97,7 +97,7 @@
|
|||||||
"
|
"
|
||||||
[options]="reportTypesEnum"
|
[options]="reportTypesEnum"
|
||||||
[translatePrefix]="'report-type.'"
|
[translatePrefix]="'report-type.'"
|
||||||
class="w-410"
|
class="mr-16"
|
||||||
formControlName="reportTypes"
|
formControlName="reportTypes"
|
||||||
></redaction-select>
|
></redaction-select>
|
||||||
<redaction-select
|
<redaction-select
|
||||||
@ -111,7 +111,6 @@
|
|||||||
"
|
"
|
||||||
[options]="downloadTypesEnum"
|
[options]="downloadTypesEnum"
|
||||||
[translatePrefix]="'download-type.'"
|
[translatePrefix]="'download-type.'"
|
||||||
class="w-410"
|
|
||||||
formControlName="downloadFileTypes"
|
formControlName="downloadFileTypes"
|
||||||
></redaction-select>
|
></redaction-select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -22,8 +22,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-410 {
|
redaction-select {
|
||||||
width: 410px;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-includes {
|
.download-includes {
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
text="file-attributes-csv-import.table-header.actions.type"
|
text="file-attributes-csv-import.table-header.actions.type"
|
||||||
></redaction-chevron-button>
|
></redaction-chevron-button>
|
||||||
|
|
||||||
<mat-menu #readOnlyMenu="matMenu" class="no-padding-bottom">
|
<mat-menu #readOnlyMenu="matMenu" class="padding-bottom-8">
|
||||||
<button
|
<button
|
||||||
(click)="setAttributeForSelection('readonly', true)"
|
(click)="setAttributeForSelection('readonly', true)"
|
||||||
mat-menu-item
|
mat-menu-item
|
||||||
@ -50,7 +50,7 @@
|
|||||||
></button>
|
></button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<mat-menu #typeMenu="matMenu" class="no-padding-bottom">
|
<mat-menu #typeMenu="matMenu" class="padding-bottom-8">
|
||||||
<button
|
<button
|
||||||
(click)="setAttributeForSelection('type', type)"
|
(click)="setAttributeForSelection('type', type)"
|
||||||
*ngFor="let type of typeOptions"
|
*ngFor="let type of typeOptions"
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="red-content-inner">
|
<div class="red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="header-item">
|
<div class="header-item">
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="red-content-inner">
|
<div class="red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="header-item">
|
<div class="header-item">
|
||||||
|
|||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="flex red-content-inner">
|
<div class="flex red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<redaction-dictionary-manager
|
<redaction-dictionary-manager
|
||||||
[initialDictionaryEntries]="entries"
|
[initialDictionaryEntries]="entries"
|
||||||
|
|||||||
@ -28,3 +28,7 @@
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redaction-dictionary-manager {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<div class="red-content-inner">
|
<div class="red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="header-item">
|
<div class="header-item">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div *ngIf="viewReady">
|
<div *ngIf="viewReady">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<div class="red-content-inner">
|
<div class="red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
<ace-editor
|
<ace-editor
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<section class="settings">
|
<section class="settings">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="settings"></redaction-side-nav>
|
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
<div class="red-content-inner">
|
<div class="red-content-inner">
|
||||||
<div class="overlay-shadow"></div>
|
<div class="overlay-shadow"></div>
|
||||||
|
|
||||||
<redaction-side-nav type="project-templates"></redaction-side-nav>
|
<redaction-admin-side-nav type="project-templates"></redaction-admin-side-nav>
|
||||||
|
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div #viewer class="viewer"></div>
|
<div #viewer class="viewer"></div>
|
||||||
|
|||||||
@ -18,15 +18,6 @@
|
|||||||
>
|
>
|
||||||
</redaction-circle-button>
|
</redaction-circle-button>
|
||||||
|
|
||||||
<redaction-circle-button
|
|
||||||
(action)="openAssignProjectOwnerDialog($event, project)"
|
|
||||||
*ngIf="permissionsService.isManager()"
|
|
||||||
icon="red:assign"
|
|
||||||
tooltip="project-listing.assign.action"
|
|
||||||
type="dark-bg"
|
|
||||||
>
|
|
||||||
</redaction-circle-button>
|
|
||||||
|
|
||||||
<redaction-circle-button
|
<redaction-circle-button
|
||||||
(action)="reanalyseProject($event, project)"
|
(action)="reanalyseProject($event, project)"
|
||||||
*ngIf="permissionsService.displayReanalyseBtn(project)"
|
*ngIf="permissionsService.displayReanalyseBtn(project)"
|
||||||
|
|||||||
@ -25,16 +25,6 @@ export class ProjectListingActionsComponent {
|
|||||||
private readonly _fileManagementControllerService: FileManagementControllerService
|
private readonly _fileManagementControllerService: FileManagementControllerService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
openAssignProjectOwnerDialog($event: MouseEvent, project: ProjectWrapper) {
|
|
||||||
this._dialogService.openAssignProjectMembersAndOwnerDialog(
|
|
||||||
$event,
|
|
||||||
project,
|
|
||||||
(pw: ProjectWrapper) => {
|
|
||||||
this.actionPerformed.emit(pw);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
openDeleteProjectDialog($event: MouseEvent, project: ProjectWrapper) {
|
openDeleteProjectDialog($event: MouseEvent, project: ProjectWrapper) {
|
||||||
this._dialogService.openDeleteProjectDialog($event, project, () => {
|
this._dialogService.openDeleteProjectDialog($event, project, () => {
|
||||||
this.actionPerformed.emit();
|
this.actionPerformed.emit();
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
<form (submit)="saveMembers()" [formGroup]="teamForm">
|
||||||
|
<div class="red-input-group w-300">
|
||||||
|
<mat-form-field floatLabel="always">
|
||||||
|
<mat-label>{{ 'assign-project-owner.dialog.single-user' | translate }}</mat-label>
|
||||||
|
<mat-select formControlName="owner">
|
||||||
|
<mat-option *ngFor="let userId of ownersSelectOptions" [value]="userId">
|
||||||
|
{{ userService.getNameForId(userId) }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div [translate]="'assign-project-owner.dialog.approvers'" class="all-caps-label mt-16"></div>
|
||||||
|
<redaction-team-members
|
||||||
|
(remove)="toggleSelected($event)"
|
||||||
|
[canAdd]="false"
|
||||||
|
[canRemove]="true"
|
||||||
|
[largeSpacing]="true"
|
||||||
|
[memberIds]="selectedApproversList"
|
||||||
|
[perLine]="13"
|
||||||
|
[unremovableMembers]="[selectedOwnerId]"
|
||||||
|
></redaction-team-members>
|
||||||
|
|
||||||
|
<pre
|
||||||
|
*ngIf="selectedApproversList.length === 0"
|
||||||
|
[innerHTML]="'assign-project-owner.dialog.no-approvers' | translate"
|
||||||
|
class="info"
|
||||||
|
></pre>
|
||||||
|
|
||||||
|
<div [translate]="'assign-project-owner.dialog.reviewers'" class="all-caps-label mt-16"></div>
|
||||||
|
<redaction-team-members
|
||||||
|
(remove)="toggleSelected($event)"
|
||||||
|
[canAdd]="false"
|
||||||
|
[canRemove]="true"
|
||||||
|
[largeSpacing]="true"
|
||||||
|
[memberIds]="selectedReviewersList"
|
||||||
|
[perLine]="13"
|
||||||
|
[unremovableMembers]="[selectedOwnerId]"
|
||||||
|
></redaction-team-members>
|
||||||
|
|
||||||
|
<pre
|
||||||
|
*ngIf="selectedReviewersList.length === 0"
|
||||||
|
[innerHTML]="'assign-project-owner.dialog.no-reviewers' | translate"
|
||||||
|
class="info"
|
||||||
|
></pre>
|
||||||
|
|
||||||
|
<redaction-search-input
|
||||||
|
[form]="searchForm"
|
||||||
|
[placeholder]="'assign-project-owner.dialog.search' | translate"
|
||||||
|
[width]="560"
|
||||||
|
class="search-container"
|
||||||
|
></redaction-search-input>
|
||||||
|
|
||||||
|
<div class="members-list">
|
||||||
|
<div
|
||||||
|
(click)="!isOwner(userId) && toggleSelected(userId)"
|
||||||
|
*ngFor="let userId of membersSelectOptions"
|
||||||
|
[class.selected]="isMemberSelected(userId)"
|
||||||
|
>
|
||||||
|
<redaction-initials-avatar
|
||||||
|
[userId]="userId"
|
||||||
|
[withName]="true"
|
||||||
|
size="large"
|
||||||
|
></redaction-initials-avatar>
|
||||||
|
<div class="actions">
|
||||||
|
<div
|
||||||
|
(click)="toggleApprover(userId, $event)"
|
||||||
|
*ngIf="!isOwner(userId)"
|
||||||
|
class="make-approver"
|
||||||
|
>
|
||||||
|
<redaction-round-checkbox
|
||||||
|
[active]="isApprover(userId)"
|
||||||
|
class="mr-8"
|
||||||
|
></redaction-round-checkbox>
|
||||||
|
<span [translate]="'assign-project-owner.dialog.make-approver'"></span>
|
||||||
|
</div>
|
||||||
|
<mat-icon *ngIf="!isOwner(userId)" svgIcon="red:check"></mat-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@ -1,9 +1,5 @@
|
|||||||
@import '../../../../../assets/styles/red-mixins';
|
@import '../../../../../assets/styles/red-mixins';
|
||||||
|
|
||||||
.no-padding-bottom {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
.search-container {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
@ -14,8 +10,6 @@ redaction-team-members {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.members-list {
|
.members-list {
|
||||||
max-height: 220px;
|
|
||||||
height: 220px;
|
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
width: 587px;
|
width: 587px;
|
||||||
@ -58,6 +52,7 @@ redaction-team-members {
|
|||||||
&.selected,
|
&.selected,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $grey-2;
|
background-color: $grey-2;
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -1,62 +1,54 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
import { ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http';
|
import { Project, ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
||||||
import { AppStateService } from '@state/app-state.service';
|
import { AppStateService } from '@state/app-state.service';
|
||||||
import { UserService } from '@services/user.service';
|
import { UserService } from '@services/user.service';
|
||||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { FileStatusWrapper } from '@models/file/file-status.wrapper';
|
|
||||||
import { ProjectWrapper } from '@state/model/project.wrapper';
|
import { ProjectWrapper } from '@state/model/project.wrapper';
|
||||||
|
|
||||||
class DialogData {
|
|
||||||
project?: ProjectWrapper;
|
|
||||||
files?: FileStatusWrapper[];
|
|
||||||
ignoreChanged?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-project-details-dialog',
|
selector: 'redaction-team-members-manager',
|
||||||
templateUrl: './assign-owner-dialog.component.html',
|
templateUrl: './team-members-manager.component.html',
|
||||||
styleUrls: ['./assign-owner-dialog.component.scss']
|
styleUrls: ['./team-members-manager.component.scss']
|
||||||
})
|
})
|
||||||
export class AssignOwnerDialogComponent {
|
export class TeamMembersManagerComponent implements OnInit {
|
||||||
usersForm: FormGroup;
|
teamForm: FormGroup;
|
||||||
searchForm: FormGroup;
|
searchForm: FormGroup;
|
||||||
|
|
||||||
|
@Input() projectWrapper: ProjectWrapper;
|
||||||
|
|
||||||
|
@Output() save = new EventEmitter<Project>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly userService: UserService,
|
readonly userService: UserService,
|
||||||
private readonly _projectControllerService: ProjectControllerService,
|
private readonly _projectControllerService: ProjectControllerService,
|
||||||
private readonly _notificationService: NotificationService,
|
private readonly _notificationService: NotificationService,
|
||||||
private readonly _formBuilder: FormBuilder,
|
private readonly _formBuilder: FormBuilder,
|
||||||
private readonly _statusControllerService: StatusControllerService,
|
private readonly _statusControllerService: StatusControllerService,
|
||||||
private readonly _appStateService: AppStateService,
|
private readonly _appStateService: AppStateService
|
||||||
public dialogRef: MatDialogRef<AssignOwnerDialogComponent>,
|
) {}
|
||||||
@Inject(MAT_DIALOG_DATA) public data: DialogData
|
|
||||||
) {
|
|
||||||
this._loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
get selectedSingleUser(): string {
|
get selectedOwnerId(): string {
|
||||||
return this.usersForm.get('singleUser').value;
|
return this.teamForm.get('owner').value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedApproversList(): string[] {
|
get selectedApproversList(): string[] {
|
||||||
return this.usersForm.get('approvers').value;
|
return this.teamForm.get('approvers').value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedReviewersList(): string[] {
|
get selectedReviewersList(): string[] {
|
||||||
return this.selectedUsersList.filter((m) => this.selectedApproversList.indexOf(m) === -1);
|
return this.selectedMembersList.filter((m) => this.selectedApproversList.indexOf(m) === -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedUsersList(): string[] {
|
get selectedMembersList(): string[] {
|
||||||
return this.usersForm.get('members').value;
|
return this.teamForm.get('members').value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get singleUsersSelectOptions() {
|
get ownersSelectOptions() {
|
||||||
return this.userService.managerUsers.map((m) => m.userId);
|
return this.userService.managerUsers.map((m) => m.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get multiUsersSelectOptions() {
|
get membersSelectOptions() {
|
||||||
const searchQuery = this.searchForm.get('query').value;
|
const searchQuery = this.searchForm.get('query').value;
|
||||||
return this.userService.eligibleUsers
|
return this.userService.eligibleUsers
|
||||||
.filter((user) =>
|
.filter((user) =>
|
||||||
@ -65,50 +57,47 @@ export class AssignOwnerDialogComponent {
|
|||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(searchQuery.toLowerCase())
|
.includes(searchQuery.toLowerCase())
|
||||||
)
|
)
|
||||||
.filter((user) => this.selectedSingleUser !== user.userId)
|
.filter((user) => this.selectedOwnerId !== user.userId)
|
||||||
.map((user) => user.userId);
|
.map((user) => user.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get valid(): boolean {
|
||||||
|
return this.teamForm.valid;
|
||||||
|
}
|
||||||
|
|
||||||
get changed(): boolean {
|
get changed(): boolean {
|
||||||
if (this.data.ignoreChanged) {
|
if (this.projectWrapper.ownerId !== this.selectedOwnerId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.data.project.ownerId !== this.selectedSingleUser) {
|
const initialMembers = this.projectWrapper.memberIds.sort();
|
||||||
return true;
|
const currentMembers = this.selectedMembersList.sort();
|
||||||
}
|
|
||||||
|
|
||||||
const initialMembers = this.data.project.memberIds.sort();
|
const initialApprovers = this.projectWrapper.approverIds.sort();
|
||||||
const currentMembers = this.selectedUsersList.sort();
|
|
||||||
|
|
||||||
const initialApprovers = this.data.project.approverIds.sort();
|
|
||||||
const currentApprovers = this.selectedApproversList.sort();
|
const currentApprovers = this.selectedApproversList.sort();
|
||||||
|
|
||||||
if (
|
return (
|
||||||
this._compareLists(initialMembers, currentMembers) ||
|
this._compareLists(initialMembers, currentMembers) ||
|
||||||
this._compareLists(initialApprovers, currentApprovers)
|
this._compareLists(initialApprovers, currentApprovers)
|
||||||
) {
|
);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwner(userId: string): boolean {
|
isOwner(userId: string): boolean {
|
||||||
return userId === this.selectedSingleUser;
|
return userId === this.selectedOwnerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveUsers() {
|
async saveMembers() {
|
||||||
let result;
|
let result;
|
||||||
try {
|
try {
|
||||||
const ownerId = this.selectedSingleUser;
|
const ownerId = this.selectedOwnerId;
|
||||||
const memberIds = this.selectedUsersList;
|
const memberIds = this.selectedMembersList;
|
||||||
const approverIds = this.selectedApproversList;
|
const approverIds = this.selectedApproversList;
|
||||||
const pw = Object.assign({}, this.data.project);
|
const pw = Object.assign({}, this.projectWrapper);
|
||||||
pw.project.memberIds = memberIds;
|
pw.project.memberIds = memberIds;
|
||||||
pw.project.approverIds = approverIds;
|
pw.project.approverIds = approverIds;
|
||||||
pw.project.ownerId = ownerId;
|
pw.project.ownerId = ownerId;
|
||||||
result = await this._appStateService.addOrUpdateProject(pw.project);
|
result = await this._appStateService.addOrUpdateProject(pw.project);
|
||||||
|
this.save.emit(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._notificationService.showToastNotification(
|
this._notificationService.showToastNotification(
|
||||||
'Failed: ' + error.error ? error.error.message : error,
|
'Failed: ' + error.error ? error.error.message : error,
|
||||||
@ -116,12 +105,10 @@ export class AssignOwnerDialogComponent {
|
|||||||
NotificationType.ERROR
|
NotificationType.ERROR
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dialogRef.close(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isMemberSelected(userId: string): boolean {
|
isMemberSelected(userId: string): boolean {
|
||||||
return this.selectedUsersList.indexOf(userId) !== -1;
|
return this.selectedMembersList.indexOf(userId) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
isApprover(userId: string): boolean {
|
isApprover(userId: string): boolean {
|
||||||
@ -147,29 +134,36 @@ export class AssignOwnerDialogComponent {
|
|||||||
|
|
||||||
toggleSelected(userId: string) {
|
toggleSelected(userId: string) {
|
||||||
if (this.isMemberSelected(userId)) {
|
if (this.isMemberSelected(userId)) {
|
||||||
this.selectedUsersList.splice(this.selectedUsersList.indexOf(userId), 1);
|
this.selectedMembersList.splice(this.selectedMembersList.indexOf(userId), 1);
|
||||||
|
|
||||||
if (this.isApprover(userId)) {
|
if (this.isApprover(userId)) {
|
||||||
this.selectedApproversList.splice(this.selectedApproversList.indexOf(userId), 1);
|
this.selectedApproversList.splice(this.selectedApproversList.indexOf(userId), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.selectedUsersList.push(userId);
|
this.selectedMembersList.push(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this._loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
revert() {
|
||||||
|
this._loadData();
|
||||||
|
}
|
||||||
|
|
||||||
private _loadData() {
|
private _loadData() {
|
||||||
const project = this.data.project;
|
this.teamForm = this._formBuilder.group({
|
||||||
this.usersForm = this._formBuilder.group({
|
owner: [this.projectWrapper?.ownerId, Validators.required],
|
||||||
singleUser: [project?.ownerId, Validators.required],
|
approvers: [[...this.projectWrapper?.approverIds]],
|
||||||
approvers: [[...project?.approverIds]],
|
members: [[...this.projectWrapper?.memberIds]]
|
||||||
members: [[...project?.memberIds]]
|
|
||||||
});
|
});
|
||||||
this.searchForm = this._formBuilder.group({
|
this.searchForm = this._formBuilder.group({
|
||||||
query: ['']
|
query: ['']
|
||||||
});
|
});
|
||||||
this.usersForm.get('singleUser').valueChanges.subscribe((singleUser) => {
|
this.teamForm.get('owner').valueChanges.subscribe((owner) => {
|
||||||
if (!this.isApprover(singleUser)) {
|
if (!this.isApprover(owner)) {
|
||||||
this.toggleApprover(singleUser);
|
this.toggleApprover(owner);
|
||||||
}
|
}
|
||||||
// If it is an approver, it is already a member, no need to check
|
// If it is an approver, it is already a member, no need to check
|
||||||
});
|
});
|
||||||
@ -1,21 +1,12 @@
|
|||||||
<section class="dialog">
|
<section class="dialog">
|
||||||
<form (submit)="saveProject()" [formGroup]="projectForm">
|
<form (submit)="saveProject()" [formGroup]="projectForm">
|
||||||
<div
|
<div class="dialog-header heading-l" translate="add-project-dialog.header-new"></div>
|
||||||
[translate]="
|
|
||||||
project?.projectId
|
|
||||||
? 'project-listing.add-edit-dialog.header-edit'
|
|
||||||
: 'project-listing.add-edit-dialog.header-new'
|
|
||||||
"
|
|
||||||
class="dialog-header heading-l"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<div class="red-input-group required w-300">
|
<div class="red-input-group required w-300">
|
||||||
<label translate="project-listing.add-edit-dialog.form.name.label"></label>
|
<label translate="add-project-dialog.form.name.label"></label>
|
||||||
<input
|
<input
|
||||||
[placeholder]="
|
[placeholder]="'add-project-dialog.form.name.placeholder' | translate"
|
||||||
'project-listing.add-edit-dialog.form.name.placeholder' | translate
|
|
||||||
"
|
|
||||||
formControlName="projectName"
|
formControlName="projectName"
|
||||||
name="projectName"
|
name="projectName"
|
||||||
type="text"
|
type="text"
|
||||||
@ -24,9 +15,7 @@
|
|||||||
|
|
||||||
<div class="red-input-group required w-400">
|
<div class="red-input-group required w-400">
|
||||||
<mat-form-field floatLabel="always">
|
<mat-form-field floatLabel="always">
|
||||||
<mat-label>{{
|
<mat-label>{{ 'add-project-dialog.form.template' | translate }}</mat-label>
|
||||||
'project-listing.add-edit-dialog.form.template' | translate
|
|
||||||
}}</mat-label>
|
|
||||||
<mat-select
|
<mat-select
|
||||||
(valueChange)="ruleSetChanged($event)"
|
(valueChange)="ruleSetChanged($event)"
|
||||||
formControlName="ruleSetId"
|
formControlName="ruleSetId"
|
||||||
@ -45,11 +34,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="red-input-group w-400">
|
<div class="red-input-group w-400">
|
||||||
<label translate="project-listing.add-edit-dialog.form.description.label"></label>
|
<label translate="add-project-dialog.form.description.label"></label>
|
||||||
<textarea
|
<textarea
|
||||||
[placeholder]="
|
[placeholder]="'add-project-dialog.form.description.placeholder' | translate"
|
||||||
'project-listing.add-edit-dialog.form.description.placeholder' | translate
|
|
||||||
"
|
|
||||||
formControlName="description"
|
formControlName="description"
|
||||||
name="description"
|
name="description"
|
||||||
redactionHasScrollbar
|
redactionHasScrollbar
|
||||||
@ -65,7 +52,7 @@
|
|||||||
class="filter-menu-checkbox"
|
class="filter-menu-checkbox"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
{{ 'project-listing.add-edit-dialog.form.due-date' | translate }}
|
{{ 'add-project-dialog.form.due-date' | translate }}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
|
|
||||||
<div *ngIf="hasDueDate" class="red-input-group datepicker-wrapper">
|
<div *ngIf="hasDueDate" class="red-input-group datepicker-wrapper">
|
||||||
@ -82,35 +69,33 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
||||||
<div class="space-between">
|
<div class="d-flex">
|
||||||
<redaction-select
|
<redaction-select
|
||||||
[label]="'report-type.label' | translate: { length: reportTypesLength }"
|
[label]="'report-type.label' | translate: { length: reportTypesLength }"
|
||||||
[options]="reportTypesEnum"
|
[options]="reportTypesEnum"
|
||||||
[translatePrefix]="'report-type.'"
|
[translatePrefix]="'report-type.'"
|
||||||
class="w-410"
|
class="mr-16"
|
||||||
formControlName="reportTypes"
|
formControlName="reportTypes"
|
||||||
></redaction-select>
|
></redaction-select>
|
||||||
<redaction-select
|
<redaction-select
|
||||||
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
||||||
[options]="downloadTypesEnum"
|
[options]="downloadTypesEnum"
|
||||||
[translatePrefix]="'download-type.'"
|
[translatePrefix]="'download-type.'"
|
||||||
class="w-410"
|
|
||||||
formControlName="downloadFileTypes"
|
formControlName="downloadFileTypes"
|
||||||
></redaction-select>
|
></redaction-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
<button [disabled]="disabled || !changed" color="primary" mat-flat-button type="submit">
|
<button [disabled]="disabled" color="primary" mat-flat-button type="submit">
|
||||||
{{ 'project-listing.add-edit-dialog.actions.save' | translate }}
|
{{ 'add-project-dialog.actions.save' | translate }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<redaction-icon-button
|
<redaction-icon-button
|
||||||
(action)="saveProjectAndAddMembers()"
|
(action)="saveProjectAndAddMembers()"
|
||||||
*ngIf="!project?.projectId"
|
[disabled]="disabled"
|
||||||
[disabled]="disabled || !changed"
|
|
||||||
icon="red:assign"
|
icon="red:assign"
|
||||||
text="project-listing.add-edit-dialog.actions.save-and-add-members"
|
text="add-project-dialog.actions.save-and-add-members"
|
||||||
type="show-bg"
|
type="show-bg"
|
||||||
></redaction-icon-button>
|
></redaction-icon-button>
|
||||||
</div>
|
</div>
|
||||||
@ -13,11 +13,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-410 {
|
|
||||||
width: 410px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.download-includes {
|
.download-includes {
|
||||||
margin: 16px 0 10px;
|
margin: 16px 0 10px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redaction-select {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
@ -1,19 +1,18 @@
|
|||||||
import { Component, Inject } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
import { Project, RuleSetModel } from '@redaction/red-ui-http';
|
import { Project, RuleSetModel } from '@redaction/red-ui-http';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { AppStateService } from '@state/app-state.service';
|
import { AppStateService } from '@state/app-state.service';
|
||||||
import { ProjectWrapper } from '@state/model/project.wrapper';
|
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-add-edit-project-dialog',
|
selector: 'redaction-add-project-dialog',
|
||||||
templateUrl: './add-edit-project-dialog.component.html',
|
templateUrl: './add-project-dialog.component.html',
|
||||||
styleUrls: ['./add-edit-project-dialog.component.scss']
|
styleUrls: ['./add-project-dialog.component.scss']
|
||||||
})
|
})
|
||||||
export class AddEditProjectDialogComponent {
|
export class AddProjectDialogComponent {
|
||||||
projectForm: FormGroup;
|
projectForm: FormGroup;
|
||||||
hasDueDate: boolean;
|
hasDueDate = false;
|
||||||
downloadTypesEnum = ['ORIGINAL', 'PREVIEW', 'REDACTED'];
|
downloadTypesEnum = ['ORIGINAL', 'PREVIEW', 'REDACTED'];
|
||||||
reportTypesEnum = Object.values(RuleSetModel.ReportTypesEnum);
|
reportTypesEnum = Object.values(RuleSetModel.ReportTypesEnum);
|
||||||
ruleSets: RuleSetModel[];
|
ruleSets: RuleSetModel[];
|
||||||
@ -21,22 +20,17 @@ export class AddEditProjectDialogComponent {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly _appStateService: AppStateService,
|
private readonly _appStateService: AppStateService,
|
||||||
private readonly _formBuilder: FormBuilder,
|
private readonly _formBuilder: FormBuilder,
|
||||||
public dialogRef: MatDialogRef<AddEditProjectDialogComponent>,
|
public dialogRef: MatDialogRef<AddProjectDialogComponent>
|
||||||
@Inject(MAT_DIALOG_DATA) public project: ProjectWrapper
|
|
||||||
) {
|
) {
|
||||||
this._filterInvalidRuleSets();
|
this._filterInvalidRuleSets();
|
||||||
this.projectForm = this._formBuilder.group({
|
this.projectForm = this._formBuilder.group({
|
||||||
projectName: [this.project?.projectName, Validators.required],
|
projectName: [null, Validators.required],
|
||||||
ruleSetId: [
|
ruleSetId: [null, Validators.required],
|
||||||
{ value: this.project?.ruleSetId, disabled: this.project?.hasFiles },
|
downloadFileTypes: [null],
|
||||||
Validators.required
|
reportTypes: [null, Validators.required],
|
||||||
],
|
description: [null],
|
||||||
downloadFileTypes: [this.project?.project?.downloadFileTypes],
|
dueDate: [null]
|
||||||
reportTypes: [this.project?.project?.reportTypes, Validators.required],
|
|
||||||
description: [this.project?.description],
|
|
||||||
dueDate: [this.project?.dueDate]
|
|
||||||
});
|
});
|
||||||
this.hasDueDate = !!this.project?.dueDate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get reportTypesLength() {
|
get reportTypesLength() {
|
||||||
@ -51,34 +45,6 @@ export class AddEditProjectDialogComponent {
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get changed() {
|
|
||||||
if (!this.project) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key of Object.keys(this.projectForm.getRawValue())) {
|
|
||||||
if (key === 'dueDate') {
|
|
||||||
if (this.hasDueDate !== !!this.project.dueDate) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
this.hasDueDate &&
|
|
||||||
!moment(this.project.dueDate).isSame(moment(this.projectForm.get(key).value))
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (key === 'downloadFileTypes' || key === 'reportTypes') {
|
|
||||||
if (this.project.project[key] !== this.projectForm.get(key).value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (this.project[key] !== this.projectForm.get(key).value) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
get disabled() {
|
get disabled() {
|
||||||
if (this.hasDueDate && this.projectForm.get('dueDate').value === null) {
|
if (this.hasDueDate && this.projectForm.get('dueDate').value === null) {
|
||||||
return true;
|
return true;
|
||||||
@ -89,7 +55,6 @@ export class AddEditProjectDialogComponent {
|
|||||||
|
|
||||||
async saveProject() {
|
async saveProject() {
|
||||||
const project: Project = this._formToObject();
|
const project: Project = this._formToObject();
|
||||||
project.projectId = this.project?.projectId;
|
|
||||||
|
|
||||||
const foundProject = this._appStateService.allProjects.find(
|
const foundProject = this._appStateService.allProjects.find(
|
||||||
(p) => p.project.projectId === project.projectId
|
(p) => p.project.projectId === project.projectId
|
||||||
@ -106,7 +71,6 @@ export class AddEditProjectDialogComponent {
|
|||||||
|
|
||||||
async saveProjectAndAddMembers() {
|
async saveProjectAndAddMembers() {
|
||||||
const project: Project = this._formToObject();
|
const project: Project = this._formToObject();
|
||||||
project.projectId = this.project?.projectId;
|
|
||||||
const savedProject = await this._appStateService.addOrUpdateProject(project);
|
const savedProject = await this._appStateService.addOrUpdateProject(project);
|
||||||
if (savedProject) {
|
if (savedProject) {
|
||||||
this.dialogRef.close({ addMembers: true, project: savedProject });
|
this.dialogRef.close({ addMembers: true, project: savedProject });
|
||||||
@ -114,28 +78,22 @@ export class AddEditProjectDialogComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ruleSetChanged(ruleSetId) {
|
ruleSetChanged(ruleSetId) {
|
||||||
// if project doesn't yet exist -> add mode
|
// get current selected ruleSet
|
||||||
if (!this.project?.projectId) {
|
const ruleSet = this.ruleSets.find((r) => r.ruleSetId === ruleSetId);
|
||||||
// get current selected ruleSet
|
if (ruleSet) {
|
||||||
const ruleSet = this.ruleSets.find((r) => r.ruleSetId === ruleSetId);
|
// update dropdown values
|
||||||
if (ruleSet) {
|
this.projectForm.patchValue(
|
||||||
// update dropdown values
|
{
|
||||||
this.projectForm.patchValue(
|
downloadFileTypes: ruleSet.downloadFileTypes,
|
||||||
{
|
reportTypes: ruleSet.reportTypes
|
||||||
downloadFileTypes: ruleSet.downloadFileTypes,
|
},
|
||||||
reportTypes: ruleSet.reportTypes
|
{ emitEvent: false }
|
||||||
},
|
);
|
||||||
{ emitEvent: false }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterInvalidRuleSets() {
|
private _filterInvalidRuleSets() {
|
||||||
this.ruleSets = this._appStateService.ruleSets.filter((r) => {
|
this.ruleSets = this._appStateService.ruleSets.filter((r) => {
|
||||||
if (this.project?.ruleSetId === r.ruleSetId) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment());
|
const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment());
|
||||||
const notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
|
const notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
|
||||||
return !(notYetValid || notValidAnymore);
|
return !(notYetValid || notValidAnymore);
|
||||||
@ -1,120 +0,0 @@
|
|||||||
<section class="dialog">
|
|
||||||
<div [translate]="'assign-project-owner.dialog.title'" class="dialog-header heading-l"></div>
|
|
||||||
|
|
||||||
<form (submit)="saveUsers()" [formGroup]="usersForm">
|
|
||||||
<div class="dialog-content no-padding-bottom">
|
|
||||||
<div class="red-input-group w-300">
|
|
||||||
<mat-form-field floatLabel="always">
|
|
||||||
<mat-label>{{
|
|
||||||
'assign-project-owner.dialog.single-user' | translate
|
|
||||||
}}</mat-label>
|
|
||||||
<mat-select formControlName="singleUser">
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let userId of singleUsersSelectOptions"
|
|
||||||
[value]="userId"
|
|
||||||
>
|
|
||||||
{{ userService.getNameForId(userId) }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
[translate]="'assign-project-owner.dialog.approvers'"
|
|
||||||
class="all-caps-label mt-16"
|
|
||||||
></div>
|
|
||||||
<redaction-team-members
|
|
||||||
(remove)="toggleSelected($event)"
|
|
||||||
[canAdd]="false"
|
|
||||||
[canRemove]="true"
|
|
||||||
[largeSpacing]="true"
|
|
||||||
[memberIds]="selectedApproversList"
|
|
||||||
[perLine]="13"
|
|
||||||
[unremovableMembers]="[selectedSingleUser]"
|
|
||||||
></redaction-team-members>
|
|
||||||
|
|
||||||
<pre
|
|
||||||
*ngIf="selectedApproversList.length === 0"
|
|
||||||
[innerHTML]="'assign-project-owner.dialog.no-approvers' | translate"
|
|
||||||
class="info"
|
|
||||||
></pre>
|
|
||||||
|
|
||||||
<div
|
|
||||||
[translate]="'assign-project-owner.dialog.reviewers'"
|
|
||||||
class="all-caps-label mt-16"
|
|
||||||
></div>
|
|
||||||
<redaction-team-members
|
|
||||||
(remove)="toggleSelected($event)"
|
|
||||||
[canAdd]="false"
|
|
||||||
[canRemove]="true"
|
|
||||||
[largeSpacing]="true"
|
|
||||||
[memberIds]="selectedReviewersList"
|
|
||||||
[perLine]="13"
|
|
||||||
[unremovableMembers]="[selectedSingleUser]"
|
|
||||||
></redaction-team-members>
|
|
||||||
|
|
||||||
<pre
|
|
||||||
*ngIf="selectedReviewersList.length === 0"
|
|
||||||
[innerHTML]="'assign-project-owner.dialog.no-reviewers' | translate"
|
|
||||||
class="info"
|
|
||||||
></pre>
|
|
||||||
|
|
||||||
<redaction-search-input
|
|
||||||
[form]="searchForm"
|
|
||||||
[placeholder]="'assign-project-owner.dialog.search' | translate"
|
|
||||||
[width]="560"
|
|
||||||
class="search-container"
|
|
||||||
></redaction-search-input>
|
|
||||||
|
|
||||||
<div class="members-list">
|
|
||||||
<div
|
|
||||||
(click)="!isOwner(userId) && toggleSelected(userId)"
|
|
||||||
*ngFor="let userId of multiUsersSelectOptions"
|
|
||||||
[class.selected]="isMemberSelected(userId)"
|
|
||||||
>
|
|
||||||
<redaction-initials-avatar
|
|
||||||
[userId]="userId"
|
|
||||||
[withName]="true"
|
|
||||||
size="large"
|
|
||||||
></redaction-initials-avatar>
|
|
||||||
<div class="actions">
|
|
||||||
<div
|
|
||||||
*ngIf="!isOwner(userId)"
|
|
||||||
(click)="toggleApprover(userId, $event)"
|
|
||||||
class="make-approver"
|
|
||||||
>
|
|
||||||
<redaction-round-checkbox
|
|
||||||
[active]="isApprover(userId)"
|
|
||||||
class="mr-8"
|
|
||||||
></redaction-round-checkbox>
|
|
||||||
<span [translate]="'assign-project-owner.dialog.make-approver'"></span>
|
|
||||||
</div>
|
|
||||||
<mat-icon *ngIf="!isOwner(userId)" svgIcon="red:check"></mat-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dialog-actions">
|
|
||||||
<button
|
|
||||||
[disabled]="!usersForm.valid || !changed"
|
|
||||||
color="primary"
|
|
||||||
mat-flat-button
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
{{ 'assign-project-owner.dialog.save' | translate }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div
|
|
||||||
[translate]="'assign-project-owner.dialog.cancel'"
|
|
||||||
class="all-caps-label pointer cancel"
|
|
||||||
mat-dialog-close
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<redaction-circle-button
|
|
||||||
class="dialog-close"
|
|
||||||
icon="red:close"
|
|
||||||
mat-dialog-close
|
|
||||||
></redaction-circle-button>
|
|
||||||
</section>
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
@import '../../../../../assets/styles/red-mixins';
|
|
||||||
|
|
||||||
.no-padding-bottom {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
redaction-team-members {
|
|
||||||
margin-top: -4px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.members-list {
|
|
||||||
max-height: 220px;
|
|
||||||
height: 220px;
|
|
||||||
margin-top: 16px;
|
|
||||||
overflow-y: hidden;
|
|
||||||
width: 587px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
overflow-y: auto;
|
|
||||||
@include scroll-bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
padding: 3px 5px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
transition: background-color ease-in-out 0.1s;
|
|
||||||
width: 560px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
.make-approver {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 13px;
|
|
||||||
top: 0;
|
|
||||||
height: 38px;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
mat-icon {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
margin-left: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected,
|
|
||||||
&:hover {
|
|
||||||
background-color: $grey-2;
|
|
||||||
.actions {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
.dialog-content {
|
.dialog-content {
|
||||||
height: calc(90vh - 160px);
|
height: calc(90vh - 160px);
|
||||||
padding: 12px 12px 0;
|
box-sizing: border-box;
|
||||||
|
padding-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,11 +12,10 @@ import { PermissionsService } from '../../../../services/permissions.service';
|
|||||||
styleUrls: ['./dossier-dictionary-dialog.component.scss']
|
styleUrls: ['./dossier-dictionary-dialog.component.scss']
|
||||||
})
|
})
|
||||||
export class DossierDictionaryDialogComponent {
|
export class DossierDictionaryDialogComponent {
|
||||||
|
canEdit = false;
|
||||||
@ViewChild('dictionaryManager', { static: false })
|
@ViewChild('dictionaryManager', { static: false })
|
||||||
private _dictionaryManager: DictionaryManagerComponent;
|
private _dictionaryManager: DictionaryManagerComponent;
|
||||||
|
|
||||||
canEdit = false;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public permissionsService: PermissionsService,
|
public permissionsService: PermissionsService,
|
||||||
public dialogRef: MatDialogRef<DossierDictionaryDialogComponent>,
|
public dialogRef: MatDialogRef<DossierDictionaryDialogComponent>,
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
<redaction-dictionary-manager
|
||||||
|
[canEdit]="canEdit"
|
||||||
|
[initialDictionaryEntries]="projectWrapper.type?.entries || []"
|
||||||
|
[withFloatingActions]="false"
|
||||||
|
></redaction-dictionary-manager>
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||||
|
import { AppStateService } from '../../../../../state/app-state.service';
|
||||||
|
import { ProjectWrapper } from '../../../../../state/model/project.wrapper';
|
||||||
|
import { EditProjectSectionInterface } from '../edit-project-section.interface';
|
||||||
|
import { DictionarySaveService } from '../../../../shared/services/dictionary-save.service';
|
||||||
|
import { DictionaryManagerComponent } from '../../../../shared/components/dictionary-manager/dictionary-manager.component';
|
||||||
|
import { PermissionsService } from '../../../../../services/permissions.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-edit-project-dictionary',
|
||||||
|
templateUrl: './edit-project-dictionary.component.html',
|
||||||
|
styleUrls: ['./edit-project-dictionary.component.scss']
|
||||||
|
})
|
||||||
|
export class EditProjectDictionaryComponent implements EditProjectSectionInterface {
|
||||||
|
@Input() projectWrapper: ProjectWrapper;
|
||||||
|
@Output() updateProject = new EventEmitter<any>();
|
||||||
|
canEdit = false;
|
||||||
|
@ViewChild(DictionaryManagerComponent, { static: false })
|
||||||
|
private _dictionaryManager: DictionaryManagerComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
private readonly _dictionarySaveService: DictionarySaveService,
|
||||||
|
private readonly _permissionsService: PermissionsService
|
||||||
|
) {
|
||||||
|
this.canEdit =
|
||||||
|
this._permissionsService.isProjectMember(this.projectWrapper) ||
|
||||||
|
this._permissionsService.isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
get changed() {
|
||||||
|
return this._dictionaryManager.hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
return !this.canEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this._dictionarySaveService
|
||||||
|
.saveEntries(
|
||||||
|
this._dictionaryManager.currentDictionaryEntries,
|
||||||
|
this._dictionaryManager.initialDictionaryEntries,
|
||||||
|
this.projectWrapper.ruleSetId,
|
||||||
|
'dossier_redaction',
|
||||||
|
this.projectWrapper.projectId,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
.subscribe(async () => {
|
||||||
|
await this._appStateService.updateProjectDictionaryVersion(this.projectWrapper);
|
||||||
|
this._appStateService.updateProjectDictionary(
|
||||||
|
this.projectWrapper.ruleSetId,
|
||||||
|
this.projectWrapper.projectId
|
||||||
|
);
|
||||||
|
this.updateProject.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
revert() {
|
||||||
|
this._dictionaryManager.revert();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<form [formGroup]="projectForm">
|
||||||
|
<redaction-select
|
||||||
|
[label]="'report-type.label' | translate: { length: reportTypesLength }"
|
||||||
|
[options]="reportTypesEnum"
|
||||||
|
[translatePrefix]="'report-type.'"
|
||||||
|
class="mr-16"
|
||||||
|
formControlName="reportTypes"
|
||||||
|
></redaction-select>
|
||||||
|
<redaction-select
|
||||||
|
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
||||||
|
[options]="downloadTypesEnum"
|
||||||
|
[translatePrefix]="'download-type.'"
|
||||||
|
formControlName="downloadFileTypes"
|
||||||
|
></redaction-select>
|
||||||
|
</form>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
@import '../../../../../../assets/styles/red-variables';
|
||||||
|
|
||||||
|
.download-includes {
|
||||||
|
margin: 16px 0 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
redaction-select {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
height: calc(100% - 44px);
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
import { RuleSetModel } from '@redaction/red-ui-http';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { AppStateService } from '../../../../../state/app-state.service';
|
||||||
|
import { ProjectWrapper } from '../../../../../state/model/project.wrapper';
|
||||||
|
import { EditProjectSectionInterface } from '../edit-project-section.interface';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-edit-project-download-package',
|
||||||
|
templateUrl: './edit-project-download-package.component.html',
|
||||||
|
styleUrls: ['./edit-project-download-package.component.scss']
|
||||||
|
})
|
||||||
|
export class EditProjectDownloadPackageComponent implements OnInit, EditProjectSectionInterface {
|
||||||
|
projectForm: FormGroup;
|
||||||
|
downloadTypesEnum = ['ORIGINAL', 'PREVIEW', 'REDACTED'];
|
||||||
|
reportTypesEnum = Object.values(RuleSetModel.ReportTypesEnum);
|
||||||
|
ruleSets: RuleSetModel[];
|
||||||
|
|
||||||
|
@Input() projectWrapper: ProjectWrapper;
|
||||||
|
@Output() updateProject = new EventEmitter<any>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
private readonly _formBuilder: FormBuilder
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get reportTypesLength() {
|
||||||
|
return this.projectForm.controls['reportTypes']?.value?.length
|
||||||
|
? this.projectForm.controls['reportTypes'].value.length
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get downloadFileTypesLength() {
|
||||||
|
return this.projectForm.controls['downloadFileTypes']?.value?.length
|
||||||
|
? this.projectForm.controls['downloadFileTypes'].value.length
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get changed() {
|
||||||
|
for (const key of Object.keys(this.projectForm.getRawValue())) {
|
||||||
|
if (
|
||||||
|
this.projectWrapper.project[key].length !== this.projectForm.get(key).value.length
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalItems = [...this.projectWrapper.project[key]].sort();
|
||||||
|
const newItems = [...this.projectForm.get(key).value].sort();
|
||||||
|
|
||||||
|
for (let idx = 0; idx < originalItems.length; ++idx) {
|
||||||
|
if (originalItems[idx] !== newItems[idx]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
return this.projectForm.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.projectForm = this._formBuilder.group({
|
||||||
|
reportTypes: [this.projectWrapper.project.reportTypes, Validators.required],
|
||||||
|
downloadFileTypes: [this.projectWrapper.project.downloadFileTypes]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async save() {
|
||||||
|
const project = {
|
||||||
|
...this.projectWrapper.project,
|
||||||
|
downloadFileTypes: this.projectForm.get('downloadFileTypes').value,
|
||||||
|
reportTypes: this.projectForm.get('reportTypes').value
|
||||||
|
};
|
||||||
|
const updatedProject = await this._appStateService.addOrUpdateProject(project);
|
||||||
|
this.updateProject.emit(updatedProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
revert() {
|
||||||
|
this.projectForm.reset({
|
||||||
|
downloadFileTypes: this.projectWrapper.project.downloadFileTypes,
|
||||||
|
reportTypes: this.projectWrapper.project.reportTypes
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
<section class="dialog">
|
||||||
|
<div class="dialog-header heading-l">
|
||||||
|
{{ 'edit-project-dialog.header' | translate: { projectName: projectWrapper.name } }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-content">
|
||||||
|
<redaction-side-nav title="configurations">
|
||||||
|
<div
|
||||||
|
(click)="changeTab(item.key)"
|
||||||
|
*ngFor="let item of navItems"
|
||||||
|
[class.active]="item.key === activeNav"
|
||||||
|
[translate]="'edit-project-dialog.nav-items.' + item.key"
|
||||||
|
class="item"
|
||||||
|
></div>
|
||||||
|
</redaction-side-nav>
|
||||||
|
<div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="heading">
|
||||||
|
{{
|
||||||
|
'edit-project-dialog.nav-items.' +
|
||||||
|
(activeNavItem.title || activeNavItem.key) | translate
|
||||||
|
}}
|
||||||
|
|
||||||
|
<div
|
||||||
|
*ngIf="activeNav === 'dossier-dictionary'"
|
||||||
|
class="small-label stats-subtitle"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||||
|
{{
|
||||||
|
'edit-project-dialog.dictionary.entries'
|
||||||
|
| translate
|
||||||
|
: { length: (projectWrapper.type?.entries || []).length }
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<redaction-edit-project-general-info
|
||||||
|
(updateProject)="updatedProject($event)"
|
||||||
|
*ngIf="activeNav === 'dossier-info'"
|
||||||
|
[projectWrapper]="projectWrapper"
|
||||||
|
></redaction-edit-project-general-info>
|
||||||
|
|
||||||
|
<redaction-edit-project-download-package
|
||||||
|
(updateProject)="updatedProject($event)"
|
||||||
|
*ngIf="activeNav === 'download-package'"
|
||||||
|
[projectWrapper]="projectWrapper"
|
||||||
|
></redaction-edit-project-download-package>
|
||||||
|
|
||||||
|
<redaction-edit-project-dictionary
|
||||||
|
(updateProject)="updatedProject($event)"
|
||||||
|
*ngIf="activeNav === 'dossier-dictionary'"
|
||||||
|
[projectWrapper]="projectWrapper"
|
||||||
|
>
|
||||||
|
</redaction-edit-project-dictionary>
|
||||||
|
|
||||||
|
<redaction-edit-project-team-members
|
||||||
|
(updateProject)="updatedProject($event)"
|
||||||
|
*ngIf="activeNav === 'members'"
|
||||||
|
[projectWrapper]="projectWrapper"
|
||||||
|
>
|
||||||
|
</redaction-edit-project-team-members>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<button
|
||||||
|
(click)="save()"
|
||||||
|
[disabled]="activeComponent?.disabled || !activeComponent?.changed"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
>
|
||||||
|
{{ 'edit-project-dialog.actions.save' | translate }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
(click)="revert()"
|
||||||
|
class="all-caps-label cancel"
|
||||||
|
translate="edit-project-dialog.actions.revert"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<redaction-circle-button
|
||||||
|
class="dialog-close"
|
||||||
|
icon="red:close"
|
||||||
|
mat-dialog-close
|
||||||
|
></redaction-circle-button>
|
||||||
|
</section>
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
@import '../../../../../assets/styles/red-variables';
|
||||||
|
@import '../../../../../assets/styles/red-mixins';
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 24px;
|
||||||
|
border-top: 1px solid $separator;
|
||||||
|
display: flex;
|
||||||
|
height: calc(90vh - 81px);
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 24px 32px;
|
||||||
|
overflow: auto;
|
||||||
|
@include scroll-bar;
|
||||||
|
height: calc(100% - 81px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redaction-edit-project-dictionary {
|
||||||
|
display: block;
|
||||||
|
height: calc(100% - 74px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-subtitle {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
import { ChangeDetectorRef, Component, Inject, ViewChild } from '@angular/core';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
import { AppStateService } from '@state/app-state.service';
|
||||||
|
import { ProjectWrapper } from '../../../../state/model/project.wrapper';
|
||||||
|
import { EditProjectGeneralInfoComponent } from './general-info/edit-project-general-info.component';
|
||||||
|
import { EditProjectDownloadPackageComponent } from './download-package/edit-project-download-package.component';
|
||||||
|
import { EditProjectSectionInterface } from './edit-project-section.interface';
|
||||||
|
import { NotificationService, NotificationType } from '../../../../services/notification.service';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { EditProjectDictionaryComponent } from './dictionary/edit-project-dictionary.component';
|
||||||
|
import { EditProjectTeamMembersComponent } from './team-members/edit-project-team-members.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-edit-project-dialog',
|
||||||
|
templateUrl: './edit-project-dialog.component.html',
|
||||||
|
styleUrls: ['./edit-project-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class EditProjectDialogComponent {
|
||||||
|
navItems: { key: string; title?: string }[] = [
|
||||||
|
{ key: 'dossier-info', title: 'general-info' },
|
||||||
|
{ key: 'download-package', title: 'choose-download' },
|
||||||
|
{ key: 'dossier-dictionary', title: 'dossier-dictionary' },
|
||||||
|
{ key: 'members', title: 'team-members' }
|
||||||
|
// TODO:
|
||||||
|
// { key: 'project-attributes' },
|
||||||
|
// { key: 'report-attributes' }
|
||||||
|
];
|
||||||
|
activeNav = 'dossier-info';
|
||||||
|
projectWrapper: ProjectWrapper;
|
||||||
|
|
||||||
|
@ViewChild(EditProjectGeneralInfoComponent)
|
||||||
|
generalInfoComponent: EditProjectGeneralInfoComponent;
|
||||||
|
@ViewChild(EditProjectDownloadPackageComponent)
|
||||||
|
downloadPackageComponent: EditProjectDownloadPackageComponent;
|
||||||
|
@ViewChild(EditProjectDictionaryComponent) dictionaryComponent: EditProjectDictionaryComponent;
|
||||||
|
@ViewChild(EditProjectTeamMembersComponent) membersComponent: EditProjectTeamMembersComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
private readonly _formBuilder: FormBuilder,
|
||||||
|
private readonly _notificationService: NotificationService,
|
||||||
|
private readonly _translateService: TranslateService,
|
||||||
|
private readonly _changeRef: ChangeDetectorRef,
|
||||||
|
public dialogRef: MatDialogRef<EditProjectDialogComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA)
|
||||||
|
public data: { projectWrapper: ProjectWrapper; afterSave: Function }
|
||||||
|
) {
|
||||||
|
this.projectWrapper = data.projectWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeNavItem(): { key: string; title?: string } {
|
||||||
|
return this.navItems.find((item) => item.key === this.activeNav);
|
||||||
|
}
|
||||||
|
|
||||||
|
get activeComponent(): EditProjectSectionInterface {
|
||||||
|
return {
|
||||||
|
'dossier-info': this.generalInfoComponent,
|
||||||
|
'download-package': this.downloadPackageComponent,
|
||||||
|
'dossier-dictionary': this.dictionaryComponent,
|
||||||
|
members: this.membersComponent
|
||||||
|
}[this.activeNav];
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedProject(updatedProject: ProjectWrapper) {
|
||||||
|
this._notificationService.showToastNotification(
|
||||||
|
this._translateService.instant('edit-project-dialog.change-successful'),
|
||||||
|
null,
|
||||||
|
NotificationType.SUCCESS
|
||||||
|
);
|
||||||
|
if (updatedProject) {
|
||||||
|
this.projectWrapper = updatedProject;
|
||||||
|
}
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
if (this.data.afterSave) {
|
||||||
|
this.data.afterSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async save() {
|
||||||
|
await this.activeComponent.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
async revert() {
|
||||||
|
this.activeComponent.revert();
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTab(key: string) {
|
||||||
|
if (this.activeComponent.changed) {
|
||||||
|
this._notificationService.showToastNotification(
|
||||||
|
this._translateService.instant('edit-project-dialog.unsaved-changes'),
|
||||||
|
null,
|
||||||
|
NotificationType.ERROR
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.activeNav = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export interface EditProjectSectionInterface {
|
||||||
|
changed: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
save: Function;
|
||||||
|
revert: Function;
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
<form (submit)="save()" [formGroup]="projectForm">
|
||||||
|
<div class="red-input-group required w-300">
|
||||||
|
<label translate="edit-project-dialog.general-info.form.name.label"></label>
|
||||||
|
<input
|
||||||
|
[placeholder]="'edit-project-dialog.general-info.form.name.placeholder' | translate"
|
||||||
|
formControlName="projectName"
|
||||||
|
name="projectName"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="red-input-group required w-400">
|
||||||
|
<mat-form-field floatLabel="always">
|
||||||
|
<mat-label>{{
|
||||||
|
'edit-project-dialog.general-info.form.template' | translate
|
||||||
|
}}</mat-label>
|
||||||
|
<mat-select formControlName="ruleSetId" style="width: 100%">
|
||||||
|
<mat-option
|
||||||
|
*ngFor="let ruleSet of ruleSets"
|
||||||
|
[matTooltip]="ruleSet.description ? ruleSet.description : ruleSet.name"
|
||||||
|
[value]="ruleSet.ruleSetId"
|
||||||
|
matTooltipPosition="after"
|
||||||
|
>
|
||||||
|
{{ ruleSet.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="red-input-group w-400">
|
||||||
|
<label translate="edit-project-dialog.general-info.form.description.label"></label>
|
||||||
|
<textarea
|
||||||
|
[placeholder]="
|
||||||
|
'edit-project-dialog.general-info.form.description.placeholder' | translate
|
||||||
|
"
|
||||||
|
formControlName="description"
|
||||||
|
name="description"
|
||||||
|
redactionHasScrollbar
|
||||||
|
rows="5"
|
||||||
|
type="text"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="due-date">
|
||||||
|
<mat-checkbox
|
||||||
|
(change)="hasDueDate = !hasDueDate"
|
||||||
|
[checked]="hasDueDate"
|
||||||
|
class="filter-menu-checkbox"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
{{ 'edit-project-dialog.general-info.form.due-date' | translate }}
|
||||||
|
</mat-checkbox>
|
||||||
|
|
||||||
|
<div *ngIf="hasDueDate" class="red-input-group datepicker-wrapper">
|
||||||
|
<input [matDatepicker]="picker" formControlName="dueDate" placeholder="dd/mm/yy" />
|
||||||
|
<mat-datepicker-toggle [for]="picker" matSuffix>
|
||||||
|
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
|
||||||
|
</mat-datepicker-toggle>
|
||||||
|
<mat-datepicker #picker></mat-datepicker>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
@import '../../../../../../assets/styles/red-variables';
|
||||||
|
|
||||||
|
.due-date {
|
||||||
|
margin-top: 16px;
|
||||||
|
min-height: 34px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
mat-checkbox {
|
||||||
|
width: fit-content;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
|
import { RuleSetModel } from '@redaction/red-ui-http';
|
||||||
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
|
import { AppStateService } from '../../../../../state/app-state.service';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import { ProjectWrapper } from '../../../../../state/model/project.wrapper';
|
||||||
|
import { EditProjectSectionInterface } from '../edit-project-section.interface';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-edit-project-general-info',
|
||||||
|
templateUrl: './edit-project-general-info.component.html',
|
||||||
|
styleUrls: ['./edit-project-general-info.component.scss']
|
||||||
|
})
|
||||||
|
export class EditProjectGeneralInfoComponent implements OnInit, EditProjectSectionInterface {
|
||||||
|
projectForm: FormGroup;
|
||||||
|
hasDueDate: boolean;
|
||||||
|
reportTypesEnum = Object.values(RuleSetModel.ReportTypesEnum);
|
||||||
|
ruleSets: RuleSetModel[];
|
||||||
|
|
||||||
|
@Input() projectWrapper: ProjectWrapper;
|
||||||
|
@Output() updateProject = new EventEmitter<any>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
private readonly _formBuilder: FormBuilder
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get changed() {
|
||||||
|
for (const key of Object.keys(this.projectForm.getRawValue())) {
|
||||||
|
if (key === 'dueDate') {
|
||||||
|
if (this.hasDueDate !== !!this.projectWrapper.dueDate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.hasDueDate &&
|
||||||
|
!moment(this.projectWrapper.dueDate).isSame(
|
||||||
|
moment(this.projectForm.get(key).value)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (this.projectWrapper[key] !== this.projectForm.get(key).value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
if (this.hasDueDate && this.projectForm.get('dueDate').value === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.projectForm.invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this._filterInvalidRuleSets();
|
||||||
|
this.projectForm = this._formBuilder.group({
|
||||||
|
projectName: [this.projectWrapper.projectName, Validators.required],
|
||||||
|
ruleSetId: [
|
||||||
|
{
|
||||||
|
value: this.projectWrapper.ruleSetId,
|
||||||
|
disabled: this.projectWrapper.hasFiles
|
||||||
|
},
|
||||||
|
Validators.required
|
||||||
|
],
|
||||||
|
description: [this.projectWrapper.description],
|
||||||
|
dueDate: [this.projectWrapper.dueDate]
|
||||||
|
});
|
||||||
|
this.hasDueDate = !!this.projectWrapper.dueDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
revert() {
|
||||||
|
this.projectForm.reset({
|
||||||
|
projectName: this.projectWrapper.projectName,
|
||||||
|
ruleSetId: this.projectWrapper.ruleSetId,
|
||||||
|
description: this.projectWrapper.description,
|
||||||
|
dueDate: this.projectWrapper.dueDate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async save() {
|
||||||
|
const project = {
|
||||||
|
...this.projectWrapper.project,
|
||||||
|
projectName: this.projectForm.get('projectName').value,
|
||||||
|
description: this.projectForm.get('description').value,
|
||||||
|
dueDate: this.hasDueDate ? this.projectForm.get('dueDate').value : undefined,
|
||||||
|
ruleSetId: this.projectForm.get('ruleSetId').value
|
||||||
|
};
|
||||||
|
const updatedProject = await this._appStateService.addOrUpdateProject(project);
|
||||||
|
this.updateProject.emit(updatedProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filterInvalidRuleSets() {
|
||||||
|
this.ruleSets = this._appStateService.ruleSets.filter((r) => {
|
||||||
|
if (this.projectWrapper?.ruleSetId === r.ruleSetId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment());
|
||||||
|
const notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
|
||||||
|
return !(notYetValid || notValidAnymore);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<redaction-team-members-manager
|
||||||
|
(save)="updatedProject($event)"
|
||||||
|
[projectWrapper]="projectWrapper"
|
||||||
|
></redaction-team-members-manager>
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
||||||
|
import { AppStateService } from '../../../../../state/app-state.service';
|
||||||
|
import { ProjectWrapper } from '../../../../../state/model/project.wrapper';
|
||||||
|
import { EditProjectSectionInterface } from '../edit-project-section.interface';
|
||||||
|
import { PermissionsService } from '../../../../../services/permissions.service';
|
||||||
|
import { TeamMembersManagerComponent } from '../../../components/team-members-manager/team-members-manager.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-edit-project-team-members',
|
||||||
|
templateUrl: './edit-project-team-members.component.html',
|
||||||
|
styleUrls: ['./edit-project-team-members.component.scss']
|
||||||
|
})
|
||||||
|
export class EditProjectTeamMembersComponent implements EditProjectSectionInterface {
|
||||||
|
@Input() projectWrapper: ProjectWrapper;
|
||||||
|
@Output() updateProject = new EventEmitter<any>();
|
||||||
|
|
||||||
|
@ViewChild(TeamMembersManagerComponent) managerComponent: TeamMembersManagerComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
private readonly _permissionsService: PermissionsService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get changed() {
|
||||||
|
return this.managerComponent.changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
return !this._permissionsService.isManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
async save() {
|
||||||
|
await this.managerComponent.saveMembers();
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedProject($event) {
|
||||||
|
this.updateProject.emit($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
revert() {
|
||||||
|
this.managerComponent.revert();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<section class="dialog">
|
||||||
|
<div [translate]="'assign-project-owner.dialog.title'" class="dialog-header heading-l"></div>
|
||||||
|
|
||||||
|
<div class="dialog-content no-padding-bottom">
|
||||||
|
<redaction-team-members-manager
|
||||||
|
(save)="save($event)"
|
||||||
|
[projectWrapper]="data.projectWrapper"
|
||||||
|
></redaction-team-members-manager>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-actions">
|
||||||
|
<button
|
||||||
|
(click)="managerComponent.saveMembers()"
|
||||||
|
[disabled]="!managerComponent.valid || !managerComponent.changed"
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
>
|
||||||
|
{{ 'assign-project-owner.dialog.save' | translate }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
[translate]="'assign-project-owner.dialog.cancel'"
|
||||||
|
class="all-caps-label pointer cancel"
|
||||||
|
mat-dialog-close
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<redaction-circle-button
|
||||||
|
class="dialog-close"
|
||||||
|
icon="red:close"
|
||||||
|
mat-dialog-close
|
||||||
|
></redaction-circle-button>
|
||||||
|
</section>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
.no-padding-bottom {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep redaction-team-members-manager .members-list {
|
||||||
|
max-height: 220px;
|
||||||
|
height: 220px;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { Component, Inject, ViewChild } from '@angular/core';
|
||||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { AppStateService } from '@state/app-state.service';
|
||||||
|
import { NotificationService } from '@services/notification.service';
|
||||||
|
import { ProjectWrapper } from '@state/model/project.wrapper';
|
||||||
|
import { TeamMembersManagerComponent } from '../../components/team-members-manager/team-members-manager.component';
|
||||||
|
|
||||||
|
class DialogData {
|
||||||
|
projectWrapper?: ProjectWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-team-members-dialog',
|
||||||
|
templateUrl: './team-members-dialog.component.html',
|
||||||
|
styleUrls: ['./team-members-dialog.component.scss']
|
||||||
|
})
|
||||||
|
export class TeamMembersDialogComponent {
|
||||||
|
@ViewChild(TeamMembersManagerComponent, { static: true })
|
||||||
|
managerComponent: TeamMembersManagerComponent;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly _notificationService: NotificationService,
|
||||||
|
private readonly _appStateService: AppStateService,
|
||||||
|
public dialogRef: MatDialogRef<TeamMembersDialogComponent>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: DialogData
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async save(result) {
|
||||||
|
this.dialogRef.close(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,8 +3,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { ProjectListingScreenComponent } from './screens/project-listing-screen/project-listing-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 { ProjectOverviewScreenComponent } from './screens/project-overview-screen/project-overview-screen.component';
|
||||||
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
|
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
|
||||||
import { AddEditProjectDialogComponent } from './dialogs/add-edit-project-dialog/add-edit-project-dialog.component';
|
import { AddProjectDialogComponent } from './dialogs/add-project-dialog/add-project-dialog.component';
|
||||||
import { AssignOwnerDialogComponent } from './dialogs/assign-owner-dialog/assign-owner-dialog.component';
|
|
||||||
import { AssignReviewerApproverDialogComponent } from './dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
import { AssignReviewerApproverDialogComponent } from './dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||||
import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||||
import { ForceRedactionDialogComponent } from './dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
import { ForceRedactionDialogComponent } from './dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
||||||
@ -37,7 +36,14 @@ import { AnnotationDrawService } from './services/annotation-draw.service';
|
|||||||
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
||||||
import { AnnotationRemoveActionsComponent } from './components/annotation-remove-actions/annotation-remove-actions.component';
|
import { AnnotationRemoveActionsComponent } from './components/annotation-remove-actions/annotation-remove-actions.component';
|
||||||
import { DossierDictionaryDialogComponent } from './dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component';
|
import { DossierDictionaryDialogComponent } from './dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component';
|
||||||
|
import { EditProjectDialogComponent } from './dialogs/edit-project-dialog/edit-project-dialog.component';
|
||||||
|
import { EditProjectGeneralInfoComponent } from './dialogs/edit-project-dialog/general-info/edit-project-general-info.component';
|
||||||
|
import { EditProjectDownloadPackageComponent } from './dialogs/edit-project-dialog/download-package/edit-project-download-package.component';
|
||||||
import { UserPreferenceControllerService } from '@redaction/red-ui-http';
|
import { UserPreferenceControllerService } from '@redaction/red-ui-http';
|
||||||
|
import { EditProjectDictionaryComponent } from './dialogs/edit-project-dialog/dictionary/edit-project-dictionary.component';
|
||||||
|
import { EditProjectTeamMembersComponent } from './dialogs/edit-project-dialog/team-members/edit-project-team-members.component';
|
||||||
|
import { TeamMembersManagerComponent } from './components/team-members-manager/team-members-manager.component';
|
||||||
|
import { TeamMembersDialogComponent } from './dialogs/team-members-dialog/team-members-dialog.component';
|
||||||
|
|
||||||
const screens = [
|
const screens = [
|
||||||
ProjectListingScreenComponent,
|
ProjectListingScreenComponent,
|
||||||
@ -46,8 +52,9 @@ const screens = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const dialogs = [
|
const dialogs = [
|
||||||
AddEditProjectDialogComponent,
|
AddProjectDialogComponent,
|
||||||
AssignOwnerDialogComponent,
|
EditProjectDialogComponent,
|
||||||
|
TeamMembersDialogComponent,
|
||||||
ManualAnnotationDialogComponent,
|
ManualAnnotationDialogComponent,
|
||||||
ForceRedactionDialogComponent,
|
ForceRedactionDialogComponent,
|
||||||
RemoveAnnotationsDialogComponent,
|
RemoveAnnotationsDialogComponent,
|
||||||
@ -72,6 +79,11 @@ const components = [
|
|||||||
DocumentInfoComponent,
|
DocumentInfoComponent,
|
||||||
FileWorkloadComponent,
|
FileWorkloadComponent,
|
||||||
AnnotationRemoveActionsComponent,
|
AnnotationRemoveActionsComponent,
|
||||||
|
EditProjectGeneralInfoComponent,
|
||||||
|
EditProjectDownloadPackageComponent,
|
||||||
|
EditProjectDictionaryComponent,
|
||||||
|
EditProjectTeamMembersComponent,
|
||||||
|
TeamMembersManagerComponent,
|
||||||
|
|
||||||
...screens,
|
...screens,
|
||||||
...dialogs
|
...dialogs
|
||||||
|
|||||||
@ -68,10 +68,6 @@
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mr-16 {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ml-8 {
|
.ml-8 {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -195,7 +195,7 @@ export class ProjectListingScreenComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAssignProjectOwnerDialog($event: MouseEvent, project: ProjectWrapper) {
|
openAssignProjectOwnerDialog($event: MouseEvent, project: ProjectWrapper) {
|
||||||
this._dialogService.openAssignProjectMembersAndOwnerDialog($event, project);
|
this._dialogService.openAssignTeamMembersDialog($event, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
actionPerformed() {
|
actionPerformed() {
|
||||||
|
|||||||
@ -54,13 +54,6 @@
|
|||||||
<!-- tooltip="project-overview.header-actions.delete"-->
|
<!-- tooltip="project-overview.header-actions.delete"-->
|
||||||
<!-- tooltipPosition="below"-->
|
<!-- tooltipPosition="below"-->
|
||||||
<!-- ></redaction-circle-button>-->
|
<!-- ></redaction-circle-button>-->
|
||||||
<redaction-circle-button
|
|
||||||
(action)="openAssignProjectMembersDialog()"
|
|
||||||
*ngIf="permissionsService.isManager()"
|
|
||||||
icon="red:assign"
|
|
||||||
tooltip="project-overview.header-actions.assign"
|
|
||||||
tooltipPosition="below"
|
|
||||||
></redaction-circle-button>
|
|
||||||
|
|
||||||
<redaction-file-download-btn
|
<redaction-file-download-btn
|
||||||
[file]="allEntities"
|
[file]="allEntities"
|
||||||
@ -199,8 +192,8 @@
|
|||||||
trackBy: fileId
|
trackBy: fileId
|
||||||
"
|
"
|
||||||
[class.disabled]="fileStatus.isExcluded"
|
[class.disabled]="fileStatus.isExcluded"
|
||||||
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
|
||||||
[class.last-opened]="isLastOpenedFile(fileStatus)"
|
[class.last-opened]="isLastOpenedFile(fileStatus)"
|
||||||
|
[class.pointer]="permissionsService.canOpenFile(fileStatus)"
|
||||||
[routerLink]="fileLink(fileStatus)"
|
[routerLink]="fileLink(fileStatus)"
|
||||||
class="table-item"
|
class="table-item"
|
||||||
>
|
>
|
||||||
@ -322,8 +315,8 @@
|
|||||||
<redaction-project-details
|
<redaction-project-details
|
||||||
#projectDetailsComponent
|
#projectDetailsComponent
|
||||||
(filtersChanged)="filtersChanged($event)"
|
(filtersChanged)="filtersChanged($event)"
|
||||||
(openDossierDictionaryDialog)="openDossierDictionaryDialog()"
|
|
||||||
(openAssignProjectMembersDialog)="openAssignProjectMembersDialog()"
|
(openAssignProjectMembersDialog)="openAssignProjectMembersDialog()"
|
||||||
|
(openDossierDictionaryDialog)="openDossierDictionaryDialog()"
|
||||||
(toggleCollapse)="toggleCollapsedDetails()"
|
(toggleCollapse)="toggleCollapsedDetails()"
|
||||||
[filters]="detailsContainerFilters"
|
[filters]="detailsContainerFilters"
|
||||||
></redaction-project-details>
|
></redaction-project-details>
|
||||||
|
|||||||
@ -87,10 +87,6 @@ export class ProjectOverviewScreenComponent
|
|||||||
return this._appStateService.activeProject;
|
return this._appStateService.activeProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
isLastOpenedFile(fileStatus: FileStatusWrapper): boolean {
|
|
||||||
return this._lastOpenedFileId === fileStatus.fileId;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get _filterComponents(): FilterComponent[] {
|
protected get _filterComponents(): FilterComponent[] {
|
||||||
return [
|
return [
|
||||||
this._statusFilterComponent,
|
this._statusFilterComponent,
|
||||||
@ -117,11 +113,17 @@ export class ProjectOverviewScreenComponent
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isLastOpenedFile(fileStatus: FileStatusWrapper): boolean {
|
||||||
|
return this._lastOpenedFileId === fileStatus.fileId;
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this._userPreferenceControllerService.getAllUserAttributes().subscribe((attributes) => {
|
this._userPreferenceControllerService.getAllUserAttributes().subscribe((attributes) => {
|
||||||
if (attributes === null || attributes === undefined) return;
|
if (attributes === null || attributes === undefined) return;
|
||||||
const key = 'Project-Recent-' + this.activeProject.projectId;
|
const key = 'Project-Recent-' + this.activeProject.projectId;
|
||||||
this._lastOpenedFileId = attributes[key][0];
|
if (attributes[key]?.length > 0) {
|
||||||
|
this._lastOpenedFileId = attributes[key][0];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._fileDropOverlayService.initFileDropHandling();
|
this._fileDropOverlayService.initFileDropHandling();
|
||||||
@ -266,7 +268,7 @@ export class ProjectOverviewScreenComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
openAssignProjectMembersDialog(): void {
|
openAssignProjectMembersDialog(): void {
|
||||||
this._dialogService.openAssignProjectMembersAndOwnerDialog(null, this.activeProject, () => {
|
this._dialogService.openAssignTeamMembersDialog(null, this.activeProject, () => {
|
||||||
this.reloadProjects();
|
this.reloadProjects();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {
|
|||||||
ManualRedactionControllerService,
|
ManualRedactionControllerService,
|
||||||
RuleSetControllerService
|
RuleSetControllerService
|
||||||
} from '@redaction/red-ui-http';
|
} from '@redaction/red-ui-http';
|
||||||
import { AddEditProjectDialogComponent } from '../dialogs/add-edit-project-dialog/add-edit-project-dialog.component';
|
import { AddProjectDialogComponent } from '../dialogs/add-project-dialog/add-project-dialog.component';
|
||||||
import { RemoveAnnotationsDialogComponent } from '../dialogs/remove-annotations-dialog/remove-annotations-dialog.component';
|
import { RemoveAnnotationsDialogComponent } from '../dialogs/remove-annotations-dialog/remove-annotations-dialog.component';
|
||||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||||
import { ForceRedactionDialogComponent } from '../dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
import { ForceRedactionDialogComponent } from '../dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
||||||
@ -23,10 +23,11 @@ import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry
|
|||||||
import { ManualAnnotationService } from './manual-annotation.service';
|
import { ManualAnnotationService } from './manual-annotation.service';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
import { ManualAnnotationDialogComponent } from '../dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||||
import { AssignOwnerDialogComponent } from '../dialogs/assign-owner-dialog/assign-owner-dialog.component';
|
|
||||||
import { DossierDictionaryDialogComponent } from '../dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component';
|
import { DossierDictionaryDialogComponent } from '../dialogs/dossier-dictionary-dialog/dossier-dictionary-dialog.component';
|
||||||
|
import { EditProjectDialogComponent } from '../dialogs/edit-project-dialog/edit-project-dialog.component';
|
||||||
import { FileStatusWrapper } from '../../../models/file/file-status.wrapper';
|
import { FileStatusWrapper } from '../../../models/file/file-status.wrapper';
|
||||||
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||||
|
import { TeamMembersDialogComponent } from '../dialogs/team-members-dialog/team-members-dialog.component';
|
||||||
|
|
||||||
const dialogConfig = {
|
const dialogConfig = {
|
||||||
width: '662px',
|
width: '662px',
|
||||||
@ -150,26 +151,6 @@ export class ProjectsDialogService {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
openEditProjectDialog(
|
|
||||||
$event: MouseEvent,
|
|
||||||
project: ProjectWrapper,
|
|
||||||
cb?: Function
|
|
||||||
): MatDialogRef<AddEditProjectDialogComponent> {
|
|
||||||
$event.stopPropagation();
|
|
||||||
const ref = this._dialog.open(AddEditProjectDialogComponent, {
|
|
||||||
...dialogConfig,
|
|
||||||
width: '900px',
|
|
||||||
autoFocus: true,
|
|
||||||
data: project
|
|
||||||
});
|
|
||||||
ref.afterClosed().subscribe(async (result) => {
|
|
||||||
if (result && cb) {
|
|
||||||
cb(result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
openForceRedactionDialog(
|
openForceRedactionDialog(
|
||||||
$event: MouseEvent,
|
$event: MouseEvent,
|
||||||
cb?: Function
|
cb?: Function
|
||||||
@ -228,15 +209,15 @@ export class ProjectsDialogService {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
openAssignProjectMembersAndOwnerDialog(
|
openAssignTeamMembersDialog(
|
||||||
$event: MouseEvent,
|
$event: MouseEvent,
|
||||||
project: ProjectWrapper,
|
projectWrapper: ProjectWrapper,
|
||||||
cb?: Function
|
cb?: Function
|
||||||
): MatDialogRef<AssignOwnerDialogComponent> {
|
): MatDialogRef<TeamMembersDialogComponent> {
|
||||||
$event?.stopPropagation();
|
$event?.stopPropagation();
|
||||||
const ref = this._dialog.open(AssignOwnerDialogComponent, {
|
const ref = this._dialog.open(TeamMembersDialogComponent, {
|
||||||
...dialogConfig,
|
...dialogConfig,
|
||||||
data: { project: project }
|
data: { projectWrapper }
|
||||||
});
|
});
|
||||||
ref.afterClosed().subscribe((result) => {
|
ref.afterClosed().subscribe((result) => {
|
||||||
if (cb) {
|
if (cb) {
|
||||||
@ -298,9 +279,10 @@ export class ProjectsDialogService {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
openAddProjectDialog(cb?: Function): MatDialogRef<AddEditProjectDialogComponent> {
|
openAddProjectDialog(cb?: Function): MatDialogRef<AddProjectDialogComponent> {
|
||||||
const ref = this._dialog.open(AddEditProjectDialogComponent, {
|
const ref = this._dialog.open(AddProjectDialogComponent, {
|
||||||
...dialogConfig,
|
...dialogConfig,
|
||||||
|
width: '900px',
|
||||||
autoFocus: true
|
autoFocus: true
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -311,6 +293,21 @@ export class ProjectsDialogService {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openEditProjectDialog(
|
||||||
|
$event: MouseEvent,
|
||||||
|
projectWrapper: ProjectWrapper,
|
||||||
|
cb?: Function
|
||||||
|
): MatDialogRef<EditProjectDialogComponent> {
|
||||||
|
$event.stopPropagation();
|
||||||
|
return this._dialog.open(EditProjectDialogComponent, {
|
||||||
|
...dialogConfig,
|
||||||
|
width: '90vw',
|
||||||
|
height: '90vh',
|
||||||
|
autoFocus: true,
|
||||||
|
data: { projectWrapper, afterSave: cb }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
openDocumentInfoDialog(
|
openDocumentInfoDialog(
|
||||||
file: FileStatus,
|
file: FileStatus,
|
||||||
cb?: Function
|
cb?: Function
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form [formGroup]="compareForm" class="compare-form">
|
<form [formGroup]="compareForm">
|
||||||
<div class="red-input-group mr-16">
|
<div class="red-input-group mr-16">
|
||||||
<mat-checkbox color="primary" formControlName="active">
|
<mat-checkbox color="primary" formControlName="active">
|
||||||
{{ 'dictionary-overview.compare.compare' | translate }}
|
{{ 'dictionary-overview.compare.compare' | translate }}
|
||||||
|
|||||||
@ -4,13 +4,15 @@
|
|||||||
:host {
|
:host {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compare-form {
|
form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
.red-input-group {
|
.red-input-group {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
@ -18,7 +20,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor-container {
|
.editor-container {
|
||||||
height: calc(100% - 50px);
|
height: calc(100% - 53px);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
> *:not(:first-child:last-child) {
|
> *:not(:first-child:last-child) {
|
||||||
@ -36,9 +38,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-container {
|
.content-container {
|
||||||
padding: 15px;
|
height: 100%;
|
||||||
height: calc(100% - 30px);
|
|
||||||
width: calc(100% - 30px);
|
|
||||||
|
|
||||||
.actions-bar {
|
.actions-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -49,11 +49,6 @@
|
|||||||
margin-right: 32px;
|
margin-right: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mr-16 {
|
|
||||||
margin-right: 16px;
|
|
||||||
//opacity: 0; // TODO: Hidden for now
|
|
||||||
}
|
|
||||||
|
|
||||||
.red-input-group {
|
.red-input-group {
|
||||||
input {
|
input {
|
||||||
padding-right: 32px;
|
padding-right: 32px;
|
||||||
|
|||||||
@ -13,12 +13,13 @@
|
|||||||
[text]="filterLabel"
|
[text]="filterLabel"
|
||||||
></redaction-chevron-button>
|
></redaction-chevron-button>
|
||||||
|
|
||||||
<mat-menu #filterMenu="matMenu" (closed)="applyFilters()" xPosition="before">
|
<mat-menu
|
||||||
<div
|
#filterMenu="matMenu"
|
||||||
(mouseenter)="filterMouseEnter()"
|
(closed)="applyFilters()"
|
||||||
(mouseleave)="filterMouseLeave()"
|
[class]="secondaryFilters?.length > 0 ? 'padding-bottom-0' : ''"
|
||||||
[class.pb-24]="secondaryFilters?.length === 0"
|
xPosition="before"
|
||||||
>
|
>
|
||||||
|
<div (mouseenter)="filterMouseEnter()" (mouseleave)="filterMouseLeave()">
|
||||||
<div class="filter-menu-header">
|
<div class="filter-menu-header">
|
||||||
<div class="all-caps-label" translate="filter-menu.filter-types"></div>
|
<div class="all-caps-label" translate="filter-menu.filter-types"></div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
|
|||||||
@ -26,10 +26,6 @@
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::ng-deep .mat-menu-panel .mat-menu-content:not(:empty) {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
::ng-deep .filter-menu-checkbox {
|
::ng-deep .filter-menu-checkbox {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,26 @@
|
|||||||
<div class="wrapper">
|
<div class="label-header">
|
||||||
<div class="label-header space-between">
|
<div class="all-caps-label">{{ label }}</div>
|
||||||
<div class="all-caps-label">{{ label }}</div>
|
<div class="actions">
|
||||||
<div class="actions">
|
<div
|
||||||
<div
|
(click)="selectAll($event)"
|
||||||
(click)="selectAll($event)"
|
[translate]="'actions.all'"
|
||||||
[translate]="'actions.all'"
|
class="all-caps-label primary pointer"
|
||||||
class="all-caps-label primary pointer"
|
></div>
|
||||||
></div>
|
<div
|
||||||
<div
|
(click)="deselectAll($event)"
|
||||||
(click)="deselectAll($event)"
|
[translate]="'actions.none'"
|
||||||
[translate]="'actions.none'"
|
class="all-caps-label primary pointer"
|
||||||
class="all-caps-label primary pointer"
|
></div>
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-chip-list
|
|
||||||
[disabled]="disabled"
|
|
||||||
[multiple]="multiple"
|
|
||||||
class="options flex-center"
|
|
||||||
selectable
|
|
||||||
>
|
|
||||||
<mat-chip
|
|
||||||
#chip="matChip"
|
|
||||||
(click)="toggleSelection(chip)"
|
|
||||||
*ngFor="let option of options"
|
|
||||||
[value]="option"
|
|
||||||
>
|
|
||||||
{{ translatePrefix + option | translate }}
|
|
||||||
</mat-chip>
|
|
||||||
</mat-chip-list>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<mat-chip-list [disabled]="disabled" [multiple]="multiple" class="options flex-center" selectable>
|
||||||
|
<mat-chip
|
||||||
|
#chip="matChip"
|
||||||
|
(click)="toggleSelection(chip)"
|
||||||
|
*ngFor="let option of options"
|
||||||
|
[value]="option"
|
||||||
|
>
|
||||||
|
{{ translatePrefix + option | translate }}
|
||||||
|
</mat-chip>
|
||||||
|
</mat-chip-list>
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
@import 'apps/red-ui/src/assets/styles/red-variables';
|
@import 'apps/red-ui/src/assets/styles/red-variables';
|
||||||
|
|
||||||
.wrapper {
|
:host {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid $grey-5;
|
border: 1px solid $grey-5;
|
||||||
height: 100%;
|
min-height: 100%;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
&.ng-invalid {
|
||||||
|
border-color: rgba($red-1, 0.3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-header {
|
.label-header {
|
||||||
padding: 16px 16px 14px 16px;
|
padding: 16px 16px 14px 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -48,6 +55,7 @@ mat-chip {
|
|||||||
background-color: $white;
|
background-color: $white;
|
||||||
color: $grey-1;
|
color: $grey-1;
|
||||||
margin: 0 0 2px 0;
|
margin: 0 0 2px 0;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $grey-8;
|
background-color: $grey-8;
|
||||||
|
|||||||
@ -23,6 +23,7 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor {
|
|||||||
@Input() multiple = true;
|
@Input() multiple = true;
|
||||||
|
|
||||||
@ViewChild(MatChipList) chipList: MatChipList;
|
@ViewChild(MatChipList) chipList: MatChipList;
|
||||||
|
|
||||||
private _value: string[] = [];
|
private _value: string[] = [];
|
||||||
private _onChange: (value: string[]) => void;
|
private _onChange: (value: string[]) => void;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
<div [translate]="title" class="all-caps-label"></div>
|
||||||
|
|
||||||
|
<ng-content></ng-content>
|
||||||
@ -3,16 +3,18 @@
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
max-width: 200px;
|
||||||
background-color: $grey-2;
|
background-color: $grey-2;
|
||||||
border-right: 1px solid $separator;
|
border-right: 1px solid $separator;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
.all-caps-label {
|
.all-caps-label {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
::ng-deep.item {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: 9px 16px;
|
padding: 9px 16px;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'redaction-side-nav',
|
||||||
|
templateUrl: './side-nav.component.html',
|
||||||
|
styleUrls: ['./side-nav.component.scss']
|
||||||
|
})
|
||||||
|
export class SideNavComponent {
|
||||||
|
@Input() title: string;
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
}
|
||||||
@ -22,7 +22,8 @@ export class DictionarySaveService {
|
|||||||
initialEntries: string[],
|
initialEntries: string[],
|
||||||
ruleSetId: string,
|
ruleSetId: string,
|
||||||
type: string,
|
type: string,
|
||||||
dossierId: string
|
dossierId: string,
|
||||||
|
showToast = true
|
||||||
): Observable<any> {
|
): Observable<any> {
|
||||||
let entriesToAdd = [];
|
let entriesToAdd = [];
|
||||||
entries.forEach((currentEntry) => {
|
entries.forEach((currentEntry) => {
|
||||||
@ -54,11 +55,15 @@ export class DictionarySaveService {
|
|||||||
return obs.pipe(
|
return obs.pipe(
|
||||||
tap(
|
tap(
|
||||||
() => {
|
() => {
|
||||||
this._notificationService.showToastNotification(
|
if (showToast) {
|
||||||
this._translateService.instant('dictionary-overview.success.generic'),
|
this._notificationService.showToastNotification(
|
||||||
null,
|
this._translateService.instant(
|
||||||
NotificationType.SUCCESS
|
'dictionary-overview.success.generic'
|
||||||
);
|
),
|
||||||
|
null,
|
||||||
|
NotificationType.SUCCESS
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this._notificationService.showToastNotification(
|
this._notificationService.showToastNotification(
|
||||||
@ -76,7 +81,7 @@ export class DictionarySaveService {
|
|||||||
NotificationType.ERROR
|
NotificationType.ERROR
|
||||||
);
|
);
|
||||||
|
|
||||||
return throwError('Entries to short');
|
return throwError('Entries too short');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ import { SelectComponent } from './components/select/select.component';
|
|||||||
import { NavigateLastProjectsScreenDirective } from './directives/navigate-last-projects-screen.directive';
|
import { NavigateLastProjectsScreenDirective } from './directives/navigate-last-projects-screen.directive';
|
||||||
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
|
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
|
||||||
import { AceEditorModule } from 'ng2-ace-editor';
|
import { AceEditorModule } from 'ng2-ace-editor';
|
||||||
|
import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
|
||||||
|
|
||||||
const buttons = [
|
const buttons = [
|
||||||
ChevronButtonComponent,
|
ChevronButtonComponent,
|
||||||
@ -60,6 +61,7 @@ const components = [
|
|||||||
SortByPipe,
|
SortByPipe,
|
||||||
RoundCheckboxComponent,
|
RoundCheckboxComponent,
|
||||||
SelectComponent,
|
SelectComponent,
|
||||||
|
SideNavComponent,
|
||||||
|
|
||||||
...buttons
|
...buttons
|
||||||
];
|
];
|
||||||
|
|||||||
@ -211,20 +211,6 @@ export class AppStateService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dictionaryVersion(ruleSetId?: string) {
|
|
||||||
if (!ruleSetId) {
|
|
||||||
ruleSetId = this.activeProject.ruleSetId;
|
|
||||||
}
|
|
||||||
return this._appState.versions[ruleSetId].dictionaryVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _rulesVersion(ruleSetId?: string) {
|
|
||||||
if (!ruleSetId) {
|
|
||||||
ruleSetId = this.activeProject.ruleSetId;
|
|
||||||
}
|
|
||||||
return this._appState.versions[ruleSetId].rulesVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
getDictionaryColor(type?: string, ruleSetId?: string) {
|
getDictionaryColor(type?: string, ruleSetId?: string) {
|
||||||
if (!ruleSetId && this.activeProject) {
|
if (!ruleSetId && this.activeProject) {
|
||||||
ruleSetId = this.activeProject.ruleSetId;
|
ruleSetId = this.activeProject.ruleSetId;
|
||||||
@ -457,8 +443,8 @@ export class AppStateService {
|
|||||||
this._notificationService.showToastNotification(
|
this._notificationService.showToastNotification(
|
||||||
this._translateService.instant(
|
this._translateService.instant(
|
||||||
error.status === 409
|
error.status === 409
|
||||||
? 'project-listing.add-edit-dialog.errors.project-already-exists'
|
? 'add-project-dialog.errors.project-already-exists'
|
||||||
: 'project-listing.add-edit-dialog.errors.generic'
|
: 'add-project-dialog.errors.generic'
|
||||||
),
|
),
|
||||||
null,
|
null,
|
||||||
NotificationType.ERROR
|
NotificationType.ERROR
|
||||||
@ -684,6 +670,20 @@ export class AppStateService {
|
|||||||
.toPromise();
|
.toPromise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _dictionaryVersion(ruleSetId?: string) {
|
||||||
|
if (!ruleSetId) {
|
||||||
|
ruleSetId = this.activeProject.ruleSetId;
|
||||||
|
}
|
||||||
|
return this._appState.versions[ruleSetId].dictionaryVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _rulesVersion(ruleSetId?: string) {
|
||||||
|
if (!ruleSetId) {
|
||||||
|
ruleSetId = this.activeProject.ruleSetId;
|
||||||
|
}
|
||||||
|
return this._appState.versions[ruleSetId].rulesVersion;
|
||||||
|
}
|
||||||
|
|
||||||
private _getExistingFiles(projectId: string) {
|
private _getExistingFiles(projectId: string) {
|
||||||
const found = this._appState.projects.find((p) => p.project.projectId === projectId);
|
const found = this._appState.projects.find((p) => p.project.projectId === projectId);
|
||||||
return found ? found.files : [];
|
return found ? found.files : [];
|
||||||
|
|||||||
@ -100,9 +100,6 @@
|
|||||||
"reanalyse": {
|
"reanalyse": {
|
||||||
"action": "Analysieren Sie das gesamte Dossier"
|
"action": "Analysieren Sie das gesamte Dossier"
|
||||||
},
|
},
|
||||||
"assign": {
|
|
||||||
"action": "Eigentümer zuweisen"
|
|
||||||
},
|
|
||||||
"download-files": {
|
"download-files": {
|
||||||
"action": "Laden Sie redigierte Dateien herunter"
|
"action": "Laden Sie redigierte Dateien herunter"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -100,9 +100,6 @@
|
|||||||
"reanalyse": {
|
"reanalyse": {
|
||||||
"action": "Analyze entire dossier"
|
"action": "Analyze entire dossier"
|
||||||
},
|
},
|
||||||
"assign": {
|
|
||||||
"action": "Assign Owner & Members"
|
|
||||||
},
|
|
||||||
"download-files": {
|
"download-files": {
|
||||||
"action": "Download Redacted Files"
|
"action": "Download Redacted Files"
|
||||||
},
|
},
|
||||||
@ -131,30 +128,6 @@
|
|||||||
"action": "New Dossier"
|
"action": "New Dossier"
|
||||||
},
|
},
|
||||||
"add-new": "New Dossier",
|
"add-new": "New Dossier",
|
||||||
"add-edit-dialog": {
|
|
||||||
"header-new": "Create Dossier",
|
|
||||||
"header-edit": "Edit Dossier",
|
|
||||||
"form": {
|
|
||||||
"name": {
|
|
||||||
"label": "Dossier Name",
|
|
||||||
"placeholder": "Enter Name"
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"label": "Description",
|
|
||||||
"placeholder": "Enter Description"
|
|
||||||
},
|
|
||||||
"due-date": "Due Date",
|
|
||||||
"template": "Dossier Template"
|
|
||||||
},
|
|
||||||
"errors": {
|
|
||||||
"project-already-exists": "Dossier with this name already exists!",
|
|
||||||
"generic": "Failed to save dossier"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"save": "Save",
|
|
||||||
"save-and-add-members": "Save and Edit Team"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"header": "Dossiers",
|
"header": "Dossiers",
|
||||||
"edit": {
|
"edit": {
|
||||||
"action": "Edit Dossier"
|
"action": "Edit Dossier"
|
||||||
@ -167,6 +140,67 @@
|
|||||||
"title": "No dossiers match your current filters."
|
"title": "No dossiers match your current filters."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"add-project-dialog": {
|
||||||
|
"header-new": "Create Dossier",
|
||||||
|
"form": {
|
||||||
|
"name": {
|
||||||
|
"label": "Dossier Name",
|
||||||
|
"placeholder": "Enter Name"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description",
|
||||||
|
"placeholder": "Enter Description"
|
||||||
|
},
|
||||||
|
"due-date": "Due Date",
|
||||||
|
"template": "Dossier Template"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"project-already-exists": "Dossier with this name already exists!",
|
||||||
|
"generic": "Failed to save dossier"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"save": "Save",
|
||||||
|
"save-and-add-members": "Save and Edit Team"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"edit-project-dialog": {
|
||||||
|
"header": "Edit {{projectName}}",
|
||||||
|
"nav-items": {
|
||||||
|
"dossier-info": "Dossier Info",
|
||||||
|
"general-info": "General Information",
|
||||||
|
"download-package": "Download Package",
|
||||||
|
"choose-download": "Choose what is included at download:",
|
||||||
|
"dictionary": "Dictionary",
|
||||||
|
"dossier-dictionary": "Dossier Dictionary",
|
||||||
|
"members": "Members",
|
||||||
|
"team-members": "Team Members",
|
||||||
|
"project-attributes": "Dossier Attributes",
|
||||||
|
"report-attributes": "Report Attributes"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"save": "Save Changes",
|
||||||
|
"revert": "Revert"
|
||||||
|
},
|
||||||
|
"general-info": {
|
||||||
|
"form": {
|
||||||
|
"name": {
|
||||||
|
"label": "Dossier Name",
|
||||||
|
"placeholder": "Enter Name"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"label": "Description",
|
||||||
|
"placeholder": "Enter Description"
|
||||||
|
},
|
||||||
|
"due-date": "Due Date",
|
||||||
|
"template": "Dossier Template"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dictionary": {
|
||||||
|
"entries": "{{length}} entries"
|
||||||
|
},
|
||||||
|
"unsaved-changes": "You have unsaved changes. Save or revert before changing the tab.",
|
||||||
|
"change-successful": "Project was updated."
|
||||||
|
},
|
||||||
"project-details": {
|
"project-details": {
|
||||||
"title": "Dossier Details",
|
"title": "Dossier Details",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -368,29 +402,7 @@
|
|||||||
"success": "Redaction added!",
|
"success": "Redaction added!",
|
||||||
"error": "Failed to save redaction: {{error}}"
|
"error": "Failed to save redaction: {{error}}"
|
||||||
},
|
},
|
||||||
"decline": {
|
"search": "Document name..."
|
||||||
"success": "Redaction suggestion declined!",
|
|
||||||
"error": "Failed to decline redaction: {{error}}"
|
|
||||||
},
|
|
||||||
"approve": {
|
|
||||||
"success": "Redaction suggestion approved!",
|
|
||||||
"error": "Failed to approved redaction: {{error}}"
|
|
||||||
},
|
|
||||||
"request-remove": {
|
|
||||||
"success": "Requested to remove redaction!",
|
|
||||||
"error": "Failed to request removal of redaction: {{error}}"
|
|
||||||
},
|
|
||||||
"assign-reviewer": "Assign Reviewer",
|
|
||||||
"assign-approver": "Assign Approver",
|
|
||||||
"assign-me": "Assign To Me",
|
|
||||||
"table-header": {
|
|
||||||
"title": "{{length}} documents",
|
|
||||||
"bulk-select": "Toggle Selection"
|
|
||||||
},
|
|
||||||
"remove": {
|
|
||||||
"success": "Redaction removed!",
|
|
||||||
"error": "Failed to remove redaction: {{error}}"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"dictionary": {
|
"dictionary": {
|
||||||
"undo": {
|
"undo": {
|
||||||
|
|||||||
@ -12,7 +12,11 @@
|
|||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.no-padding-bottom .mat-menu-content:not(:empty) {
|
&.padding-bottom-0 .mat-menu-content:not(:empty) {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.padding-bottom-8 .mat-menu-content:not(:empty) {
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ section.settings {
|
|||||||
width: calc(100vw - 200px);
|
width: calc(100vw - 200px);
|
||||||
}
|
}
|
||||||
|
|
||||||
redaction-side-nav {
|
redaction-admin-side-nav {
|
||||||
height: calc(100vh - 61px);
|
height: calc(100vh - 61px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,11 +330,14 @@ section.settings {
|
|||||||
margin-right: 8px !important;
|
margin-right: 8px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mr-16 {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.fit-content {
|
.fit-content {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.space-between {
|
.d-flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,6 +76,7 @@ pre {
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
|
font-weight: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-action {
|
.link-action {
|
||||||
|
|||||||
@ -31,11 +31,11 @@
|
|||||||
|
|
||||||
&.warn {
|
&.warn {
|
||||||
background-color: $yellow-2;
|
background-color: $yellow-2;
|
||||||
color: $accent;
|
color: $accent !important;
|
||||||
|
|
||||||
&:after {
|
//&:after {
|
||||||
border-top: solid 6px $yellow-2;
|
// border-top: solid 6px $yellow-2;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user