RED-8748 - WIP on filtering components
This commit is contained in:
parent
1d2485db3c
commit
f709edb2ee
@ -6,7 +6,7 @@
|
||||
class="mt-6 mr-10"
|
||||
></redaction-annotation-icon>
|
||||
|
||||
<div class="flex-1">
|
||||
<div [class.flex-1]="!isDocumine">
|
||||
<div>
|
||||
<strong>{{ annotation.superTypeLabel | translate }}</strong>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div *ngIf="annotation.typeLabel">
|
||||
<div *ngIf="annotation.typeLabel" [class.type-label]="isDocumine">
|
||||
<strong>
|
||||
<span>{{ annotation.descriptor | translate }}</span
|
||||
>:
|
||||
|
||||
@ -3,6 +3,13 @@
|
||||
position: relative;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
|
||||
.type-label {
|
||||
width: 130px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.active-icon-marker-container {
|
||||
|
||||
@ -3,6 +3,7 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { annotationTypesTranslations } from '@translations/annotation-types-translations';
|
||||
import { Roles } from '@users/roles';
|
||||
import { getConfig } from '@iqser/common-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-annotation-card',
|
||||
@ -10,8 +11,9 @@ import { Roles } from '@users/roles';
|
||||
styleUrls: ['./annotation-card.component.scss'],
|
||||
})
|
||||
export class AnnotationCardComponent {
|
||||
readonly roles = Roles;
|
||||
readonly annotationTypesTranslations = annotationTypesTranslations;
|
||||
protected readonly roles = Roles;
|
||||
protected readonly annotationTypesTranslations = annotationTypesTranslations;
|
||||
protected readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||
@Input() annotation: AnnotationWrapper;
|
||||
@Input() isSelected = false;
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
(click)="annotationClicked(annotation.item, $event)"
|
||||
[annotation]="annotation"
|
||||
[id]="'annotation-' + annotation.item.id"
|
||||
[class.documine-wrapper]="isDocumine"
|
||||
></redaction-annotation-wrapper>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
@include common-mixins.scroll-bar;
|
||||
}
|
||||
|
||||
&.has-scrollbar:hover redaction-annotation-wrapper::ng-deep {
|
||||
&.has-scrollbar:hover redaction-annotation-wrapper::ng-deep,
|
||||
&::ng-deep.documine-wrapper {
|
||||
.annotation {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ChangeDetectorRef, Component, computed, ElementRef, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { HasScrollbarDirective } from '@iqser/common-ui';
|
||||
import { getConfig, HasScrollbarDirective } from '@iqser/common-ui';
|
||||
import { FilterService } from '@iqser/common-ui/lib/filtering';
|
||||
import { IqserEventTarget } from '@iqser/common-ui/lib/utils';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
@ -26,6 +26,7 @@ export class AnnotationsListComponent extends HasScrollbarDirective {
|
||||
}
|
||||
return [] as EarmarkGroup[];
|
||||
});
|
||||
protected readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||
|
||||
constructor(
|
||||
protected readonly _elementRef: ElementRef,
|
||||
|
||||
@ -11,10 +11,9 @@
|
||||
(action)="edit()"
|
||||
*ngIf="canEdit"
|
||||
[tooltip]="'component-management.actions.edit' | translate"
|
||||
class="ml-2"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
<div class="changes-dot"></div>
|
||||
<div class="changes-dot" *ngIf="entry.componentValues[0].value !== entry.componentValues[0].originalValue && canEdit"></div>
|
||||
</div>
|
||||
</div>
|
||||
<mat-icon *ngIf="!editing" class="arrow-right" svgIcon="red:arrow-right"></mat-icon>
|
||||
@ -22,41 +21,41 @@
|
||||
|
||||
<ng-template #editValue>
|
||||
<form [formGroup]="form" (submit)="save()">
|
||||
<ng-container *ngFor="let componentValue of entry.componentValues; let index = index">
|
||||
<div class="editing-value" *ngIf="form.get(index.toString())">
|
||||
<ng-container *ngFor="let control of form.controls | keyvalue">
|
||||
<div class="editing-value">
|
||||
<mat-icon class="draggable" svgIcon="red:draggable-dots"></mat-icon>
|
||||
<div class="iqser-input-group w-400">
|
||||
<textarea [formControlName]="index" rows="1" type="text"></textarea>
|
||||
<div class="iqser-input-group w-full">
|
||||
<textarea [formControlName]="control.key" rows="1" type="text"></textarea>
|
||||
</div>
|
||||
<iqser-circle-button
|
||||
(action)="removeValue(index)"
|
||||
(action)="removeValue(control.key)"
|
||||
[tooltip]="'component-management.actions.delete' | translate"
|
||||
class="ml-2"
|
||||
class="remove-value"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="editing-actions">
|
||||
<iqser-icon-button
|
||||
[disabled]="disabled"
|
||||
(action)="save()"
|
||||
[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>
|
||||
|
||||
<!-- *ngIf="entry.componentValues[0].value !== entry.componentValues[0].originalValue && canEdit"-->
|
||||
<div class="flex right">
|
||||
<iqser-circle-button
|
||||
*ngIf="entry.componentValues[0].value !== entry.componentValues[0].originalValue && canEdit"
|
||||
(action)="undo(entry.originalKey)"
|
||||
[showDot]="true"
|
||||
[tooltip]="'component-management.actions.undo' | translate"
|
||||
class="ml-2"
|
||||
class="undo-value"
|
||||
icon="red:undo"
|
||||
></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="add()"
|
||||
[tooltip]="'component-management.actions.add' | translate"
|
||||
class="ml-2"
|
||||
class="add-value"
|
||||
icon="iqser:plus"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
@ -90,18 +90,26 @@
|
||||
|
||||
.editing-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 0 10px 22px;
|
||||
|
||||
.iqser-input-group {
|
||||
margin-top: 0;
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
textarea::-webkit-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
textarea::-moz-resizer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
iqser-circle-button {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.draggable {
|
||||
margin-top: 7px;
|
||||
cursor: grab;
|
||||
}
|
||||
}
|
||||
@ -111,11 +119,30 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin: 20px 10px 10px 22px;
|
||||
margin: 30px 10px 10px 22px;
|
||||
|
||||
.right {
|
||||
margin-left: auto;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .add-value {
|
||||
mat-icon {
|
||||
transform: scale(2);
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .undo-value {
|
||||
mat-icon {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .remove-value {
|
||||
mat-icon {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,36 +1,29 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ComponentLogEntry } from '@red/domain';
|
||||
import { FormBuilder, FormControl, UntypedFormGroup } from '@angular/forms';
|
||||
import { IconButtonTypes } from '@iqser/common-ui';
|
||||
import { BaseFormComponent } from '@iqser/common-ui';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-editable-structured-component-value [entry] [canEdit]',
|
||||
templateUrl: './editable-structured-component-value.component.html',
|
||||
styleUrls: ['/editable-structured-component-value.component.scss'],
|
||||
})
|
||||
export class EditableStructuredComponentValueComponent implements OnInit {
|
||||
export class EditableStructuredComponentValueComponent extends BaseFormComponent implements OnInit {
|
||||
@Input() entry: ComponentLogEntry;
|
||||
@Input() canEdit: boolean;
|
||||
@Output() readonly deselectLast = new EventEmitter();
|
||||
|
||||
protected readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
form: UntypedFormGroup;
|
||||
selected = false;
|
||||
editing = false;
|
||||
|
||||
constructor(private readonly _formBuilder: FormBuilder) {}
|
||||
constructor(private readonly _formBuilder: FormBuilder) {
|
||||
super();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form = this.#getForm();
|
||||
}
|
||||
|
||||
#getForm() {
|
||||
const form = this._formBuilder.group({});
|
||||
this.entry.componentValues.forEach((value, index) => {
|
||||
form.addControl(index.toString(), this._formBuilder.control(value.value ?? value.originalValue));
|
||||
});
|
||||
return form;
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
select() {
|
||||
@ -56,23 +49,26 @@ export class EditableStructuredComponentValueComponent implements OnInit {
|
||||
this.editing = false;
|
||||
}
|
||||
|
||||
removeValue(key: number) {
|
||||
this.form.removeControl(key.toString());
|
||||
removeValue(key: string) {
|
||||
this.form.removeControl(key);
|
||||
}
|
||||
|
||||
save() {}
|
||||
async save() {
|
||||
const value = this.form.getRawValue();
|
||||
}
|
||||
|
||||
undo(originalKey: string) {}
|
||||
|
||||
add() {
|
||||
const key = (Object.keys(this.form.controls).length + 1).toString();
|
||||
const key = Object.keys(this.form.controls).length.toString();
|
||||
this.form.addControl(key, new FormControl(''));
|
||||
this.entry.componentValues.push({
|
||||
value: '',
|
||||
originalValue: '',
|
||||
valueDescription: '',
|
||||
componentRuleId: '',
|
||||
entityReferences: [],
|
||||
}
|
||||
|
||||
#getForm() {
|
||||
const form = this._formBuilder.group({});
|
||||
this.entry.componentValues.forEach((value, index) => {
|
||||
form.addControl(index.toString(), this._formBuilder.control(value.value ?? value.originalValue));
|
||||
});
|
||||
return form;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class="components-header">
|
||||
<span [translate]="'component-management.components'"></span>
|
||||
<iqser-popup-filter [primaryFiltersSlug]="'primaryFilters'" [secondaryFiltersSlug]="'secondaryFilters'"></iqser-popup-filter>
|
||||
<iqser-popup-filter [primaryFiltersSlug]="'componentLogFilters'"></iqser-popup-filter>
|
||||
</div>
|
||||
|
||||
<div *ngIf="componentLogData() as componentLogEntries" class="components-container">
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Input, QueryList, signal, ViewChildren } from '@angular/core';
|
||||
import { Component, Input, signal, ViewChildren } from '@angular/core';
|
||||
import { ComponentLogEntry, Dictionary, File, WorkflowFileStatuses } from '@red/domain';
|
||||
import { IconButtonTypes, LoadingService } from '@iqser/common-ui';
|
||||
import { ComponentLogService } from '@services/files/component-log.service';
|
||||
@ -7,6 +7,8 @@ import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { List } from '@common-ui/utils';
|
||||
import { EditableStructuredComponentValueComponent } from '../editable-structured-component-value/editable-structured-component-value.component';
|
||||
import { FilterService } from '@common-ui/filtering';
|
||||
import { ComponentLogFilterService } from '../../services/component-log-filter.service';
|
||||
|
||||
interface DeselectEvent {
|
||||
name: string;
|
||||
@ -31,6 +33,8 @@ export class StructuredComponentManagementComponent {
|
||||
private readonly _componentLogService: ComponentLogService,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _componentLogFilterService: ComponentLogFilterService,
|
||||
private readonly _filterService: FilterService,
|
||||
readonly userPreferences: UserPreferenceService,
|
||||
) {}
|
||||
|
||||
@ -100,6 +104,7 @@ export class StructuredComponentManagementComponent {
|
||||
const componentLogData = await firstValueFrom(
|
||||
this._componentLogService.getComponentLogData(this.file.dossierTemplateId, this.file.dossierId, this.file.fileId),
|
||||
);
|
||||
this.#computeFilters(componentLogData);
|
||||
this.#updateDisplayValue(componentLogData);
|
||||
this.componentLogData.set(componentLogData);
|
||||
this._loadingService.stop();
|
||||
@ -120,4 +125,9 @@ export class StructuredComponentManagementComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#computeFilters(componentLogs: ComponentLogEntry[]) {
|
||||
const filterGroups = this._componentLogFilterService.filterGroups(componentLogs);
|
||||
this._filterService.addFilterGroups(filterGroups);
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ import { PdfProxyService } from './services/pdf-proxy.service';
|
||||
import { SkippedService } from './services/skipped.service';
|
||||
import { StampService } from './services/stamp.service';
|
||||
import { ViewModeService } from './services/view-mode.service';
|
||||
import { ComponentLogFilterService } from './services/component-log-filter.service';
|
||||
|
||||
export const filePreviewScreenProviders = [
|
||||
FilterService,
|
||||
@ -38,4 +39,5 @@ export const filePreviewScreenProviders = [
|
||||
SearchService,
|
||||
StampService,
|
||||
PdfProxyService,
|
||||
ComponentLogFilterService,
|
||||
];
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ComponentLogEntry } from '@red/domain';
|
||||
import { NestedFilter } from '@common-ui/filtering';
|
||||
import { componentLogChecker } from '@utils/filter-utils';
|
||||
|
||||
@Injectable()
|
||||
export class ComponentLogFilterService {
|
||||
filterGroups(entities: ComponentLogEntry[]) {
|
||||
const allDistinctComponentLogs = new Set<string>();
|
||||
|
||||
entities?.forEach(entry => allDistinctComponentLogs.add(entry.name));
|
||||
|
||||
const componentLogFilters = [...allDistinctComponentLogs].map(
|
||||
id =>
|
||||
new NestedFilter({
|
||||
id: id,
|
||||
label: id,
|
||||
}),
|
||||
);
|
||||
|
||||
return [
|
||||
{
|
||||
slug: 'componentLogFilters',
|
||||
filters: componentLogFilters,
|
||||
checker: componentLogChecker,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { handleCheckedValue, INestedFilter } from '@iqser/common-ui/lib/filtering';
|
||||
import { Dossier, File, User, UserType } from '@red/domain';
|
||||
import { ComponentLogEntry, Dossier, File, User, UserType } from '@red/domain';
|
||||
|
||||
export function handleFilterDelta(oldFilters: INestedFilter[], newFilters: INestedFilter[], allFilters: INestedFilter[]) {
|
||||
const newFiltersDelta = {};
|
||||
@ -84,6 +84,8 @@ export const dossierTemplateChecker = (dw: Dossier, filter: INestedFilter) => dw
|
||||
export const dossierStateChecker = (dw: Dossier, filter: INestedFilter) =>
|
||||
dw.dossierStatusId === (filter.id === 'undefined' ? null : filter.id);
|
||||
|
||||
export const componentLogChecker = (componentLogEntry: ComponentLogEntry, filter: INestedFilter) => componentLogEntry.name === filter.id;
|
||||
|
||||
export const userTypeFilters: { [key in UserType]: (user: User) => boolean } = {
|
||||
INACTIVE: (user: User) => !user.hasAnyRole,
|
||||
REGULAR: (user: User) => user.roles.length === 1 && user.roles[0] === 'RED_USER',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user