Merge remote-tracking branch 'origin/master' into RED-9747

This commit is contained in:
Dan Percic 2024-07-30 10:33:58 +03:00
commit 66df5f807c
13 changed files with 343 additions and 258 deletions

View File

@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core';
import { Component, input, Input } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { Dossier } from '@red/domain';
import { Dossier, File } from '@red/domain';
import { ComponentLogService } from '@services/files/component-log.service';
import { MatTooltip } from '@angular/material/tooltip';
import { TranslateModule } from '@ngx-translate/core';
@ -13,15 +13,18 @@ import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
imports: [MatTooltip, TranslateModule, MatMenuTrigger, MatMenu, MatMenuItem],
})
export class DocumineExportComponent {
@Input() dossier: Dossier;
readonly dossier = input<Dossier>();
readonly file = input<File>();
constructor(private readonly _componentLogService: ComponentLogService) {}
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() {
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,64 +1,76 @@
<div (click)="select()" [ngClass]="{ selected: selected, editing: editing }" class="component-value">
<div class="component">{{ entryLabel }}</div>
<div *ngIf="!editing; else editValue" class="value">
<div class="text">
<span
*ngFor="let componentValue of entry.componentValues"
[innerHTML]="transformNewLines(componentValue.value ?? componentValue.originalValue)"
>
</span>
</div>
<div class="actions">
<iqser-circle-button
(action)="edit()"
*ngIf="canEdit"
[tooltip]="'component-management.actions.edit' | translate"
icon="iqser:edit"
></iqser-circle-button>
<div *ngIf="hasUpdatedValues && canEdit" class="changes-dot"></div>
</div>
</div>
<mat-icon *ngIf="!editing" class="arrow-right" svgIcon="red:arrow-right"></mat-icon>
</div>
<ng-template #editValue>
<div (cdkDropListDropped)="drop($event)" cdkDropList>
<div *ngFor="let value of entry.componentValues; let index = index" cdkDrag class="editing-value">
<mat-icon cdkDragHandle class="draggable" svgIcon="red:draggable-dots"></mat-icon>
<div class="iqser-input-group w-full">
<textarea [id]="'value-input-' + index" [(ngModel)]="value.value" rows="1" type="text"></textarea>
@if (!editing) {
<div class="value">
<div class="text">
@for (componentValue of entry.componentValues; track componentValue) {
<span [innerHTML]="transformNewLines(componentValue.value ?? componentValue.originalValue)"></span>
}
</div>
<div class="actions">
@if (canEdit) {
<iqser-circle-button
(action)="edit()"
[tooltip]="'component-management.actions.edit' | translate"
icon="iqser:edit"
></iqser-circle-button>
@if (hasUpdatedValues) {
<div class="changes-dot"></div>
}
}
</div>
<iqser-circle-button
(action)="removeValue(index)"
[tooltip]="'component-management.actions.delete' | translate"
class="remove-value"
icon="iqser:trash"
></iqser-circle-button>
</div>
</div>
<div class="editing-actions">
<iqser-icon-button
(action)="save()"
[disabled]="disabled"
[label]="'component-management.actions.save' | translate"
[type]="iconButtonTypes.primary"
></iqser-icon-button>
<div (click)="deselect($event)" class="all-caps-label cancel" translate="component-management.actions.cancel"></div>
<div class="flex right">
<iqser-circle-button
(action)="undo()"
*ngIf="hasUpdatedValues && canEdit"
[tooltip]="'component-management.actions.undo' | translate"
class="undo-value"
icon="red:undo"
showDot
></iqser-circle-button>
<iqser-circle-button
(action)="add()"
[tooltip]="'component-management.actions.add' | translate"
class="add-value"
icon="iqser:plus"
></iqser-circle-button>
} @else {
<div (cdkDropListDropped)="drop($event)" cdkDropList>
@for (value of entry.componentValues; track value) {
<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">
<textarea [id]="'value-input-' + $index" [(ngModel)]="value.value" rows="1" type="text"></textarea>
</div>
<iqser-circle-button
(action)="removeValue($index)"
[tooltip]="'component-management.actions.delete' | translate"
[class.hidden-button]="entry.componentValues.length === 1"
class="remove-value"
icon="iqser:trash"
></iqser-circle-button>
</div>
}
</div>
</div>
</ng-template>
<div class="editing-actions">
<iqser-icon-button
(action)="save()"
[disabled]="disabled"
[label]="'component-management.actions.save' | translate"
[type]="iconButtonTypes.primary"
></iqser-icon-button>
<div (click)="deselect($event)" class="all-caps-label cancel" translate="component-management.actions.cancel"></div>
<div class="flex right">
@if (hasUpdatedValues && canEdit) {
<iqser-circle-button
(action)="undo()"
[tooltip]="'component-management.actions.undo' | translate"
class="undo-value"
icon="red:undo"
showDot
></iqser-circle-button>
}
<iqser-circle-button
(action)="add()"
[tooltip]="'component-management.actions.add' | translate"
class="add-value"
icon="iqser:plus"
></iqser-circle-button>
</div>
</div>
}
@if (!editing) {
<mat-icon class="arrow-right" svgIcon="red:arrow-right"></mat-icon>
}
</div>

View File

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

View File

@ -1,7 +1,7 @@
<div class="page-header">
<div class="flex">
<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>
<!-- TODO: mode this file preview header to a separate component-->

View File

@ -32,197 +32,212 @@
</ng-template>
</ng-container>
<div class="right-content">
<ng-container *ngIf="!isDocumine">
<redaction-readonly-banner
*ngIf="showAnalysisDisabledBanner; else readOnlyBanner"
[customTranslation]="translations.analysisDisabled"
></redaction-readonly-banner>
<ng-template #readOnlyBanner>
<redaction-readonly-banner *ngIf="state.isReadonly()"></redaction-readonly-banner>
</ng-template>
</ng-container>
@if (displayedAnnotations$ | async; as annotations) {
<div class="right-content">
<ng-container *ngIf="!isDocumine">
<redaction-readonly-banner
*ngIf="showAnalysisDisabledBanner; else readOnlyBanner"
[customTranslation]="translations.analysisDisabled"
></redaction-readonly-banner>
<ng-template #readOnlyBanner>
<redaction-readonly-banner *ngIf="state.isReadonly()"></redaction-readonly-banner>
</ng-template>
</ng-container>
<div *ngIf="multiSelectService.active()" class="multi-select">
<div class="selected-wrapper">
<iqser-round-checkbox
(click)="annotationManager.deselect()"
[indeterminate]="listingService.areSomeSelected$ | async"
type="with-bg"
></iqser-round-checkbox>
<div *ngIf="multiSelectService.active()" class="multi-select">
<div class="selected-wrapper">
<iqser-round-checkbox
(click)="annotationManager.deselect()"
[indeterminate]="listingService.areSomeSelected$ | async"
type="with-bg"
></iqser-round-checkbox>
<span class="all-caps-label">{{ listingService.selectedLength$ | async }} selected </span>
<span class="all-caps-label">{{ listingService.selectedLength$ | async }} selected </span>
<redaction-annotation-actions
*ngIf="listingService.areSomeSelected$ | async"
[alwaysVisible]="true"
[annotations]="listingService.selectedEntities$ | async"
[canPerformAnnotationActions]="state.isWritable()"
buttonType="primary"
tooltipPosition="above"
></redaction-annotation-actions>
</div>
<iqser-circle-button
(action)="multiSelectService.deactivate()"
[tooltip]="'file-preview.tabs.multi-select.close' | translate"
[type]="circleButtonTypes.primary"
icon="iqser:close"
tooltipPosition="before"
></iqser-circle-button>
</div>
<div class="annotations-wrapper" [class.documine-direction]="isDocumine">
<div [class.border-left]="isDocumine">
<div
#quickNavigation
*ngIf="!(documentInfoService.shown() && isDocumine); else documentInfo"
(keydown)="preventKeyDefault($event)"
(keyup)="preventKeyDefault($event)"
[class.active-panel]="pagesPanelActive"
class="quick-navigation"
tabindex="0"
>
<div
(click)="scrollQuickNavFirst()"
[class.disabled]="pdf.currentPage() === 1"
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
[class.documine-height]="isDocumine"
class="jump"
matTooltipPosition="above"
>
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
</div>
<redaction-pages (click)="pagesPanelActive = true" [pages]="displayedPages"></redaction-pages>
<div
(click)="scrollQuickNavLast()"
[class.disabled]="pdf.currentPage() === state.file()?.numberOfPages"
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
[class.documine-height]="isDocumine"
class="jump"
matTooltipPosition="above"
>
<mat-icon svgIcon="iqser:nav-last"></mat-icon>
</div>
</div>
</div>
<div class="content" [class.documine-width]="isDocumine">
<div
*ngIf="!viewModeService.isEarmarks()"
[attr.anotation-page-header]="pdf.currentPage()"
[hidden]="excludedPagesService.shown()"
class="workload-separator"
>
<span *ngIf="!!pdf.currentPage()" class="flex-align-items-center">
<ng-container *ngIf="!isDocumine; else documineHeader">
<iqser-circle-button
(action)="excludedPagesService.toggle()"
*ngIf="currentPageIsExcluded()"
[size]="14"
[tooltip]="'file-preview.excluded-from-redaction' | translate | capitalize"
class="mr-10 primary"
icon="red:exclude-pages"
tooltipPosition="above"
></iqser-circle-button>
<span
[translateParams]="{ page: pdf.currentPage(), count: activeAnnotations.length }"
[translate]="'page'"
class="all-caps-label"
></span>
</ng-container>
</span>
<div *ngIf="multiSelectService.active()">
<div
(click)="selectAllOnActivePage()"
class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select-all"
></div>
<div
(click)="deselectAllOnActivePage()"
class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select-none"
></div>
</div>
<redaction-annotation-actions
*ngIf="listingService.areSomeSelected$ | async"
[alwaysVisible]="true"
[annotations]="listingService.selectedEntities$ | async"
[canPerformAnnotationActions]="state.isWritable()"
buttonType="primary"
tooltipPosition="above"
></redaction-annotation-actions>
</div>
<div
#annotationsElement
(keydown)="preventKeyDefault($event)"
(keyup)="preventKeyDefault($event)"
[class.active-panel]="!pagesPanelActive"
[hidden]="excludedPagesService.shown()"
class="annotations"
id="annotations-list"
tabindex="1"
>
<ng-container *ngIf="pdf.currentPage() && !displayedAnnotations.get(pdf.currentPage())?.length">
<iqser-empty-state
[horizontalPadding]="24"
[text]="'file-preview.no-data.title' | translate"
[verticalPadding]="40"
icon="iqser:document"
<iqser-circle-button
(action)="multiSelectService.deactivate()"
[tooltip]="'file-preview.tabs.multi-select.close' | translate"
[type]="circleButtonTypes.primary"
icon="iqser:close"
tooltipPosition="before"
></iqser-circle-button>
</div>
<div class="annotations-wrapper" [class.documine-direction]="isDocumine">
<div [class.border-left]="isDocumine">
<div
#quickNavigation
*ngIf="!(documentInfoService.shown() && isDocumine); else documentInfo"
(keydown)="preventKeyDefault($event)"
(keyup)="preventKeyDefault($event)"
[class.active-panel]="pagesPanelActive"
class="quick-navigation"
tabindex="0"
>
<div
(click)="scrollQuickNavFirst()"
[class.disabled]="pdf.currentPage() === 1"
[matTooltip]="'file-preview.quick-nav.jump-first' | translate"
[class.documine-height]="isDocumine"
class="jump"
matTooltipPosition="above"
>
<ng-container *ngIf="currentPageIsExcluded() && displayedPages.length">
{{ 'file-preview.tabs.annotations.page-is' | translate }}
<a
(click)="excludedPagesService.toggle()"
class="with-underline"
translate="file-preview.excluded-from-redaction"
></a
>.
</ng-container>
<ng-container *ngIf="(fileDataService.allLength$ | async) === 0 || filterService.noAnnotationsFilterChecked">
{{ 'file-preview.tabs.annotations.no-annotations' | translate }}
</ng-container>
<ng-container
*ngIf="
(fileDataService.allLength$ | async) > 0 &&
displayedPages.length === 0 &&
!filterService.noAnnotationsFilterChecked
"
>{{ 'file-preview.tabs.annotations.wrong-filters' | translate }}
<a (click)="filterService.reset()" class="with-underline" translate="file-preview.tabs.annotations.reset"></a>
{{ 'file-preview.tabs.annotations.the-filters' | translate }}
</ng-container>
</iqser-empty-state>
<div *ngIf="displayedPages.length" class="no-annotations-buttons-container mt-32">
<iqser-icon-button
(action)="jumpToPreviousWithAnnotations()"
[disabled]="pdf.currentPage() <= displayedPages[0]"
[label]="'file-preview.tabs.annotations.jump-to-previous' | translate"
[type]="iconButtonTypes.dark"
icon="iqser:nav-prev"
></iqser-icon-button>
<iqser-icon-button
(action)="jumpToNextWithAnnotations()"
[disabled]="pdf.currentPage() >= displayedPages[displayedPages.length - 1]"
[label]="'file-preview.tabs.annotations.jump-to-next' | translate"
[type]="iconButtonTypes.dark"
class="mt-8"
icon="iqser:nav-next"
></iqser-icon-button>
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
</div>
</ng-container>
<redaction-annotations-list
(pagesPanelActive)="pagesPanelActive = $event"
[annotations]="(displayedAnnotations$ | async)?.get(pdf.currentPage())"
></redaction-annotations-list>
<redaction-pages (click)="pagesPanelActive = true" [pages]="displayedPages"></redaction-pages>
<div
(click)="scrollQuickNavLast()"
[class.disabled]="pdf.currentPage() === state.file()?.numberOfPages"
[matTooltip]="'file-preview.quick-nav.jump-last' | translate"
[class.documine-height]="isDocumine"
class="jump"
matTooltipPosition="above"
>
<mat-icon svgIcon="iqser:nav-last"></mat-icon>
</div>
</div>
</div>
<redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion>
<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
*ngIf="!viewModeService.isEarmarks()"
[attr.anotation-page-header]="pdf.currentPage()"
[hidden]="excludedPagesService.shown()"
class="workload-separator"
>
<span *ngIf="!!pdf.currentPage()" class="flex-align-items-center">
<ng-container *ngIf="!isDocumine; else documineHeader">
<iqser-circle-button
(action)="excludedPagesService.toggle()"
*ngIf="currentPageIsExcluded()"
[size]="14"
[tooltip]="'file-preview.excluded-from-redaction' | translate | capitalize"
class="mr-10 primary"
icon="red:exclude-pages"
tooltipPosition="above"
></iqser-circle-button>
<span
[translateParams]="{ page: pdf.currentPage(), count: activeAnnotations.length }"
[translate]="'page'"
class="all-caps-label"
></span>
</ng-container>
</span>
<div *ngIf="multiSelectService.active()">
<div
(click)="selectAllOnActivePage()"
class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select-all"
></div>
<div
(click)="deselectAllOnActivePage()"
class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select-none"
></div>
</div>
</div>
<div
#annotationsElement
(keydown)="preventKeyDefault($event)"
(keyup)="preventKeyDefault($event)"
[class.active-panel]="!pagesPanelActive"
[hidden]="excludedPagesService.shown()"
class="annotations"
id="annotations-list"
tabindex="1"
>
<ng-container *ngIf="pdf.currentPage() && !displayedAnnotations.get(pdf.currentPage())?.length">
<iqser-empty-state
[horizontalPadding]="24"
[text]="'file-preview.no-data.title' | translate"
[verticalPadding]="40"
icon="iqser:document"
>
<ng-container *ngIf="currentPageIsExcluded() && displayedPages.length">
{{ 'file-preview.tabs.annotations.page-is' | translate }}
<a
(click)="excludedPagesService.toggle()"
class="with-underline"
translate="file-preview.excluded-from-redaction"
></a
>.
</ng-container>
<ng-container
*ngIf="(fileDataService.allLength$ | async) === 0 || filterService.noAnnotationsFilterChecked"
>
{{ 'file-preview.tabs.annotations.no-annotations' | translate }}
</ng-container>
<ng-container
*ngIf="
(fileDataService.allLength$ | async) > 0 &&
displayedPages.length === 0 &&
!filterService.noAnnotationsFilterChecked
"
>{{ 'file-preview.tabs.annotations.wrong-filters' | translate }}
<a
(click)="filterService.reset()"
class="with-underline"
translate="file-preview.tabs.annotations.reset"
></a>
{{ 'file-preview.tabs.annotations.the-filters' | translate }}
</ng-container>
</iqser-empty-state>
<div *ngIf="displayedPages.length" class="no-annotations-buttons-container mt-32">
<iqser-icon-button
(action)="jumpToPreviousWithAnnotations()"
[disabled]="pdf.currentPage() <= displayedPages[0]"
[label]="'file-preview.tabs.annotations.jump-to-previous' | translate"
[type]="iconButtonTypes.dark"
icon="iqser:nav-prev"
></iqser-icon-button>
<iqser-icon-button
(action)="jumpToNextWithAnnotations()"
[disabled]="pdf.currentPage() >= displayedPages[displayedPages.length - 1]"
[label]="'file-preview.tabs.annotations.jump-to-next' | translate"
[type]="iconButtonTypes.dark"
class="mt-8"
icon="iqser:nav-next"
></iqser-icon-button>
</div>
</ng-container>
<redaction-annotations-list
(pagesPanelActive)="pagesPanelActive = $event"
[annotations]="annotations.get(pdf.currentPage())"
></redaction-annotations-list>
</div>
}
<redaction-page-exclusion *ngIf="excludedPagesService.shown()"></redaction-page-exclusion>
</div>
</div>
</div>
</div>
}
<ng-template #annotationFilterActionTemplate let-filter="filter">
<iqser-circle-button

View File

@ -25,7 +25,7 @@ import { workloadTranslations } from '@translations/workload-translations';
import { UserPreferenceService } from '@users/user-preference.service';
import { getLocalStorageDataByFileId } from '@utils/local-storage';
import { combineLatest, delay, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { map, tap } from 'rxjs/operators';
import scrollIntoView from 'scroll-into-view-if-needed';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { REDDocumentViewer } from '../../../pdf-viewer/services/document-viewer.service';
@ -182,6 +182,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
delay(0),
map(([annotations, primary, secondary]) => this.#filterAnnotations(annotations, primary, secondary)),
map(annotations => this.#mapListItemsFromAnnotationWrapperArray(annotations)),
tap(annotations => this.#scrollToFirstAnnotationPage(annotations)),
);
}
@ -520,4 +521,11 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
});
return listItemsMap;
}
#scrollToFirstAnnotationPage(annotations: Map<number, ListItem<AnnotationWrapper>[]>) {
if (this.isDocumine && annotations.size && !this.displayedPages.includes(this.pdf.currentPage())) {
const page = annotations.keys().next().value;
this.pdf.navigateTo(page);
}
}
}

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@
[tooltipPosition]="tooltipPosition"
[helpModeKeyPrefix]="helpModeKeyPrefix"
[isDossierOverviewWorkflow]="isDossierOverviewWorkflow"
[file]="file"
></redaction-expandable-file-actions>
</div>
</ng-template>

