WIP on master

RED-8748 - Integrated component view in DocuMine
This commit is contained in:
Valentin Mihai 2024-07-29 01:02:46 +03:00
parent aaef6c7649
commit dbc609765b
10 changed files with 303 additions and 257 deletions

View File

@ -6,7 +6,6 @@
[matMenuTriggerFor]="bulkComponentDownloadMenu" [matMenuTriggerFor]="bulkComponentDownloadMenu"
[matTooltipPosition]="'above'" [matTooltipPosition]="'above'"
[matTooltip]="'documine-export.export-tooltip' | translate" [matTooltip]="'documine-export.export-tooltip' | translate"
[hidden]="true"
class="red-tab" class="red-tab"
> >
{{ 'documine-export.export' | translate }} {{ 'documine-export.export' | translate }}

View File

@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core'; import { Component, input, Input } from '@angular/core';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { Dossier } from '@red/domain'; import { Dossier, File } from '@red/domain';
import { ComponentLogService } from '@services/files/component-log.service'; import { ComponentLogService } from '@services/files/component-log.service';
import { MatTooltip } from '@angular/material/tooltip'; import { MatTooltip } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@ -13,15 +13,18 @@ import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
imports: [MatTooltip, TranslateModule, MatMenuTrigger, MatMenu, MatMenuItem], imports: [MatTooltip, TranslateModule, MatMenuTrigger, MatMenu, MatMenuItem],
}) })
export class DocumineExportComponent { export class DocumineExportComponent {
@Input() dossier: Dossier; readonly dossier = input<Dossier>();
readonly file = input<File>();
constructor(private readonly _componentLogService: ComponentLogService) {} constructor(private readonly _componentLogService: ComponentLogService) {}
downloadComponentAsJSON() { downloadComponentAsJSON() {
return firstValueFrom(this._componentLogService.exportJSON(this.dossier.dossierTemplateId, this.dossier.dossierId)); return firstValueFrom(
this._componentLogService.exportJSON(this.dossier().dossierTemplateId, this.dossier().dossierId, this.file()),
);
} }
async downloadComponentAsXML() { async downloadComponentAsXML() {
return firstValueFrom(this._componentLogService.exportXML(this.dossier.dossierTemplateId, this.dossier.dossierId)); return firstValueFrom(this._componentLogService.exportXML(this.dossier().dossierTemplateId, this.dossier().dossierId, this.file()));
} }
} }

View File

