Document info
This commit is contained in:
parent
f0056fee56
commit
9659cbe289
@ -118,6 +118,8 @@ import { SearchInputComponent } from './components/search-input/search-input.com
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { ConfirmDeleteFileAttributeDialogComponent } from './dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component';
|
||||
import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component';
|
||||
import { DocumentInfoComponent } from './components/document-info/document-info.component';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json');
|
||||
@ -222,7 +224,9 @@ const matImports = [
|
||||
FileAttributesListingScreenComponent,
|
||||
SearchInputComponent,
|
||||
AddEditFileAttributeDialogComponent,
|
||||
ConfirmDeleteFileAttributeDialogComponent
|
||||
ConfirmDeleteFileAttributeDialogComponent,
|
||||
DocumentInfoDialogComponent,
|
||||
DocumentInfoComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
<div class="right-title heading" translate="file-preview.tabs.document-info.label">
|
||||
<div>
|
||||
<redaction-circle-button
|
||||
icon="red:edit"
|
||||
(action)="closeDocumentInfoView.emit()"
|
||||
tooltipPosition="before"
|
||||
tooltip="file-preview.tabs.document-info.edit"
|
||||
></redaction-circle-button>
|
||||
<redaction-circle-button
|
||||
icon="red:close"
|
||||
(action)="closeDocumentInfoView.emit()"
|
||||
tooltipPosition="before"
|
||||
tooltip="file-preview.tabs.document-info.close"
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
Attributes go here
|
||||
</div>
|
||||
|
||||
<div class="section small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:folder"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.project' | translate: { projectName: project.name } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:document"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.pages' | translate: { pages: file.numberOfPages } }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.created-on' | translate: { date: file.added | date: 'mediumDate' } }}</span>
|
||||
</div>
|
||||
<div *ngIf="project.project.dueDate">
|
||||
<mat-icon svgIcon="red:lightning"></mat-icon>
|
||||
<span>{{ 'file-preview.tabs.document-info.details.due' | translate: { date: project.project.dueDate | date: 'mediumDate' } }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,22 @@
|
||||
@import '../../../assets/styles/red-variables';
|
||||
|
||||
.right-title > div {
|
||||
display: flex;
|
||||
|
||||
> redaction-circle-button:not(:last-child) {
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 25px;
|
||||
flex-direction: column;
|
||||
|
||||
> div {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $separator;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FileStatus } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-document-info',
|
||||
templateUrl: './document-info.component.html',
|
||||
styleUrls: ['./document-info.component.scss']
|
||||
})
|
||||
export class DocumentInfoComponent implements OnInit {
|
||||
@Input() file: FileStatus;
|
||||
@Output() closeDocumentInfoView = new EventEmitter();
|
||||
|
||||
constructor(private _appStateService: AppStateService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
public get project() {
|
||||
return this._appStateService.getProjectById(this.file.projectId);
|
||||
}
|
||||
}
|
||||
@ -49,6 +49,15 @@
|
||||
>
|
||||
</redaction-file-download-btn>
|
||||
|
||||
<redaction-circle-button
|
||||
*ngIf="screen === 'file-preview'"
|
||||
(action)="toggleViewDocumentInfo()"
|
||||
tooltip="file-preview.document-info"
|
||||
tooltipPosition="before"
|
||||
icon="red:status-info"
|
||||
[attr.aria-expanded]="activeDocumentInfo"
|
||||
></redaction-circle-button>
|
||||
|
||||
<!-- Ready for approval-->
|
||||
<redaction-circle-button
|
||||
(action)="setFileUnderApproval($event, fileStatus)"
|
||||
|
||||
@ -14,6 +14,7 @@ import { DEFAULT_RUL_SET_UUID } from '../../utils/rule-set-default';
|
||||
})
|
||||
export class FileActionsComponent implements OnInit {
|
||||
@Input() fileStatus: FileStatusWrapper;
|
||||
@Input() activeDocumentInfo: boolean;
|
||||
@Output() actionPerformed = new EventEmitter<string>();
|
||||
actionMenuOpen: boolean;
|
||||
|
||||
@ -40,6 +41,10 @@ export class FileActionsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public toggleViewDocumentInfo() {
|
||||
this.actionPerformed.emit('view-document-info');
|
||||
}
|
||||
|
||||
public get tooltipPosition() {
|
||||
return this.screen === 'file-preview' ? 'below' : 'above';
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ (fileAttribute ? 'add-edit-file-attribute.title.edit' : 'add-edit-file-attribute.title.new') | translate: { name: fileAttribute?.name } }}
|
||||
{{ (fileAttribute ? 'add-edit-file-attribute.title.edit' : 'add-edit-file-attribute.title.new') | translate: { name: fileAttribute?.label } }}
|
||||
</div>
|
||||
|
||||
<form (submit)="saveFileAttribute()" [formGroup]="fileAttributeForm">
|
||||
<div class="dialog-content">
|
||||
<div class="red-input-group required w-300">
|
||||
<label translate="add-edit-file-attribute.form.name"></label>
|
||||
<input formControlName="name" name="name" type="text" placeholder="{{ 'add-edit-file-attribute.form.name-placeholder' | translate }}" />
|
||||
<input formControlName="label" name="label" type="text" placeholder="{{ 'add-edit-file-attribute.form.name-placeholder' | translate }}" />
|
||||
</div>
|
||||
|
||||
<div class="red-input-group ignore-label-styles">
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { FileAttribute, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { FileAttributeConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { computerize } from '../../utils/functions';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-file-attribute-dialog',
|
||||
@ -11,7 +12,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
})
|
||||
export class AddEditFileAttributeDialogComponent {
|
||||
public fileAttributeForm: FormGroup;
|
||||
public fileAttribute: FileAttribute;
|
||||
public fileAttribute: FileAttributeConfig;
|
||||
public ruleSetId: string;
|
||||
|
||||
constructor(
|
||||
@ -19,13 +20,13 @@ export class AddEditFileAttributeDialogComponent {
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _fileAttributesService: FileAttributesControllerService,
|
||||
public dialogRef: MatDialogRef<AddEditFileAttributeDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: { fileAttribute: FileAttribute; ruleSetId: string }
|
||||
@Inject(MAT_DIALOG_DATA) public data: { fileAttribute: FileAttributeConfig; ruleSetId: string }
|
||||
) {
|
||||
this.fileAttribute = data.fileAttribute;
|
||||
this.ruleSetId = data.ruleSetId;
|
||||
|
||||
this.fileAttributeForm = this._formBuilder.group({
|
||||
name: [this.fileAttribute?.name, Validators.required],
|
||||
label: [this.fileAttribute?.label, Validators.required],
|
||||
readonly: [this.fileAttribute ? !this.fileAttribute.editable : false],
|
||||
visible: [this.fileAttribute?.visible]
|
||||
});
|
||||
@ -48,12 +49,13 @@ export class AddEditFileAttributeDialogComponent {
|
||||
}
|
||||
|
||||
async saveFileAttribute() {
|
||||
const fileAttribute = {
|
||||
const fileAttribute: FileAttributeConfig = {
|
||||
id: this.fileAttribute?.id,
|
||||
editable: !this.fileAttributeForm.get('readonly').value,
|
||||
csvColumnHeader: this.fileAttribute?.csvColumnHeader || computerize(this.fileAttributeForm.get('label').value),
|
||||
...this.fileAttributeForm.getRawValue()
|
||||
};
|
||||
await this._fileAttributesService.setFileAttributesConfiguration({ fileAttributes: [fileAttribute] }, this.ruleSetId).toPromise();
|
||||
await this._fileAttributesService.setFileAttributesConfiguration(fileAttribute, this.ruleSetId).toPromise();
|
||||
this.dialogRef.close(fileAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ 'confirm-delete-file-attribute.title' | translate: { name: fileAttribute.name } }}
|
||||
{{ 'confirm-delete-file-attribute.title' | translate: { name: fileAttribute.label } }}
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { FileAttribute, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { FileAttributeConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
@ -9,7 +9,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
styleUrls: ['./confirm-delete-file-attribute-dialog.component.scss']
|
||||
})
|
||||
export class ConfirmDeleteFileAttributeDialogComponent {
|
||||
public fileAttribute: FileAttribute;
|
||||
public fileAttribute: FileAttributeConfig;
|
||||
public ruleSetId: string;
|
||||
public checkboxes = [{ value: false }, { value: false }];
|
||||
|
||||
@ -17,7 +17,7 @@ export class ConfirmDeleteFileAttributeDialogComponent {
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _fileAttributesService: FileAttributesControllerService,
|
||||
public dialogRef: MatDialogRef<ConfirmDeleteFileAttributeDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: { fileAttribute: FileAttribute; ruleSetId: string }
|
||||
@Inject(MAT_DIALOG_DATA) public data: { fileAttribute: FileAttributeConfig; ruleSetId: string }
|
||||
) {
|
||||
this.fileAttribute = data.fileAttribute;
|
||||
this.ruleSetId = data.ruleSetId;
|
||||
|
||||
@ -3,7 +3,7 @@ import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
import {
|
||||
Colors,
|
||||
DictionaryControllerService,
|
||||
FileAttribute,
|
||||
FileAttributeConfig,
|
||||
FileManagementControllerService,
|
||||
FileStatus,
|
||||
ManualRedactionControllerService,
|
||||
@ -30,6 +30,7 @@ import { RemoveAnnotationsDialogComponent } from './remove-annotations-dialog/re
|
||||
import { ForceRedactionDialogComponent } from './force-redaction-dialog/force-redaction-dialog.component';
|
||||
import { AddEditFileAttributeDialogComponent } from './add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { ConfirmDeleteFileAttributeDialogComponent } from './confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component';
|
||||
import { DocumentInfoDialogComponent } from './document-info-dialog/document-info-dialog.component';
|
||||
|
||||
const dialogConfig = {
|
||||
width: '662px',
|
||||
@ -339,7 +340,11 @@ export class DialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public openAddEditFileAttributeDialog(fileAttribute: FileAttribute, ruleSetId: string, cb?: Function): MatDialogRef<AddEditFileAttributeDialogComponent> {
|
||||
public openAddEditFileAttributeDialog(
|
||||
fileAttribute: FileAttributeConfig,
|
||||
ruleSetId: string,
|
||||
cb?: Function
|
||||
): MatDialogRef<AddEditFileAttributeDialogComponent> {
|
||||
const ref = this._dialog.open(AddEditFileAttributeDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: { fileAttribute, ruleSetId },
|
||||
@ -356,7 +361,7 @@ export class DialogService {
|
||||
}
|
||||
|
||||
public openConfirmDeleteFileAttributeDialog(
|
||||
fileAttribute: FileAttribute,
|
||||
fileAttribute: FileAttributeConfig,
|
||||
ruleSetId: string,
|
||||
cb?: Function
|
||||
): MatDialogRef<ConfirmDeleteFileAttributeDialogComponent> {
|
||||
@ -375,6 +380,22 @@ export class DialogService {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public openDocumentInfoDialog(file: FileStatus, cb?: Function): MatDialogRef<DocumentInfoDialogComponent> {
|
||||
const ref = this._dialog.open(DocumentInfoDialogComponent, {
|
||||
...dialogConfig,
|
||||
data: file,
|
||||
autoFocus: true
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe((result) => {
|
||||
if (result && cb) {
|
||||
cb(result);
|
||||
}
|
||||
});
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
openRemoveAnnotationModal($event: MouseEvent, annotation: AnnotationWrapper, callback: () => void) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l" translate="document-info.title"></div>
|
||||
|
||||
<form (submit)="saveDocumentInfo()" [formGroup]="documentInfoForm">
|
||||
<div class="dialog-content">
|
||||
{{ file.filename }}
|
||||
<!-- <div class="red-input-group required w-300">-->
|
||||
<!-- <label translate="add-edit-file-attribute.form.name"></label>-->
|
||||
<!-- <input formControlName="name" name="name" type="text" placeholder="{{ 'add-edit-file-attribute.form.name-placeholder' | translate }}" />-->
|
||||
<!-- </div>-->
|
||||
|
||||
<!-- <div class="red-input-group ignore-label-styles">-->
|
||||
<!-- <mat-slide-toggle formControlName="readonly" color="primary">{{ 'add-edit-file-attribute.form.read-only' | translate }}</mat-slide-toggle>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<button [disabled]="documentInfoForm.invalid" color="primary" mat-flat-button type="submit">
|
||||
{{ 'document-info.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<redaction-circle-button icon="red:close" mat-dialog-close class="dialog-close"></redaction-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,36 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FileAttributesControllerService, FileStatus } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '../../state/app-state.service';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-document-info-dialog',
|
||||
templateUrl: './document-info-dialog.component.html',
|
||||
styleUrls: ['./document-info-dialog.component.scss']
|
||||
})
|
||||
export class DocumentInfoDialogComponent implements OnInit {
|
||||
public documentInfoForm: FormGroup;
|
||||
public file: FileStatus;
|
||||
|
||||
constructor(
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _fileAttributesService: FileAttributesControllerService,
|
||||
public dialogRef: MatDialogRef<DocumentInfoDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: FileStatus
|
||||
) {
|
||||
this.file = this.data;
|
||||
console.log(this.data);
|
||||
|
||||
this.documentInfoForm = this._formBuilder.group({
|
||||
// name: [this.fileAttribute?.name, Validators.required],
|
||||
// readonly: [this.fileAttribute ? !this.fileAttribute.editable : false],
|
||||
// visible: [this.fileAttribute?.visible]
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
public saveDocumentInfo() {}
|
||||
}
|
||||
@ -64,8 +64,9 @@ export class IconsModule {
|
||||
'sort-asc',
|
||||
'sort-desc',
|
||||
'status',
|
||||
'status-expand',
|
||||
'status-collapse',
|
||||
'status-expand',
|
||||
'status-info',
|
||||
'template',
|
||||
'thumb-down',
|
||||
'thumb-up',
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-header" redactionSyncWidth="table-item">
|
||||
<div [class.no-data]="noData" class="table-header" redactionSyncWidth="table-item">
|
||||
<div class="select-oval-placeholder"></div>
|
||||
|
||||
<redaction-table-col-name
|
||||
@ -81,7 +81,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ attribute.name }}
|
||||
{{ attribute.label }}
|
||||
</div>
|
||||
<!-- TODO-->
|
||||
<!-- <div class="center">-->
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { PermissionsService } from '../../../utils/permissions.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { FileAttribute, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { FileAttributeConfig, FileAttributesControllerService } from '@redaction/red-ui-http';
|
||||
import { AppStateService } from '../../../state/app-state.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { debounce } from '../../../utils/debounce';
|
||||
@ -15,8 +15,8 @@ import { DialogService } from '../../../dialogs/dialog.service';
|
||||
})
|
||||
export class FileAttributesListingScreenComponent implements OnInit {
|
||||
public searchForm: FormGroup;
|
||||
public attributes: FileAttribute[] = [];
|
||||
public displayedAttributes: FileAttribute[] = [];
|
||||
public attributes: FileAttributeConfig[] = [];
|
||||
public displayedAttributes: FileAttributeConfig[] = [];
|
||||
public selectedFileAttributeIds: string[] = [];
|
||||
public viewReady = false;
|
||||
|
||||
@ -47,6 +47,7 @@ export class FileAttributesListingScreenComponent implements OnInit {
|
||||
try {
|
||||
const response = await this._fileAttributesService.getFileAttributesConfiguration(this._appStateService.activeRuleSetId).toPromise();
|
||||
this.attributes = response?.fileAttributes || [];
|
||||
} catch (e) {
|
||||
} finally {
|
||||
this.displayedAttributes = [...this.attributes];
|
||||
this._executeSearch();
|
||||
@ -71,24 +72,24 @@ export class FileAttributesListingScreenComponent implements OnInit {
|
||||
if (!value) {
|
||||
value = { query: this.searchForm.get('query').value };
|
||||
}
|
||||
this.displayedAttributes = this.attributes.filter((attribute) => attribute.name.toLowerCase().includes(value.query.toLowerCase()));
|
||||
this.displayedAttributes = this.attributes.filter((attribute) => attribute.label.toLowerCase().includes(value.query.toLowerCase()));
|
||||
}
|
||||
|
||||
public openAddEditAttributeDialog($event: MouseEvent, fileAttribute?: FileAttribute) {
|
||||
public openAddEditAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) {
|
||||
$event.stopPropagation();
|
||||
this._dialogService.openAddEditFileAttributeDialog(fileAttribute, this._appStateService.activeRuleSetId, async () => {
|
||||
await this._loadData();
|
||||
});
|
||||
}
|
||||
|
||||
public openConfirmDeleteAttributeDialog($event: MouseEvent, fileAttribute?: FileAttribute) {
|
||||
public openConfirmDeleteAttributeDialog($event: MouseEvent, fileAttribute?: FileAttributeConfig) {
|
||||
$event.stopPropagation();
|
||||
this._dialogService.openConfirmDeleteFileAttributeDialog(fileAttribute, this._appStateService.activeRuleSetId, async () => {
|
||||
await this._loadData();
|
||||
});
|
||||
}
|
||||
|
||||
public toggleAttributeSelected($event: MouseEvent, attribute: FileAttribute) {
|
||||
public toggleAttributeSelected($event: MouseEvent, attribute: FileAttributeConfig) {
|
||||
$event.stopPropagation();
|
||||
const idx = this.selectedFileAttributeIds.indexOf(attribute.id);
|
||||
if (idx === -1) {
|
||||
@ -114,7 +115,7 @@ export class FileAttributesListingScreenComponent implements OnInit {
|
||||
return this.selectedFileAttributeIds.length > 0;
|
||||
}
|
||||
|
||||
public isAttributeSelected(attribute: FileAttribute) {
|
||||
public isAttributeSelected(attribute: FileAttributeConfig) {
|
||||
return this.selectedFileAttributeIds.indexOf(attribute.id) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import { PermissionsService } from '../../../utils/permissions.service';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { debounce } from '../../../utils/debounce';
|
||||
import { RuleSetModel } from '@redaction/red-ui-http';
|
||||
import { UserPreferenceService } from '../../../common/service/user-preference.service';
|
||||
import { UserPreferenceService } from '../../../utils/user-preference.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-rule-sets-listing-screen',
|
||||
|
||||
@ -129,7 +129,11 @@
|
||||
</ng-container>
|
||||
<div class="vertical-line"></div>
|
||||
|
||||
<redaction-file-actions (actionPerformed)="fileActionPerformed($event)" *ngIf="viewReady"></redaction-file-actions>
|
||||
<redaction-file-actions
|
||||
(actionPerformed)="fileActionPerformed($event)"
|
||||
[activeDocumentInfo]="viewDocumentInfo"
|
||||
*ngIf="viewReady"
|
||||
></redaction-file-actions>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="toggleFullScreen()"
|
||||
@ -199,119 +203,124 @@
|
||||
></redaction-pdf-viewer>
|
||||
</div>
|
||||
|
||||
<div class="right-container">
|
||||
<div class="right-title heading" translate="file-preview.tabs.annotations.label">
|
||||
<div>
|
||||
<redaction-filter
|
||||
(filtersChanged)="filtersChanged($event)"
|
||||
[chevron]="true"
|
||||
[filterTemplate]="annotationFilterTemplate"
|
||||
[actionsTemplate]="annotationFilterActionTemplate"
|
||||
[filters]="annotationFilters"
|
||||
></redaction-filter>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-content">
|
||||
<div
|
||||
#quickNavigation
|
||||
(keydown)="preventKeyDefault($event)"
|
||||
(keyup)="preventKeyDefault($event)"
|
||||
[class.active-panel]="pagesPanelActive"
|
||||
class="quick-navigation"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="jump"
|
||||
[class.disabled]="!quickScrollFirstEnabled"
|
||||
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
|
||||
matTooltipPosition="above"
|
||||
(click)="quickScrollFirstEnabled && scrollQuickNavFirst()"
|
||||
>
|
||||
<mat-icon svgIcon="red:nav-first"></mat-icon>
|
||||
</div>
|
||||
<div class="pages" (scroll)="computeQuickNavButtonsState()" id="pages">
|
||||
<redaction-page-indicator
|
||||
(pageSelected)="pageSelectedByClick($event)"
|
||||
*ngFor="let pageNumber of displayedPages"
|
||||
[active]="pageNumber === activeViewerPage"
|
||||
[number]="pageNumber"
|
||||
[viewedPages]="fileData.viewedPages"
|
||||
>
|
||||
</redaction-page-indicator>
|
||||
</div>
|
||||
<div
|
||||
class="jump"
|
||||
[class.disabled]="!quickScrollLastEnabled"
|
||||
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
|
||||
matTooltipPosition="above"
|
||||
(click)="scrollQuickNavLast()"
|
||||
>
|
||||
<mat-icon svgIcon="red:nav-last"></mat-icon>
|
||||
<div class="right-container" redactionHasScrollbar>
|
||||
<redaction-document-info *ngIf="viewDocumentInfo" [file]="fileData.fileStatus" (closeDocumentInfoView)="viewDocumentInfo = false">
|
||||
</redaction-document-info>
|
||||
|
||||
<ng-container *ngIf="!viewDocumentInfo">
|
||||
<div class="right-title heading" translate="file-preview.tabs.annotations.label">
|
||||
<div>
|
||||
<redaction-filter
|
||||
(filtersChanged)="filtersChanged($event)"
|
||||
[chevron]="true"
|
||||
[filterTemplate]="annotationFilterTemplate"
|
||||
[actionsTemplate]="annotationFilterActionTemplate"
|
||||
[filters]="annotationFilters"
|
||||
></redaction-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="overflow: hidden; width: 100%;">
|
||||
<div attr.anotation-page-header="{{ activeViewerPage }}" class="page-separator">
|
||||
<span *ngIf="!!activeViewerPage" class="all-caps-label"
|
||||
><span translate="page"></span> {{ activeViewerPage }} - {{ displayedAnnotations[activeViewerPage]?.annotations?.length || 0 }}
|
||||
<span [translate]="displayedAnnotations[activeViewerPage]?.annotations?.length === 1 ? 'annotation' : 'annotations'"></span
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div class="right-content">
|
||||
<div
|
||||
#annotationsElement
|
||||
#quickNavigation
|
||||
(keydown)="preventKeyDefault($event)"
|
||||
(keyup)="preventKeyDefault($event)"
|
||||
[class.active-panel]="!pagesPanelActive"
|
||||
redactionHasScrollbar
|
||||
class="annotations"
|
||||
tabindex="1"
|
||||
[class.active-panel]="pagesPanelActive"
|
||||
class="quick-navigation"
|
||||
tabindex="0"
|
||||
>
|
||||
<div *ngIf="!displayedAnnotations[activeViewerPage]" class="heading-l no-annotations">
|
||||
{{ 'file-preview.no-annotations-for-page' | translate }}
|
||||
<div
|
||||
class="jump"
|
||||
[class.disabled]="!quickScrollFirstEnabled"
|
||||
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
|
||||
matTooltipPosition="above"
|
||||
(click)="quickScrollFirstEnabled && scrollQuickNavFirst()"
|
||||
>
|
||||
<mat-icon svgIcon="red:nav-first"></mat-icon>
|
||||
</div>
|
||||
<div class="pages" (scroll)="computeQuickNavButtonsState()" id="pages">
|
||||
<redaction-page-indicator
|
||||
(pageSelected)="pageSelectedByClick($event)"
|
||||
*ngFor="let pageNumber of displayedPages"
|
||||
[active]="pageNumber === activeViewerPage"
|
||||
[number]="pageNumber"
|
||||
[viewedPages]="fileData.viewedPages"
|
||||
>
|
||||
</redaction-page-indicator>
|
||||
</div>
|
||||
<div
|
||||
class="jump"
|
||||
[class.disabled]="!quickScrollLastEnabled"
|
||||
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
|
||||
matTooltipPosition="above"
|
||||
(click)="scrollQuickNavLast()"
|
||||
>
|
||||
<mat-icon svgIcon="red:nav-last"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="overflow: hidden; width: 100%;">
|
||||
<div attr.anotation-page-header="{{ activeViewerPage }}" class="page-separator">
|
||||
<span *ngIf="!!activeViewerPage" class="all-caps-label"
|
||||
><span translate="page"></span> {{ activeViewerPage }} - {{ displayedAnnotations[activeViewerPage]?.annotations?.length || 0 }}
|
||||
<span [translate]="displayedAnnotations[activeViewerPage]?.annotations?.length === 1 ? 'annotation' : 'annotations'"></span
|
||||
></span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
(click)="annotationClicked(annotation)"
|
||||
class="annotation-wrapper"
|
||||
*ngFor="let annotation of displayedAnnotations[activeViewerPage]?.annotations"
|
||||
attr.annotation-id="{{ annotation.id }}"
|
||||
attr.annotation-page="{{ activeViewerPage }}"
|
||||
[class.active]="annotationIsSelected(annotation)"
|
||||
#annotationsElement
|
||||
(keydown)="preventKeyDefault($event)"
|
||||
(keyup)="preventKeyDefault($event)"
|
||||
[class.active-panel]="!pagesPanelActive"
|
||||
redactionHasScrollbar
|
||||
class="annotations"
|
||||
tabindex="1"
|
||||
>
|
||||
<div class="active-marker"></div>
|
||||
<div class="annotation" [class.removed]="annotation.isChangeLogRemoved">
|
||||
<redaction-hidden-action (action)="logAnnotation(annotation)" [requiredClicks]="2">
|
||||
<div class="details">
|
||||
<redaction-type-annotation-icon [annotation]="annotation"></redaction-type-annotation-icon>
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<strong>{{ annotation.typeLabel | translate }}</strong>
|
||||
</div>
|
||||
<div *ngIf="annotation.dictionary && annotation.dictionary !== 'manual'">
|
||||
<strong
|
||||
><span>{{ annotation.descriptor | translate }}</span
|
||||
>: </strong
|
||||
>{{ annotation.dictionary | humanize: false }}
|
||||
</div>
|
||||
<div *ngIf="annotation.content && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.content }}
|
||||
<div *ngIf="!displayedAnnotations[activeViewerPage]" class="heading-l no-annotations">
|
||||
{{ 'file-preview.no-annotations-for-page' | translate }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
(click)="annotationClicked(annotation)"
|
||||
class="annotation-wrapper"
|
||||
*ngFor="let annotation of displayedAnnotations[activeViewerPage]?.annotations"
|
||||
attr.annotation-id="{{ annotation.id }}"
|
||||
attr.annotation-page="{{ activeViewerPage }}"
|
||||
[class.active]="annotationIsSelected(annotation)"
|
||||
>
|
||||
<div class="active-marker"></div>
|
||||
<div class="annotation" [class.removed]="annotation.isChangeLogRemoved">
|
||||
<redaction-hidden-action (action)="logAnnotation(annotation)" [requiredClicks]="2">
|
||||
<div class="details">
|
||||
<redaction-type-annotation-icon [annotation]="annotation"></redaction-type-annotation-icon>
|
||||
<div class="flex-1">
|
||||
<div>
|
||||
<strong>{{ annotation.typeLabel | translate }}</strong>
|
||||
</div>
|
||||
<div *ngIf="annotation.dictionary && annotation.dictionary !== 'manual'">
|
||||
<strong
|
||||
><span>{{ annotation.descriptor | translate }}</span
|
||||
>: </strong
|
||||
>{{ annotation.dictionary | humanize: false }}
|
||||
</div>
|
||||
<div *ngIf="annotation.content && !annotation.isHint">
|
||||
<strong><span translate="content"></span>: </strong>{{ annotation.content }}
|
||||
</div>
|
||||
</div>
|
||||
<redaction-annotation-actions
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
[annotation]="annotation"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-annotation-actions>
|
||||
</div>
|
||||
<redaction-annotation-actions
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
[annotation]="annotation"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-annotation-actions>
|
||||
</div>
|
||||
</redaction-hidden-action>
|
||||
<redaction-comments [annotation]="annotation"></redaction-comments>
|
||||
</redaction-hidden-action>
|
||||
<redaction-comments [annotation]="annotation"></redaction-comments>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -30,27 +30,20 @@
|
||||
width: 350px;
|
||||
min-width: 350px;
|
||||
|
||||
.right-title {
|
||||
&.has-scrollbar:hover {
|
||||
::ng-deep redaction-document-info .right-title,
|
||||
::ng-deep redaction-document-info .section {
|
||||
padding-right: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep.right-title {
|
||||
height: 70px;
|
||||
display: flex;
|
||||
border-bottom: 1px solid $separator;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 24px;
|
||||
|
||||
.close-icon {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
|
||||
redaction-circle-button {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-content {
|
||||
|
||||
@ -146,6 +146,22 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
|
||||
hideSkipped = false;
|
||||
|
||||
private _viewDocumentInfo = false;
|
||||
|
||||
public get viewDocumentInfo(): boolean {
|
||||
return this._viewDocumentInfo;
|
||||
}
|
||||
|
||||
public set viewDocumentInfo(value: boolean) {
|
||||
this._viewDocumentInfo = value;
|
||||
if (!value) {
|
||||
setTimeout(() => {
|
||||
this._scrollQuickNavigation();
|
||||
this.scrollToSelectedAnnotation();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
updateViewMode() {
|
||||
const allAnnotations = this._instance.annotManager.getAnnotationsList();
|
||||
|
||||
@ -329,13 +345,16 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
|
||||
@debounce()
|
||||
private _scrollViews() {
|
||||
if (this.viewDocumentInfo) {
|
||||
return;
|
||||
}
|
||||
this._scrollQuickNavigation();
|
||||
this._scrollAnnotations();
|
||||
}
|
||||
|
||||
@debounce()
|
||||
private scrollToSelectedAnnotation() {
|
||||
if (!this.selectedAnnotations || this.selectedAnnotations.length === 0) {
|
||||
if (this.viewDocumentInfo || !this.selectedAnnotations || this.selectedAnnotations.length === 0) {
|
||||
return;
|
||||
}
|
||||
const elements: any[] = this._annotationsElement.nativeElement.querySelectorAll(`div[annotation-id="${this.firstSelectedAnnotation.id}"].active`);
|
||||
@ -602,6 +621,9 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public computeQuickNavButtonsState() {
|
||||
if (this.viewDocumentInfo) {
|
||||
return;
|
||||
}
|
||||
const element: HTMLElement = this._quickNavigationElement.nativeElement.querySelector(`#pages`);
|
||||
const { scrollTop, scrollHeight, clientHeight } = element;
|
||||
this.quickScrollFirstEnabled = scrollTop !== 0;
|
||||
@ -670,6 +692,11 @@ export class FilePreviewScreenComponent implements OnInit, OnDestroy {
|
||||
this._updateCanPerformActions();
|
||||
await this.appStateService.reloadActiveProjectFiles();
|
||||
return;
|
||||
|
||||
case 'view-document-info':
|
||||
this.viewDocumentInfo = !this.viewDocumentInfo;
|
||||
return;
|
||||
|
||||
default:
|
||||
this._updateCanPerformActions();
|
||||
}
|
||||
|
||||
@ -291,6 +291,18 @@
|
||||
"view-toggle": "Redacted View",
|
||||
"tabs": {
|
||||
"quick-navigation": "Quick Navigation",
|
||||
"document-info": {
|
||||
"label": "Document Info",
|
||||
"close": "Close Document Info",
|
||||
"edit": "Edit Document Info",
|
||||
"details": {
|
||||
"project": "in {{projectName}}",
|
||||
"pages": "{{pages}} pages",
|
||||
"revised-pages": "{{pages}} revised pages",
|
||||
"created-on": "Created on: {{date}}",
|
||||
"due": "Due: {{date}}"
|
||||
}
|
||||
},
|
||||
"annotations": {
|
||||
"label": "Workload"
|
||||
}
|
||||
@ -303,6 +315,7 @@
|
||||
"assign-me": "Assign to me",
|
||||
"last-reviewer": "Last Reviewed by:",
|
||||
"fullscreen": "Full Screen (F)",
|
||||
"document-info": "Your Document Info lives here. This includes metadata required on each document.",
|
||||
"new-tab-ssr": "Open Document in Server Side Rendering Mode",
|
||||
"html-debug": "Open Document HTML Debug",
|
||||
"download-original-file": "Download Original File",
|
||||
@ -732,6 +745,11 @@
|
||||
"checkbox-1": "All documents it is used on will be impacted",
|
||||
"checkbox-2": "All inputted details on the documents will be lost"
|
||||
},
|
||||
"document-info": {
|
||||
"title": "Introduce Document Info",
|
||||
"save": "Save Document Info",
|
||||
"save-approval": "Save and Send for Approval"
|
||||
},
|
||||
"user-listing": {
|
||||
"table-header": {
|
||||
"title": "{{length}} users"
|
||||
|
||||
27
apps/red-ui/src/assets/icons/general/status-info.svg
Normal file
27
apps/red-ui/src/assets/icons/general/status-info.svg
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>F8E3057D-BE44-469F-9E28-9A04A0B36DF0</title>
|
||||
<defs>
|
||||
<rect id="path-1" x="0" y="61" width="1440" height="50"></rect>
|
||||
<filter x="-0.5%" y="-10.0%" width="101.0%" height="128.0%" filterUnits="objectBoundingBox" id="filter-2">
|
||||
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0.88627451 0 0 0 0 0.894117647 0 0 0 0 0.91372549 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="File-attributes" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Reviewer---Doc-Info-sidebar" transform="translate(-1256.000000, -79.000000)">
|
||||
<rect x="0" y="0" width="1440" height="750"></rect>
|
||||
<g id="Header-Document">
|
||||
<g id="Group-6" transform="translate(1246.000000, 69.000000)">
|
||||
<rect id="Rectangle" opacity="0.1" x="0" y="0" width="34" height="34" rx="17"></rect>
|
||||
<g id="status" transform="translate(10.000000, 10.000000)" fill="currentColor">
|
||||
<path d="M2.8,0 L0,0 L0,14 L14,14 L14,0 M12.6,1.4 L12.6,12.6 L1.4,12.6 L1.4,1.4 L2.8,1.4" id="pages" fill-rule="nonzero"></path>
|
||||
<rect id="Rectangle" x="6.3" y="5.46" width="1.4" height="5.46"></rect>
|
||||
<rect id="Rectangle" x="6.3" y="3.08" width="1.4" height="1.4"></rect>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@ -74,7 +74,7 @@
|
||||
|
||||
mat-icon {
|
||||
width: 10px;
|
||||
margin-right: 4px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user