View File

@ -1,3 +1,14 @@
@if (isDocumine) {
<iqser-circle-button
[attr.help-mode-key]="'component_download'"
[icon]="'red:extract'"
[matMenuTriggerFor]="bulkComponentDownloadMenu"
[tooltip]="'documine-export.export-tooltip' | translate"
[tooltipPosition]="tooltipPosition"
dropdownButton
></iqser-circle-button>
}
<ng-container *ngFor="let btn of displayedButtons; trackBy: trackBy">
<iqser-circle-button
(action)="btn.action($event)"
@ -73,3 +84,8 @@
</ng-container>
</button>
</mat-menu>
<mat-menu #bulkComponentDownloadMenu="matMenu">
<button (click)="downloadComponentAsJSON()" [innerHTML]="'component-download.json' | translate" mat-menu-item></button>
<button (click)="downloadComponentAsXML()" [innerHTML]="'component-download.xml' | translate" mat-menu-item></button>
</mat-menu>

View File

@ -1,6 +1,6 @@
import { Component, inject, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
import { Action, ActionTypes, Dossier, File } from '@red/domain';
import { CircleButtonComponent, CircleButtonType, IqserDialog, StopPropagationDirective, Toaster } from '@iqser/common-ui';
import { CircleButtonComponent, CircleButtonType, getConfig, IqserDialog, StopPropagationDirective, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FileDownloadService } from '@upload-download/services/file-download.service';
import { PermissionsService } from '@services/permissions.service';
@ -13,6 +13,8 @@ import { FileDownloadBtnComponent } from '@shared/components/buttons/file-downlo
import { MatSlideToggle } from '@angular/material/slide-toggle';
import { MatTooltip } from '@angular/material/tooltip';
import { MatIcon } from '@angular/material/icon';
import { firstValueFrom } from 'rxjs';
import { ComponentLogService } from '@services/files/component-log.service';
@Component({
selector: 'redaction-expandable-file-actions',
@ -44,11 +46,13 @@ export class ExpandableFileActionsComponent implements OnChanges {
@Input() tooltipPosition: IqserTooltipPosition;
@Input() helpModeKeyPrefix: 'dossier' | 'editor';
@Input() isDossierOverviewWorkflow = false;
@Input() file: File;
displayedButtons: Action[];
hiddenButtons: Action[];
expanded = false;
@ViewChild(MatMenuTrigger) readonly matMenu: MatMenuTrigger;
readonly trackBy = trackByFactory();
readonly isDocumine = getConfig().IS_DOCUMINE;
readonly #appBaseHref = inject(APP_BASE_HREF);
constructor(
@ -56,6 +60,7 @@ export class ExpandableFileActionsComponent implements OnChanges {
private readonly _toaster: Toaster,
private readonly _permissionsService: PermissionsService,
private readonly _dialog: IqserDialog,
private readonly _componentLogService: ComponentLogService,
) {}
ngOnChanges(changes: SimpleChanges) {
@ -124,4 +129,12 @@ export class ExpandableFileActionsComponent implements OnChanges {
params: { downloadHref: `${this.#appBaseHref}/main/downloads` },
});
}
downloadComponentAsJSON() {
return firstValueFrom(this._componentLogService.exportJSON(this.file.dossierTemplateId, this.file.dossierId, this.file));
}
async downloadComponentAsXML() {
return firstValueFrom(this._componentLogService.exportXML(this.file.dossierTemplateId, this.file.dossierId, this.file));
}
}

View File

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