New edit project dialog WIP
This commit is contained in:
parent
0df0c5eebe
commit
ddd5f86e3f
@ -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';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-side-nav',
|
||||
templateUrl: './side-nav.component.html',
|
||||
styleUrls: ['./side-nav.component.scss']
|
||||
selector: 'redaction-admin-side-nav',
|
||||
templateUrl: './admin-side-nav.component.html',
|
||||
styleUrls: ['./admin-side-nav.component.scss']
|
||||
})
|
||||
export class SideNavComponent {
|
||||
export class AdminSideNavComponent {
|
||||
@Input() type: 'settings' | 'project-templates';
|
||||
|
||||
items: { [key: string]: { screen: string; onlyDevMode?: boolean; onlyAdmin?: boolean; userManagerOnly?: boolean; label?: string }[] } = {
|
||||
@ -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 { 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 { SideNavComponent } from './components/side-nav/side-nav.component';
|
||||
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||
|
||||
const dialogs = [
|
||||
AddEditRuleSetDialogComponent,
|
||||
@ -43,7 +43,8 @@ const dialogs = [
|
||||
SmtpAuthDialogComponent,
|
||||
AddEditUserDialogComponent,
|
||||
ConfirmDeleteUsersDialogComponent,
|
||||
FileAttributesCsvImportDialogComponent
|
||||
FileAttributesCsvImportDialogComponent,
|
||||
AdminSideNavComponent
|
||||
];
|
||||
|
||||
const screens = [
|
||||
@ -68,7 +69,6 @@ const components = [
|
||||
ComboSeriesVerticalComponent,
|
||||
UsersStatsComponent,
|
||||
ActiveFieldsListingComponent,
|
||||
SideNavComponent,
|
||||
|
||||
...dialogs,
|
||||
...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>
|
||||
@ -56,19 +56,18 @@
|
||||
</div>
|
||||
|
||||
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
||||
<div class="space-between">
|
||||
<div class="d-flex">
|
||||
<redaction-select
|
||||
[label]="'report-type.label' | translate: { length: this.ruleSetForm.controls['reportTypes'].value.length }"
|
||||
[options]="reportTypesEnum"
|
||||
[translatePrefix]="'report-type.'"
|
||||
class="w-410"
|
||||
class="mr-16"
|
||||
formControlName="reportTypes"
|
||||
></redaction-select>
|
||||
<redaction-select
|
||||
[label]="'download-type.label' | translate: { length: this.ruleSetForm.controls['downloadFileTypes'].value.length }"
|
||||
[options]="downloadTypesEnum"
|
||||
[translatePrefix]="'download-type.'"
|
||||
class="w-410"
|
||||
formControlName="downloadFileTypes"
|
||||
></redaction-select>
|
||||
</div>
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.w-410 {
|
||||
width: 410px;
|
||||
redaction-select {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.download-includes {
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<redaction-chevron-button [matMenuTriggerFor]="typeMenu" text="file-attributes-csv-import.table-header.actions.type"></redaction-chevron-button>
|
||||
|
||||
<mat-menu #readOnlyMenu="matMenu" class="no-padding-bottom">
|
||||
<mat-menu #readOnlyMenu="matMenu" class="padding-bottom-8">
|
||||
<button
|
||||
(click)="setAttributeForSelection('readonly', true)"
|
||||
mat-menu-item
|
||||
@ -44,7 +44,7 @@
|
||||
></button>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #typeMenu="matMenu" class="no-padding-bottom">
|
||||
<mat-menu #typeMenu="matMenu" class="padding-bottom-8">
|
||||
<button (click)="setAttributeForSelection('type', type)" *ngFor="let type of typeOptions" mat-menu-item>
|
||||
{{ 'file-attribute-types.' + type | translate }}
|
||||
</button>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="red-content-inner">
|
||||
<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="header-item">
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="red-content-inner">
|
||||
<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="header-item">
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
<div class="flex red-content-inner">
|
||||
<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
|
||||
[initialDictionaryEntries]="entries"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<div class="red-content-inner">
|
||||
<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="header-item">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="red-content-inner">
|
||||
<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">
|
||||
<ace-editor
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<section class="settings">
|
||||
<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 class="page-header">
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<div class="red-content-inner">
|
||||
<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 #viewer class="viewer"></div>
|
||||
|
||||
@ -1,24 +1,16 @@
|
||||
<section class="dialog">
|
||||
<form (submit)="saveProject()" [formGroup]="projectForm">
|
||||
<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-header heading-l" translate="add-project-dialog.header-new"></div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<div class="red-input-group required w-300">
|
||||
<label translate="project-listing.add-edit-dialog.form.name.label"></label>
|
||||
<input
|
||||
[placeholder]="'project-listing.add-edit-dialog.form.name.placeholder' | translate"
|
||||
formControlName="projectName"
|
||||
name="projectName"
|
||||
type="text"
|
||||
/>
|
||||
<label translate="add-project-dialog.form.name.label"></label>
|
||||
<input [placeholder]="'add-project-dialog.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>{{ 'project-listing.add-edit-dialog.form.template' | translate }}</mat-label>
|
||||
<mat-label>{{ 'add-project-dialog.form.template' | translate }}</mat-label>
|
||||
<mat-select (valueChange)="ruleSetChanged($event)" formControlName="ruleSetId" style="width: 100%">
|
||||
<mat-option
|
||||
*ngFor="let ruleSet of ruleSets"
|
||||
@ -33,9 +25,9 @@
|
||||
</div>
|
||||
|
||||
<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
|
||||
[placeholder]="'project-listing.add-edit-dialog.form.description.placeholder' | translate"
|
||||
[placeholder]="'add-project-dialog.form.description.placeholder' | translate"
|
||||
formControlName="description"
|
||||
name="description"
|
||||
redactionHasScrollbar
|
||||
@ -46,7 +38,7 @@
|
||||
|
||||
<div class="due-date">
|
||||
<mat-checkbox (change)="hasDueDate = !hasDueDate" [checked]="hasDueDate" class="filter-menu-checkbox" color="primary">
|
||||
{{ 'project-listing.add-edit-dialog.form.due-date' | translate }}
|
||||
{{ 'add-project-dialog.form.due-date' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
<div *ngIf="hasDueDate" class="red-input-group datepicker-wrapper">
|
||||
@ -59,35 +51,33 @@
|
||||
</div>
|
||||
|
||||
<p class="download-includes">{{ 'download-includes' | translate }}</p>
|
||||
<div class="space-between">
|
||||
<div class="d-flex">
|
||||
<redaction-select
|
||||
[label]="'report-type.label' | translate: { length: reportTypesLength }"
|
||||
[options]="reportTypesEnum"
|
||||
[translatePrefix]="'report-type.'"
|
||||
class="w-410"
|
||||
class="mr-16"
|
||||
formControlName="reportTypes"
|
||||
></redaction-select>
|
||||
<redaction-select
|
||||
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
||||
[options]="downloadTypesEnum"
|
||||
[translatePrefix]="'download-type.'"
|
||||
class="w-410"
|
||||
formControlName="downloadFileTypes"
|
||||
></redaction-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button [disabled]="disabled || !changed" color="primary" mat-flat-button type="submit">
|
||||
{{ 'project-listing.add-edit-dialog.actions.save' | translate }}
|
||||
<button [disabled]="disabled" color="primary" mat-flat-button type="submit">
|
||||
{{ 'add-project-dialog.actions.save' | translate }}
|
||||
</button>
|
||||
|
||||
<redaction-icon-button
|
||||
(action)="saveProjectAndAddMembers()"
|
||||
*ngIf="!project?.projectId"
|
||||
[disabled]="disabled || !changed"
|
||||
[disabled]="disabled"
|
||||
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"
|
||||
></redaction-icon-button>
|
||||
</div>
|
||||
@ -13,11 +13,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.w-410 {
|
||||
width: 410px;
|
||||
}
|
||||
|
||||
.download-includes {
|
||||
margin: 16px 0 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
redaction-select {
|
||||
flex: 1;
|
||||
}
|
||||
@ -1,19 +1,18 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Component } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { Project, 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 * as moment from 'moment';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-project-dialog',
|
||||
templateUrl: './add-edit-project-dialog.component.html',
|
||||
styleUrls: ['./add-edit-project-dialog.component.scss']
|
||||
selector: 'redaction-add-project-dialog',
|
||||
templateUrl: './add-project-dialog.component.html',
|
||||
styleUrls: ['./add-project-dialog.component.scss']
|
||||
})
|
||||
export class AddEditProjectDialogComponent {
|
||||
export class AddProjectDialogComponent {
|
||||
projectForm: FormGroup;
|
||||
hasDueDate: boolean;
|
||||
hasDueDate = false;
|
||||
downloadTypesEnum = ['ORIGINAL', 'PREVIEW', 'REDACTED'];
|
||||
reportTypesEnum = Object.values(RuleSetModel.ReportTypesEnum);
|
||||
ruleSets: RuleSetModel[];
|
||||
@ -21,19 +20,17 @@ export class AddEditProjectDialogComponent {
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
public dialogRef: MatDialogRef<AddEditProjectDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public project: ProjectWrapper
|
||||
public dialogRef: MatDialogRef<AddProjectDialogComponent>
|
||||
) {
|
||||
this._filterInvalidRuleSets();
|
||||
this.projectForm = this._formBuilder.group({
|
||||
projectName: [this.project?.projectName, Validators.required],
|
||||
ruleSetId: [{ value: this.project?.ruleSetId, disabled: this.project?.hasFiles }, Validators.required],
|
||||
downloadFileTypes: [this.project?.project?.downloadFileTypes],
|
||||
reportTypes: [this.project?.project?.reportTypes, Validators.required],
|
||||
description: [this.project?.description],
|
||||
dueDate: [this.project?.dueDate]
|
||||
projectName: [null, Validators.required],
|
||||
ruleSetId: [null, Validators.required],
|
||||
downloadFileTypes: [null],
|
||||
reportTypes: [null, Validators.required],
|
||||
description: [null],
|
||||
dueDate: [null]
|
||||
});
|
||||
this.hasDueDate = !!this.project?.dueDate;
|
||||
}
|
||||
|
||||
get reportTypesLength() {
|
||||
@ -44,31 +41,6 @@ export class AddEditProjectDialogComponent {
|
||||
return this.projectForm.controls['downloadFileTypes']?.value?.length ? this.projectForm.controls['downloadFileTypes'].value.length : 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() {
|
||||
if (this.hasDueDate && this.projectForm.get('dueDate').value === null) {
|
||||
return true;
|
||||
@ -79,7 +51,6 @@ export class AddEditProjectDialogComponent {
|
||||
|
||||
async saveProject() {
|
||||
const project: Project = this._formToObject();
|
||||
project.projectId = this.project?.projectId;
|
||||
|
||||
const foundProject = this._appStateService.allProjects.find((p) => p.project.projectId === project.projectId);
|
||||
if (foundProject) {
|
||||
@ -94,7 +65,6 @@ export class AddEditProjectDialogComponent {
|
||||
|
||||
async saveProjectAndAddMembers() {
|
||||
const project: Project = this._formToObject();
|
||||
project.projectId = this.project?.projectId;
|
||||
const savedProject = await this._appStateService.addOrUpdateProject(project);
|
||||
if (savedProject) {
|
||||
this.dialogRef.close({ addMembers: true, project: savedProject });
|
||||
@ -102,28 +72,22 @@ export class AddEditProjectDialogComponent {
|
||||
}
|
||||
|
||||
ruleSetChanged(ruleSetId) {
|
||||
// if project doesn't yet exist -> add mode
|
||||
if (!this.project?.projectId) {
|
||||
// get current selected ruleSet
|
||||
const ruleSet = this.ruleSets.find((r) => r.ruleSetId === ruleSetId);
|
||||
if (ruleSet) {
|
||||
// update dropdown values
|
||||
this.projectForm.patchValue(
|
||||
{
|
||||
downloadFileTypes: ruleSet.downloadFileTypes,
|
||||
reportTypes: ruleSet.reportTypes
|
||||
},
|
||||
{ emitEvent: false }
|
||||
);
|
||||
}
|
||||
// get current selected ruleSet
|
||||
const ruleSet = this.ruleSets.find((r) => r.ruleSetId === ruleSetId);
|
||||
if (ruleSet) {
|
||||
// update dropdown values
|
||||
this.projectForm.patchValue(
|
||||
{
|
||||
downloadFileTypes: ruleSet.downloadFileTypes,
|
||||
reportTypes: ruleSet.reportTypes
|
||||
},
|
||||
{ emitEvent: false }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _filterInvalidRuleSets() {
|
||||
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 notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
|
||||
return !(notYetValid || notValidAnymore);
|
||||
@ -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,78 @@
|
||||
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,42 @@
|
||||
<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 [translate]="'edit-project-dialog.nav-items.' + (activeNavItem.title || activeNavItem.key)" class="heading"></div>
|
||||
|
||||
<redaction-edit-project-general-info
|
||||
(updateProject)="updatedProject($event)"
|
||||
*ngIf="activeNav === 'project-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>
|
||||
</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,25 @@
|
||||
@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% - 129px);
|
||||
|
||||
.heading {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
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';
|
||||
|
||||
@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: 'project-info', title: 'general-info' },
|
||||
{ key: 'download-package', title: 'choose-download' }
|
||||
// { key: 'project-dictionary' }
|
||||
// TODO:
|
||||
// { key: 'project-attributes' },
|
||||
// { key: 'report-attributes' }
|
||||
];
|
||||
activeNav = 'project-info';
|
||||
projectWrapper: ProjectWrapper;
|
||||
|
||||
@ViewChild(EditProjectGeneralInfoComponent) generalInfoComponent: EditProjectGeneralInfoComponent;
|
||||
@ViewChild(EditProjectDownloadPackageComponent) downloadPackageComponent: EditProjectDownloadPackageComponent;
|
||||
|
||||
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 {
|
||||
'project-info': this.generalInfoComponent,
|
||||
'download-package': this.downloadPackageComponent
|
||||
}[this.activeNav];
|
||||
}
|
||||
|
||||
updatedProject(updatedProject: ProjectWrapper) {
|
||||
this._notificationService.showToastNotification(
|
||||
this._translateService.instant('edit-project-dialog.change-successful'),
|
||||
null,
|
||||
NotificationType.SUCCESS
|
||||
);
|
||||
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,53 @@
|
||||
<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,98 @@
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
|
||||
import { ProjectListingScreenComponent } from './screens/project-listing-screen/project-listing-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 { 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 { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||
@ -37,12 +37,16 @@ import { AnnotationDrawService } from './services/annotation-draw.service';
|
||||
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
||||
import { AnnotationRemoveActionsComponent } from './components/annotation-remove-actions/annotation-remove-actions.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';
|
||||
|
||||
const screens = [ProjectListingScreenComponent, ProjectOverviewScreenComponent, FilePreviewScreenComponent];
|
||||
|
||||
const dialogs = [
|
||||
AddEditProjectDialogComponent,
|
||||
AddProjectDialogComponent,
|
||||
EditProjectDialogComponent,
|
||||
AssignOwnerDialogComponent,
|
||||
ManualAnnotationDialogComponent,
|
||||
ForceRedactionDialogComponent,
|
||||
@ -68,6 +72,8 @@ const components = [
|
||||
DocumentInfoComponent,
|
||||
FileWorkloadComponent,
|
||||
AnnotationRemoveActionsComponent,
|
||||
EditProjectGeneralInfoComponent,
|
||||
EditProjectDownloadPackageComponent,
|
||||
|
||||
...screens,
|
||||
...dialogs
|
||||
|
||||
@ -68,10 +68,6 @@
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mr-16 {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.ml-8 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
@ -80,10 +80,6 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
return this._appStateService.activeProject;
|
||||
}
|
||||
|
||||
isLastOpenedFile(fileStatus: FileStatusWrapper): boolean {
|
||||
return this._lastOpenedFileId === fileStatus.fileId;
|
||||
}
|
||||
|
||||
protected get _filterComponents(): FilterComponent[] {
|
||||
return [this._statusFilterComponent, this._peopleFilterComponent, this._needsWorkFilterComponent];
|
||||
}
|
||||
@ -101,11 +97,17 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent<FileSta
|
||||
];
|
||||
}
|
||||
|
||||
isLastOpenedFile(fileStatus: FileStatusWrapper): boolean {
|
||||
return this._lastOpenedFileId === fileStatus.fileId;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._userPreferenceControllerService.getAllUserAttributes().subscribe((attributes) => {
|
||||
if (attributes === null || attributes === undefined) return;
|
||||
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();
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
ManualRedactionControllerService,
|
||||
RuleSetControllerService
|
||||
} 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 { NotificationService, NotificationType } from '@services/notification.service';
|
||||
import { ForceRedactionDialogComponent } from '../dialogs/force-redaction-dialog/force-redaction-dialog.component';
|
||||
@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
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 { EditProjectDialogComponent } from '../dialogs/edit-project-dialog/edit-project-dialog.component';
|
||||
import { FileStatusWrapper } from '../../../models/file/file-status.wrapper';
|
||||
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||
|
||||
@ -123,22 +124,6 @@ export class ProjectsDialogService {
|
||||
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($event: MouseEvent, cb?: Function): MatDialogRef<ForceRedactionDialogComponent> {
|
||||
$event?.stopPropagation();
|
||||
const ref = this._dialog.open(ForceRedactionDialogComponent, {
|
||||
@ -252,9 +237,10 @@ export class ProjectsDialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
openAddProjectDialog(cb?: Function): MatDialogRef<AddEditProjectDialogComponent> {
|
||||
const ref = this._dialog.open(AddEditProjectDialogComponent, {
|
||||
openAddProjectDialog(cb?: Function): MatDialogRef<AddProjectDialogComponent> {
|
||||
const ref = this._dialog.open(AddProjectDialogComponent, {
|
||||
...dialogConfig,
|
||||
width: '900px',
|
||||
autoFocus: true
|
||||
});
|
||||
|
||||
@ -265,6 +251,17 @@ export class ProjectsDialogService {
|
||||
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(file: FileStatus, cb?: Function): MatDialogRef<DocumentInfoDialogComponent> {
|
||||
const ref = this._dialog.open(DocumentInfoDialogComponent, {
|
||||
...dialogConfig,
|
||||
|
||||
@ -49,11 +49,6 @@
|
||||
margin-right: 32px;
|
||||
}
|
||||
|
||||
.mr-16 {
|
||||
margin-right: 16px;
|
||||
//opacity: 0; // TODO: Hidden for now
|
||||
}
|
||||
|
||||
.red-input-group {
|
||||
input {
|
||||
padding-right: 32px;
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
<redaction-chevron-button *ngIf="chevron" [matMenuTriggerFor]="filterMenu" [showDot]="hasActiveFilters" [text]="filterLabel"></redaction-chevron-button>
|
||||
|
||||
<mat-menu #filterMenu="matMenu" (closed)="applyFilters()" xPosition="before">
|
||||
<div (mouseenter)="filterMouseEnter()" (mouseleave)="filterMouseLeave()" [class.pb-24]="secondaryFilters?.length === 0">
|
||||
<mat-menu #filterMenu="matMenu" (closed)="applyFilters()" [class]="secondaryFilters?.length > 0 ? 'padding-bottom-0' : ''" xPosition="before">
|
||||
<div (mouseenter)="filterMouseEnter()" (mouseleave)="filterMouseLeave()">
|
||||
<div class="filter-menu-header">
|
||||
<div class="all-caps-label" translate="filter-menu.filter-types"></div>
|
||||
<div class="actions">
|
||||
|
||||
@ -26,10 +26,6 @@
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
::ng-deep .mat-menu-panel .mat-menu-content:not(:empty) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
::ng-deep .filter-menu-checkbox {
|
||||
width: 100%;
|
||||
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
<div class="wrapper">
|
||||
<div class="label-header space-between">
|
||||
<div class="all-caps-label">{{ label }}</div>
|
||||
<div class="actions">
|
||||
<div (click)="selectAll($event)" [translate]="'actions.all'" class="all-caps-label primary pointer"></div>
|
||||
<div (click)="deselectAll($event)" [translate]="'actions.none'" class="all-caps-label primary pointer"></div>
|
||||
</div>
|
||||
<div class="label-header">
|
||||
<div class="all-caps-label">{{ label }}</div>
|
||||
<div class="actions">
|
||||
<div (click)="selectAll($event)" [translate]="'actions.all'" class="all-caps-label primary pointer"></div>
|
||||
<div (click)="deselectAll($event)" [translate]="'actions.none'" class="all-caps-label primary pointer"></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>
|
||||
|
||||
<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';
|
||||
|
||||
.wrapper {
|
||||
:host {
|
||||
border-radius: 8px;
|
||||
border: 1px solid $grey-5;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
display: block;
|
||||
|
||||
&.ng-invalid {
|
||||
border-color: rgba($red-1, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.label-header {
|
||||
padding: 16px 16px 14px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
@ -48,6 +55,7 @@ mat-chip {
|
||||
background-color: $white;
|
||||
color: $grey-1;
|
||||
margin: 0 0 2px 0;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: $grey-8;
|
||||
|
||||
@ -23,6 +23,7 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor {
|
||||
@Input() multiple = true;
|
||||
|
||||
@ViewChild(MatChipList) chipList: MatChipList;
|
||||
|
||||
private _value: string[] = [];
|
||||
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 {
|
||||
display: block;
|
||||
min-width: 200px;
|
||||
max-width: 200px;
|
||||
background-color: $grey-2;
|
||||
border-right: 1px solid $separator;
|
||||
box-sizing: border-box;
|
||||
padding: 8px;
|
||||
height: 100%;
|
||||
|
||||
.all-caps-label {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.item {
|
||||
::ng-deep.item {
|
||||
margin-bottom: 4px;
|
||||
border-radius: 20px;
|
||||
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() {}
|
||||
}
|
||||
@ -34,6 +34,7 @@ import { SelectComponent } from './components/select/select.component';
|
||||
import { NavigateLastProjectsScreenDirective } from './directives/navigate-last-projects-screen.directive';
|
||||
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
|
||||
import { AceEditorModule } from 'ng2-ace-editor';
|
||||
import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
|
||||
|
||||
const buttons = [ChevronButtonComponent, CircleButtonComponent, FileDownloadBtnComponent, IconButtonComponent, UserButtonComponent];
|
||||
|
||||
@ -54,6 +55,7 @@ const components = [
|
||||
SortByPipe,
|
||||
RoundCheckboxComponent,
|
||||
SelectComponent,
|
||||
SideNavComponent,
|
||||
|
||||
...buttons
|
||||
];
|
||||
|
||||
@ -196,20 +196,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) {
|
||||
if (!ruleSetId && this.activeProject) {
|
||||
ruleSetId = this.activeProject.ruleSetId;
|
||||
@ -421,9 +407,7 @@ export class AppStateService {
|
||||
return foundProject;
|
||||
} catch (error) {
|
||||
this._notificationService.showToastNotification(
|
||||
this._translateService.instant(
|
||||
error.status === 409 ? 'project-listing.add-edit-dialog.errors.project-already-exists' : 'project-listing.add-edit-dialog.errors.generic'
|
||||
),
|
||||
this._translateService.instant(error.status === 409 ? 'add-project-dialog.errors.project-already-exists' : 'add-project-dialog.errors.generic'),
|
||||
null,
|
||||
NotificationType.ERROR
|
||||
);
|
||||
@ -633,6 +617,20 @@ export class AppStateService {
|
||||
project.dictionaryVersion = await this._versionsControllerService.getDossierDictionaryVersion(project.projectId, project.ruleSetId).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) {
|
||||
const found = this._appState.projects.find((p) => p.project.projectId === projectId);
|
||||
return found ? found.files : [];
|
||||
|
||||
@ -131,30 +131,6 @@
|
||||
"action": "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",
|
||||
"edit": {
|
||||
"action": "Edit Dossier"
|
||||
@ -167,6 +143,61 @@
|
||||
"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": {
|
||||
"project-info": "Project Info",
|
||||
"general-info": "General Information",
|
||||
"download-package": "Download Package",
|
||||
"choose-download": "Choose what is included at download:",
|
||||
"project-dictionary": "Project Dictionary",
|
||||
"project-attributes": "Project 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"
|
||||
}
|
||||
},
|
||||
"unsaved-changes": "You have unsaved changes. Save or revert before changing the tab.",
|
||||
"change-successful": "Project was updated."
|
||||
},
|
||||
"project-details": {
|
||||
"title": "Dossier Details",
|
||||
"dialog": {
|
||||
|
||||
@ -12,7 +12,11 @@
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ section.settings {
|
||||
width: calc(100vw - 200px);
|
||||
}
|
||||
|
||||
redaction-side-nav {
|
||||
redaction-admin-side-nav {
|
||||
height: calc(100vh - 61px);
|
||||
}
|
||||
}
|
||||
@ -330,11 +330,14 @@ section.settings {
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
||||
.mr-16 {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.fit-content {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.space-between {
|
||||
.d-flex {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user