@ -1,40 +1,47 @@
<div (click)="select()" [ngClass]="{ selected: selected, editing: editing }" class="component-value"> <div (click)="select()" [ngClass]="{ selected: selected, editing: editing }" class="component-value">
<div class="component">{{ entryLabel }}</div> <div class="component">{{ entryLabel }}</div>
<div *ngIf="!editing; else editValue" class="value"> @if (!editing) {
<div class="value">
<div class="text"> <div class="text">
<span @for (componentValue of entry.componentValues; track componentValue) {
*ngFor="let componentValue of entry.componentValues" <span [innerHTML]="transformNewLines(componentValue.value ?? componentValue.originalValue)"></span>
[innerHTML]="transformNewLines(componentValue.value ?? componentValue.originalValue)" }
>
</span>
</div> </div>
<div class="actions"> <div class="actions">
@if (canEdit) {
<iqser-circle-button <iqser-circle-button
(action)="edit()" (action)="edit()"
*ngIf="canEdit"
[tooltip]="'component-management.actions.edit' | translate" [tooltip]="'component-management.actions.edit' | translate"
icon="iqser:edit" icon="iqser:edit"
></iqser-circle-button> ></iqser-circle-button>
<div *ngIf="hasUpdatedValues && canEdit" class="changes-dot"></div> @if (hasUpdatedValues) {
<div class="changes-dot"></div>
}
}
</div> </div>
</div> </div>
<mat-icon *ngIf="!editing" class="arrow-right" svgIcon="red:arrow-right"></mat-icon> } @else {
</div>
<ng-template #editValue>
<div (cdkDropListDropped)="drop($event)" cdkDropList> <div (cdkDropListDropped)="drop($event)" cdkDropList>
<div *ngFor="let value of entry.componentValues; let index = index" cdkDrag class="editing-value"> @for (value of entry.componentValues; track value) {
<mat-icon cdkDragHandle class="draggable" svgIcon="red:draggable-dots"></mat-icon> <div cdkDrag class="editing-value">
<mat-icon
[class.hidden-button]="entry.componentValues.length === 1"
cdkDragHandle
class="draggable"
svgIcon="red:draggable-dots"
></mat-icon>
<div class="iqser-input-group w-full"> <div class="iqser-input-group w-full">
<textarea [id]="'value-input-' + index" [(ngModel)]="value.value" rows="1" type="text"></textarea> <textarea [id]="'value-input-' + $index" [(ngModel)]="value.value" rows="1" type="text"></textarea>
</div> </div>
<iqser-circle-button <iqser-circle-button
(action)="removeValue(index)" (action)="removeValue($index)"
[tooltip]="'component-management.actions.delete' | translate" [tooltip]="'component-management.actions.delete' | translate"
[class.hidden-button]="entry.componentValues.length === 1"
class="remove-value" class="remove-value"
icon="iqser:trash" icon="iqser:trash"
></iqser-circle-button> ></iqser-circle-button>
</div> </div>
}
</div> </div>
<div class="editing-actions"> <div class="editing-actions">
<iqser-icon-button <iqser-icon-button
@ -45,14 +52,15 @@
></iqser-icon-button> ></iqser-icon-button>
<div (click)="deselect($event)" class="all-caps-label cancel" translate="component-management.actions.cancel"></div> <div (click)="deselect($event)" class="all-caps-label cancel" translate="component-management.actions.cancel"></div>
<div class="flex right"> <div class="flex right">
@if (hasUpdatedValues && canEdit) {
<iqser-circle-button <iqser-circle-button
(action)="undo()" (action)="undo()"
*ngIf="hasUpdatedValues && canEdit"
[tooltip]="'component-management.actions.undo' | translate" [tooltip]="'component-management.actions.undo' | translate"
class="undo-value" class="undo-value"
icon="red:undo" icon="red:undo"
showDot showDot
></iqser-circle-button> ></iqser-circle-button>
}
<iqser-circle-button <iqser-circle-button
(action)="add()" (action)="add()"
[tooltip]="'component-management.actions.add' | translate" [tooltip]="'component-management.actions.add' | translate"
@ -61,4 +69,8 @@
></iqser-circle-button> ></iqser-circle-button>
</div> </div>
</div> </div>
</ng-template> }
@if (!editing) {
<mat-icon class="arrow-right" svgIcon="red:arrow-right"></mat-icon>
}
</div>

View File

@ -59,7 +59,6 @@
&:not(.header):hover, &:not(.header):hover,
&.selected { &.selected {
background-color: var(--iqser-grey-8); background-color: var(--iqser-grey-8);
border-left: 4px solid var(--iqser-primary);
margin-left: 0; margin-left: 0;
margin-right: 0; margin-right: 0;
@ -67,18 +66,31 @@
cursor: pointer; cursor: pointer;
} }
.component {
margin-left: 22px;
}
.value { .value {
margin-right: 26px; margin-right: 26px;
}
}
&:hover {
.component {
margin-left: 26px;
}
.value {
.actions { .actions {
iqser-circle-button { iqser-circle-button {
visibility: visible; visibility: visible;
} }
} }
} }
}
&.selected {
border-left: 4px solid var(--iqser-primary);
.component {
margin-left: 22px;
}
.arrow-right { .arrow-right {
visibility: visible; visibility: visible;
@ -129,6 +141,10 @@
} }
} }
.hidden-button {
visibility: hidden;
}
::ng-deep .add-value { ::ng-deep .add-value {
mat-icon { mat-icon {
transform: scale(2); transform: scale(2);

View File

@ -1,7 +1,7 @@
<div class="page-header"> <div class="page-header">
<div class="flex"> <div class="flex">
<redaction-view-switch *ngIf="!isDocumine"></redaction-view-switch> <redaction-view-switch *ngIf="!isDocumine"></redaction-view-switch>
<redaction-documine-export *ngIf="isDocumine" [dossier]="state.dossier()"></redaction-documine-export> <redaction-documine-export *ngIf="isDocumine" [dossier]="state.dossier()" [file]="state.file()"></redaction-documine-export>
</div> </div>
<!-- TODO: mode this file preview header to a separate component--> <!-- TODO: mode this file preview header to a separate component-->

View File

@ -32,7 +32,8 @@
</ng-template> </ng-template>
</ng-container> </ng-container>
<div class="right-content"> @if (displayedAnnotations$ | async; as annotations) {
<div class="right-content">
<ng-container *ngIf="!isDocumine"> <ng-container *ngIf="!isDocumine">
<redaction-readonly-banner <redaction-readonly-banner
*ngIf="showAnalysisDisabledBanner; else readOnlyBanner" *ngIf="showAnalysisDisabledBanner; else readOnlyBanner"
@ -110,6 +111,13 @@
</div> </div>
<div class="content" [class.documine-width]="isDocumine"> <div class="content" [class.documine-width]="isDocumine">
@if (state.file().excluded && documentInfoService.hidden()) {
<iqser-empty-state
[horizontalPadding]="40"
[text]="'file-preview.tabs.is-excluded' | translate"
icon="red:needs-work"
></iqser-empty-state>
} @else {
<div <div
*ngIf="!viewModeService.isEarmarks()" *ngIf="!viewModeService.isEarmarks()"
[attr.anotation-page-header]="pdf.currentPage()" [attr.anotation-page-header]="pdf.currentPage()"
@ -177,7 +185,9 @@
>. >.
</ng-container> </ng-container>
<ng-container *ngIf="(fileDataService.allLength$ | async) === 0 || filterService.noAnnotationsFilterChecked"> <ng-container
*ngIf="(fileDataService.allLength$ | async) === 0 || filterService.noAnnotationsFilterChecked"
>
{{ 'file-preview.tabs.annotations.no-annotations' | translate }} {{ 'file-preview.tabs.annotations.no-annotations' | translate }}
</ng-container> </ng-container>
@ -188,7 +198,11 @@
!filterService.noAnnotationsFilterChecked !filterService.noAnnotationsFilterChecked
" "
>{{ 'file-preview.tabs.annotations.wrong-filters' | translate }} >{{ 'file-preview.tabs.annotations.wrong-filters' | translate }}
<a (click)="filterService.reset()" class="with-underline" translate="file-preview.tabs.annotations.reset"></a> <a
(click)="filterService.reset()"
class="with-underline"
translate="file-preview.tabs.annotations.reset"
></a>
{{ 'file-preview.tabs.annotations.the-filters' | translate }} {{ 'file-preview.tabs.annotations.the-filters' | translate }}
</ng-container> </ng-container>
</iqser-empty-state> </iqser-empty-state>
@ -215,14 +229,15 @@
<redaction-annotations-list <redaction-annotations-list
(pagesPanelActive)="pagesPanelActive = $event" (pagesPanelActive)="pagesPanelActive = $event"
[annotations]="(displayedAnnotations$ | async)?.get(pdf.currentPage())" [annotations]="annotations.get(pdf.currentPage())"
></redaction-annotations-list> ></redaction-annotations-list>
</div> </div>
}
<redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion> <redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion>
</div> </div>
</div> </div>
</div> </div>
}
<ng-template #annotationFilterActionTemplate let-filter="filter"> <ng-template #annotationFilterActionTemplate let-filter="filter">
<iqser-circle-button <iqser-circle-button

View File

@ -1,6 +1,6 @@
<ng-container *ngIf="state.file() as file"> <ng-container *ngIf="state.file() as file">
<iqser-empty-state <iqser-empty-state
*ngIf="file.excluded && documentInfoService.hidden()" *ngIf="file.excluded && documentInfoService.hidden() && !this.isDocumine"
[horizontalPadding]="40" [horizontalPadding]="40"
[text]="'file-preview.tabs.is-excluded' | translate" [text]="'file-preview.tabs.is-excluded' | translate"
icon="red:needs-work" icon="red:needs-work"
@ -8,5 +8,5 @@
<redaction-document-info *ngIf="documentInfoService.shown() && !isDocumine" id="document-info"></redaction-document-info> <redaction-document-info *ngIf="documentInfoService.shown() && !isDocumine" id="document-info"></redaction-document-info>
<redaction-file-workload *ngIf="!file.excluded"></redaction-file-workload> <redaction-file-workload *ngIf="!file.excluded || isDocumine"></redaction-file-workload>
</ng-container> </ng-container>

View File

@ -39,7 +39,7 @@
} }
&.documine-container { &.documine-container {
width: 70%; width: 60%;
} }
} }

View File

@ -275,6 +275,7 @@ export class ViewerHeaderService {
updateElements(): void { updateElements(): void {
this._pdf.instance?.UI.setHeaderItems(header => { this._pdf.instance?.UI.setHeaderItems(header => {
const documineButtons = this.#isDocumine ? 1 : 0;
const enabledItems: IHeaderElement[] = []; const enabledItems: IHeaderElement[] = [];
const groups: HeaderElementType[][] = [ const groups: HeaderElementType[][] = [
[HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON], [HeaderElements.COMPARE_BUTTON, HeaderElements.CLOSE_COMPARE_BUTTON],
@ -293,15 +294,15 @@ export class ViewerHeaderService {
groups.forEach(group => this.#pushGroup(enabledItems, group)); groups.forEach(group => this.#pushGroup(enabledItems, group));
const loadAllAnnotationsButton = this.#buttons.get(HeaderElements.LOAD_ALL_ANNOTATIONS); const loadAllAnnotationsButton = this.#buttons.get(HeaderElements.LOAD_ALL_ANNOTATIONS);
let startButtons = 11; let startButtons = 11 - documineButtons;
let deleteCount = 15; let deleteCount = 15 - documineButtons;
if (this.#isEnabled(HeaderElements.LOAD_ALL_ANNOTATIONS)) { if (this.#isEnabled(HeaderElements.LOAD_ALL_ANNOTATIONS)) {
if (!header.getItems().includes(loadAllAnnotationsButton)) { if (!header.getItems().includes(loadAllAnnotationsButton)) {
header.get('leftPanelButton').insertAfter(loadAllAnnotationsButton); header.get('leftPanelButton').insertAfter(loadAllAnnotationsButton);
} }
startButtons = 12; startButtons = 12 - documineButtons;
deleteCount = 16; deleteCount = 16 - documineButtons;
} else { } else {
header.delete(HeaderElements.LOAD_ALL_ANNOTATIONS); header.delete(HeaderElements.LOAD_ALL_ANNOTATIONS);
} }

View File

@ -164,7 +164,7 @@ $dark-accent-10: darken(vars.$accent, 10%);
body { body {
--workload-width: 350px; --workload-width: 350px;
--documine-workload-content-width: 287px; --documine-workload-content-width: 287px;
--structured-component-management-width: 30%; --structured-component-management-width: 40%;
--qiuck-navigation-width: 61px; --qiuck-navigation-width: 61px;
--iqser-app-name-font-family: OpenSans Extrabold, sans-serif; --iqser-app-name-font-family: OpenSans Extrabold, sans-serif;
--iqser-app-name-font-size: 13px; --iqser-app-name-font-size: 13px;