Refactor complete

This commit is contained in:
Adina Țeudan 2021-10-01 20:44:18 +03:00
parent ed3eba9083
commit 6c6a42b68b
20 changed files with 356 additions and 564 deletions

View File

@ -1,5 +1,4 @@
<iqser-table
[actionsTemplate]="actionsTemplate"
[bulkActions]="bulkActions"
[itemMouseEnterFn]="itemMouseEnterFn"
[itemMouseLeaveFn]="itemMouseLeaveFn"
@ -54,54 +53,50 @@
</ng-container>
</ng-template>
<ng-template #actionsTemplate let-field="entity">
<div class="action-buttons">
<iqser-circle-button
(action)="field.primaryAttribute = false; toggleFieldActive.emit(field)"
[removeTooltip]="true"
[tooltip]="'file-attributes-csv-import.action.remove' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</ng-template>
<ng-template #tableItemTemplate let-field="entity">
<div>
<div class="cell">
<iqser-editable-input
(save)="field.name = $event"
[buttonsType]="circleButtonTypes.dark"
[cancelTooltip]="'file-attributes-csv-import.action.cancel-edit-name' | translate"
[class]="'w-200'"
[editTooltip]="'file-attributes-csv-import.action.edit-name' | translate"
[saveTooltip]="'file-attributes-csv-import.action.save-name' | translate"
[value]="field.name"
></iqser-editable-input>
</div>
<ng-template #labelTemplate let-field="entity">
<div class="cell">
<iqser-editable-input
(save)="field.name = $event"
[buttonsType]="circleButtonTypes.dark"
[cancelTooltip]="'file-attributes-csv-import.action.cancel-edit-name' | translate"
[class]="'w-200'"
[editTooltip]="'file-attributes-csv-import.action.edit-name' | translate"
[saveTooltip]="'file-attributes-csv-import.action.save-name' | translate"
[value]="field.name"
></iqser-editable-input>
</div>
</ng-template>
<div class="cell">
<div class="iqser-input-group">
<mat-form-field class="no-label">
<mat-select [(ngModel)]="field.type">
<mat-option *ngFor="let type of typeOptions" [value]="type">
{{ translations[type] | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<ng-template #typeTemplate let-field="entity">
<div class="cell">
<div class="iqser-input-group">
<mat-form-field class="no-label">
<mat-select [(ngModel)]="field.type">
<mat-option *ngFor="let type of typeOptions" [value]="type">
{{ translations[type] | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<div class="cell center">
<mat-slide-toggle [(ngModel)]="field.readonly" color="primary"></mat-slide-toggle>
</div>
<div class="cell center">
<iqser-round-checkbox (click)="togglePrimary(field)" [active]="field.primaryAttribute"></iqser-round-checkbox>
</div>
<div class="cell">
<div class="action-buttons">
<iqser-circle-button
(action)="field.primaryAttribute = false; toggleFieldActive.emit(field)"
[removeTooltip]="true"
[tooltip]="'file-attributes-csv-import.action.remove' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>
<ng-template #readonlyTemplate let-field="entity">
<div class="cell center">
<mat-slide-toggle [(ngModel)]="field.readonly" color="primary"></mat-slide-toggle>
</div>
</ng-template>
<ng-template #primaryTemplate let-field="entity">
<div class="cell center">
<iqser-round-checkbox (click)="togglePrimary(field)" [active]="field.primaryAttribute"></iqser-round-checkbox>
</div>
</ng-template>

View File

@ -30,19 +30,19 @@
cdk-virtual-scroll-viewport {
height: calc(100% - 80px) !important;
.cdk-virtual-scroll-content-wrapper .table-item > div.cell {
iqser-editable-input:not(.editing) {
padding-left: 12px;
}
iqser-editable-input::ng-deep .edit-button {
display: none;
}
&:hover iqser-editable-input::ng-deep .edit-button {
display: block;
}
}
}
}
.cell {
iqser-editable-input:not(.editing) {
padding-left: 12px;
}
iqser-editable-input::ng-deep .edit-button {
display: none;
}
&:hover iqser-editable-input::ng-deep .edit-button {
display: block;
}
}

View File

@ -1,16 +1,4 @@
import {
Component,
EventEmitter,
forwardRef,
Injector,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
TemplateRef,
ViewChild
} from '@angular/core';
import { Component, EventEmitter, forwardRef, Injector, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Field } from '../file-attributes-csv-import-dialog.component';
import { FileAttributeConfigTypes } from '@redaction/red-ui-http';
import { CircleButtonTypes, DefaultListingServices, ListingComponent, TableColumnConfig } from '@iqser/common-ui';
@ -23,16 +11,35 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
styleUrls: ['./active-fields-listing.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => ActiveFieldsListingComponent) }]
})
export class ActiveFieldsListingComponent extends ListingComponent<Field> implements OnChanges, OnInit {
export class ActiveFieldsListingComponent extends ListingComponent<Field> implements OnChanges {
readonly circleButtonTypes = CircleButtonTypes;
readonly translations = fileAttributeTypesTranslations;
readonly tableHeaderLabel = _('file-attributes-csv-import.table-header.title');
tableColumnConfigs: TableColumnConfig<Field>[];
readonly tableColumnConfigs: TableColumnConfig<Field>[] = [
{
label: _('file-attributes-csv-import.table-col-names.name'),
class: 'name',
width: 'minmax(0, 350px)'
},
{
label: _('file-attributes-csv-import.table-col-names.type'),
width: '150px'
},
{
label: _('file-attributes-csv-import.table-col-names.read-only'),
class: 'flex-center',
leftIcon: 'red:read-only',
width: 'auto'
},
{
label: _('file-attributes-csv-import.table-col-names.primary'),
class: 'flex-center',
rightIcon: 'red:status-info',
rightIconTooltip: _('file-attributes-csv-import.table-col-names.primary-info-tooltip'),
width: 'auto'
}
];
readonly typeOptions = Object.keys(FileAttributeConfigTypes);
@ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef<never>;
@ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef<never>;
@ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef<never>;
@ViewChild('primaryTemplate', { static: true }) primaryTemplate: TemplateRef<never>;
@Input() entities: Field[];
@Output() readonly entitiesChange = new EventEmitter<Field[]>();
@Output() readonly setHoveredColumn = new EventEmitter<string>();
@ -42,10 +49,6 @@ export class ActiveFieldsListingComponent extends ListingComponent<Field> implem
super(_injector);
}
ngOnInit(): void {
this._configureTableColumns();
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.entities) {
this.entitiesService.setEntities(this.entities);
@ -80,35 +83,4 @@ export class ActiveFieldsListingComponent extends ListingComponent<Field> implem
itemMouseEnterFn = (field: Field) => this.setHoveredColumn.emit(field.csvColumn);
itemMouseLeaveFn = () => this.setHoveredColumn.emit();
private _configureTableColumns() {
this.tableColumnConfigs = [
{
label: _('file-attributes-csv-import.table-col-names.name'),
class: 'name',
template: this.labelTemplate,
width: 'minmax(0, 350px)'
},
{
label: _('file-attributes-csv-import.table-col-names.type'),
template: this.typeTemplate,
width: '150px'
},
{
label: _('file-attributes-csv-import.table-col-names.read-only'),
class: 'flex-center',
leftIcon: 'red:read-only',
template: this.readonlyTemplate,
width: 'auto'
},
{
label: _('file-attributes-csv-import.table-col-names.primary'),
class: 'flex-center',
rightIcon: 'red:status-info',
rightIconTooltip: _('file-attributes-csv-import.table-col-names.primary-info-tooltip'),
template: this.primaryTemplate,
width: 'auto'
}
];
}
}

View File

@ -97,24 +97,20 @@
</div>
</ng-template>
<ng-template #messageTemplate let-log="entity">
<div class="cell">
{{ log.message }}
<ng-template #tableItemTemplate let-log="entity">
<div>
<div class="cell">
{{ log.message }}
</div>
<div class="small-label cell">
{{ log.recordDate | date: 'd MMM. yyyy, hh:mm a' }}
</div>
<div class="user-column cell">
<redaction-initials-avatar [userId]="log.userId" [withName]="true" size="small"></redaction-initials-avatar>
</div>
<div [translate]="translations[log.category]" class="cell"></div>
</div>
</ng-template>
<ng-template #dateTemplate let-log="entity">
<div class="small-label cell">
{{ log.recordDate | date: 'd MMM. yyyy, hh:mm a' }}
</div>
</ng-template>
<ng-template #userTemplate let-log="entity">
<div class="user-column cell">
<redaction-initials-avatar [userId]="log.userId" [withName]="true" size="small"></redaction-initials-avatar>
</div>
</ng-template>
<ng-template #categoryTemplate let-log="entity">
<div [translate]="translations[log.category]" class="cell"></div>
</ng-template>

View File

@ -1,4 +1,4 @@
import { Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Component, forwardRef, Injector, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { AuditControllerService, AuditResponse, AuditSearchRequest, IAudit } from '@redaction/red-ui-http';
import { Moment } from 'moment';
@ -22,15 +22,16 @@ export class AuditScreenComponent extends ListingComponent<Audit> implements OnD
readonly ALL_USERS = _('audit-screen.all-users');
readonly translations = auditCategoriesTranslations;
readonly currentUser = this._userService.currentUser;
@ViewChild('messageTemplate', { static: true }) messageTemplate: TemplateRef<unknown>;
@ViewChild('dateTemplate', { static: true }) dateTemplate: TemplateRef<unknown>;
@ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef<unknown>;
@ViewChild('categoryTemplate', { static: true }) categoryTemplate: TemplateRef<unknown>;
filterForm: FormGroup;
categories: string[] = [];
userIds: Set<string>;
logs: AuditResponse;
tableColumnConfigs: TableColumnConfig<Audit>[];
readonly tableColumnConfigs: TableColumnConfig<Audit>[] = [
{ label: _('audit-screen.table-col-names.message') },
{ label: _('audit-screen.table-col-names.date') },
{ label: _('audit-screen.table-col-names.user'), class: 'user-column' },
{ label: _('audit-screen.table-col-names.category') }
];
readonly tableHeaderLabel = _('audit-screen.table-header.title');
private _previousFrom: Moment;
private _previousTo: Moment;
@ -69,32 +70,9 @@ export class AuditScreenComponent extends ListingComponent<Audit> implements OnD
}
async ngOnInit() {
this._configureTableColumns();
await this._fetchData();
}
private _configureTableColumns() {
this.tableColumnConfigs = [
{
label: _('audit-screen.table-col-names.message'),
template: this.messageTemplate
},
{
label: _('audit-screen.table-col-names.date'),
template: this.dateTemplate
},
{
label: _('audit-screen.table-col-names.user'),
class: 'user-column',
template: this.userTemplate
},
{
label: _('audit-screen.table-col-names.category'),
template: this.categoryTemplate
}
];
}
private _updateDateFilters(value): boolean {
if (applyIntervalConstraints(value, this._previousFrom, this._previousTo, this.filterForm, 'from', 'to')) {
return true;

View File

@ -22,7 +22,6 @@
<div class="content-container">
<iqser-table
(noDataAction)="openAddEditAttributeDialog(null)"
[actionsTemplate]="actionsTemplate"
[bulkActions]="bulkActions"
[headerTemplate]="headerTemplate"
[itemSize]="50"
@ -65,38 +64,36 @@
</div>
</ng-template>
<ng-template #actionsTemplate let-attribute="entity">
<div *ngIf="currentUser.isAdmin" class="action-buttons">
<iqser-circle-button
(action)="openAddEditAttributeDialog($event, attribute)"
[tooltip]="'dossier-attributes-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<ng-template #tableItemTemplate let-attribute="entity">
<div>
<div class="cell">
{{ attribute.label }}
</div>
<iqser-circle-button
(action)="openConfirmDeleteAttributeDialog($event, attribute)"
[tooltip]="'dossier-attributes-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</ng-template>
<ng-template #labelTemplate let-attribute="entity">
<div class="cell">
{{ attribute.label }}
</div>
</ng-template>
<ng-template #placeholderTemplate let-attribute="entity">
<div class="cell small-label">
{{ attribute.placeholder }}
</div>
</ng-template>
<ng-template #typeTemplate let-attribute="entity">
<div class="cell small-label">
{{ translations[attribute.type] | translate }}
<div class="cell small-label">
{{ attribute.placeholder }}
</div>
<div class="cell small-label">
{{ translations[attribute.type] | translate }}
</div>
<div class="cell">
<div *ngIf="currentUser.isAdmin" class="action-buttons">
<iqser-circle-button
(action)="openAddEditAttributeDialog($event, attribute)"
[tooltip]="'dossier-attributes-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openConfirmDeleteAttributeDialog($event, attribute)"
[tooltip]="'dossier-attributes-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>

View File

@ -1,4 +1,4 @@
import { Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Component, forwardRef, Injector, OnInit } from '@angular/core';
import {
CircleButtonTypes,
DefaultListingServices,
@ -31,10 +31,11 @@ export class DossierAttributesListingScreenComponent extends ListingComponent<Do
readonly currentUser = this._userService.currentUser;
readonly translations = dossierAttributeTypesTranslations;
readonly tableHeaderLabel = _('dossier-attributes-listing.table-header.title');
tableColumnConfigs: TableColumnConfig<DossierAttributeConfig>[];
@ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef<never>;
@ViewChild('placeholderTemplate', { static: true }) placeholderTemplate: TemplateRef<never>;
@ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef<never>;
readonly tableColumnConfigs: TableColumnConfig<DossierAttributeConfig>[] = [
{ label: _('dossier-attributes-listing.table-col-names.label'), sortByKey: 'label', width: '2fr' },
{ label: _('dossier-attributes-listing.table-col-names.placeholder'), width: '2fr' },
{ label: _('dossier-attributes-listing.table-col-names.type'), sortByKey: 'type' }
];
constructor(
protected readonly _injector: Injector,
@ -50,7 +51,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent<Do
}
async ngOnInit() {
this._configureTableColumns();
await this._loadData();
}
@ -75,27 +75,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent<Do
);
}
private _configureTableColumns() {
this.tableColumnConfigs = [
{
label: _('dossier-attributes-listing.table-col-names.label'),
sortByKey: 'label',
width: '2fr',
template: this.labelTemplate
},
{
label: _('dossier-attributes-listing.table-col-names.placeholder'),
width: '2fr',
template: this.placeholderTemplate
},
{
label: _('dossier-attributes-listing.table-col-names.type'),
sortByKey: 'type',
template: this.typeTemplate
}
];
}
private async _loadData() {
this._loadingService.start();
const attributes = await this._dossierAttributesService.getConfig();

View File

@ -21,7 +21,6 @@
<div class="content-container">
<iqser-table
[actionsTemplate]="actionsTemplate"
[bulkActions]="bulkActions"
[headerTemplate]="headerTemplate"
[itemSize]="80"
@ -75,64 +74,54 @@
</div>
</ng-template>
<ng-template #actionsTemplate let-attribute="entity">
<div *ngIf="currentUser.isAdmin" class="action-buttons">
<iqser-circle-button
(action)="openAddEditAttributeDialog($event, attribute)"
[tooltip]="'file-attributes-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openConfirmDeleteAttributeDialog($event, attribute)"
[tooltip]="'file-attributes-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</ng-template>
<ng-template #labelTemplate let-attribute="entity">
<div class="label cell">
<span>{{ attribute.label }}</span>
</div>
</ng-template>
<ng-template #typeTemplate let-attribute="entity">
<div [translate]="translations[attribute.type]" class="small-label cell"></div>
</ng-template>
<ng-template #readonlyTemplate let-attribute="entity">
<div class="center read-only cell">
<mat-icon
*ngIf="!attribute.editable"
[matTooltip]="'file-attributes-listing.read-only' | translate"
matTooltipPosition="above"
svgIcon="red:read-only"
></mat-icon>
</div>
</ng-template>
<ng-template #csvColumnHeaderTemplate let-attribute="entity">
<div class="small-label cell">
{{ attribute.csvColumnHeader }}
</div>
</ng-template>
<ng-template #filterableTemplate let-attribute="entity">
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.filterable" [active]="true" [size]="18"></iqser-round-checkbox>
</div>
</ng-template>
<ng-template #displayedInFileListTemplate let-attribute="entity">
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.displayedInFileList" [active]="true" [size]="18"></iqser-round-checkbox>
</div>
</ng-template>
<ng-template #primaryAttributeTemplate let-attribute="entity">
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.primaryAttribute" [active]="true" [size]="18"></iqser-round-checkbox>
<ng-template #tableItemTemplate let-attribute="entity">
<div>
<div class="label cell">
<span>{{ attribute.label }}</span>
</div>
<div [translate]="translations[attribute.type]" class="small-label cell"></div>
<div class="center read-only cell">
<mat-icon
*ngIf="!attribute.editable"
[matTooltip]="'file-attributes-listing.read-only' | translate"
matTooltipPosition="above"
svgIcon="red:read-only"
></mat-icon>
</div>
<div class="small-label cell">
{{ attribute.csvColumnHeader }}
</div>
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.filterable" [active]="true" [size]="18"></iqser-round-checkbox>
</div>
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.displayedInFileList" [active]="true" [size]="18"></iqser-round-checkbox>
</div>
<div class="center cell">
<iqser-round-checkbox *ngIf="attribute.primaryAttribute" [active]="true" [size]="18"></iqser-round-checkbox>
</div>
<div class="cell">
<div *ngIf="currentUser.isAdmin" class="action-buttons">
<iqser-circle-button
(action)="openAddEditAttributeDialog($event, attribute)"
[tooltip]="'file-attributes-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openConfirmDeleteAttributeDialog($event, attribute)"
[tooltip]="'file-attributes-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>

View File

@ -1,10 +1,6 @@
@use 'common-mixins';
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
&.center {
align-items: center;
}
.cell {
&.label span {
@include common-mixins.line-clamp(1);
}

View File

@ -1,14 +1,4 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
forwardRef,
Injector,
OnDestroy,
OnInit,
TemplateRef,
ViewChild
} from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, forwardRef, Injector, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FileAttributesConfig, IFileAttributeConfig } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { ActivatedRoute } from '@angular/router';
@ -42,14 +32,20 @@ export class FileAttributesListingScreenComponent extends ListingComponent<FileA
readonly currentUser = this._userService.currentUser;
readonly translations = fileAttributeTypesTranslations;
readonly tableHeaderLabel = _('file-attributes-listing.table-header.title');
tableColumnConfigs: TableColumnConfig<FileAttributeConfig>[];
@ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef<unknown>;
@ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef<unknown>;
@ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef<unknown>;
@ViewChild('csvColumnHeaderTemplate', { static: true }) csvColumnHeaderTemplate: TemplateRef<unknown>;
@ViewChild('filterableTemplate', { static: true }) filterableTemplate: TemplateRef<unknown>;
@ViewChild('displayedInFileListTemplate', { static: true }) displayedInFileListTemplate: TemplateRef<unknown>;
@ViewChild('primaryAttributeTemplate', { static: true }) primaryAttributeTemplate: TemplateRef<unknown>;
readonly tableColumnConfigs: TableColumnConfig<FileAttributeConfig>[] = [
{ label: _('file-attributes-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' },
{ label: _('file-attributes-listing.table-col-names.type'), sortByKey: 'type' },
{ label: _('file-attributes-listing.table-col-names.read-only'), sortByKey: 'editable', class: 'flex-center' },
{ label: _('file-attributes-listing.table-col-names.csv-column') },
{ label: _('file-attributes-listing.table-col-names.filterable'), class: 'flex-center' },
{ label: _('file-attributes-listing.table-col-names.displayed-in-file-list'), class: 'flex-center' },
{
label: _('file-attributes-listing.table-col-names.primary'),
class: 'flex-center',
rightIcon: 'red:status-info',
rightIconTooltip: _('file-attributes-listing.table-col-names.primary-info-tooltip')
}
];
private _existingConfiguration: FileAttributesConfig;
@ViewChild('fileInput') private _fileInput: ElementRef;
@ -67,7 +63,6 @@ export class FileAttributesListingScreenComponent extends ListingComponent<FileA
}
async ngOnInit() {
this._configureTableColumns();
await this._loadData();
}
@ -123,46 +118,6 @@ export class FileAttributesListingScreenComponent extends ListingComponent<FileA
);
}
private _configureTableColumns() {
this.tableColumnConfigs = [
{
label: _('file-attributes-listing.table-col-names.name'),
sortByKey: 'searchKey',
width: '2fr',
template: this.labelTemplate
},
{
label: _('file-attributes-listing.table-col-names.type'),
sortByKey: 'type',
template: this.typeTemplate
},
{
label: _('file-attributes-listing.table-col-names.read-only'),
sortByKey: 'editable',
class: 'flex-center',
template: this.readonlyTemplate
},
{ label: _('file-attributes-listing.table-col-names.csv-column'), template: this.csvColumnHeaderTemplate },
{
label: _('file-attributes-listing.table-col-names.filterable'),
class: 'flex-center',
template: this.filterableTemplate
},
{
label: _('file-attributes-listing.table-col-names.displayed-in-file-list'),
class: 'flex-center',
template: this.displayedInFileListTemplate
},
{
label: _('file-attributes-listing.table-col-names.primary'),
class: 'flex-center',
rightIcon: 'red:status-info',
rightIconTooltip: _('file-attributes-listing.table-col-names.primary-info-tooltip'),
template: this.primaryAttributeTemplate
}
];
}
private async _loadData() {
this._loadingService.start();

View File

@ -33,7 +33,6 @@
<div class="red-content-inner">
<div [class.extended]="collapsedDetails" class="content-container">
<iqser-table
[actionsTemplate]="actionsTemplate"
[bulkActions]="bulkActions"
[itemSize]="80"
[noMatchText]="'user-listing.no-match.title' | translate"
@ -66,40 +65,36 @@
></iqser-circle-button>
</ng-template>
<ng-template #nameTemplate let-user="entity">
<div class="cell">
<redaction-initials-avatar [showYou]="true" [userId]="user.id" [withName]="true"></redaction-initials-avatar>
</div>
</ng-template>
<ng-template #emailTemplate let-user="entity">
<div class="small-label cell">{{ user.email || '-' }}</div>
</ng-template>
<ng-template #activeTemplate let-user="entity">
<div class="center cell">
<mat-slide-toggle (toggleChange)="toggleActive(user)" [checked]="user.isActive" color="primary"></mat-slide-toggle>
</div>
</ng-template>
<ng-template #rolesTemplate let-user="entity">
<div class="small-label cell">{{ getDisplayRoles(user) }}</div>
</ng-template>
<ng-template #actionsTemplate let-user="entity">
<div class="action-buttons">
<iqser-circle-button
(action)="openAddEditUserDialog($event, user)"
[tooltip]="'user-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openDeleteUsersDialog([user], $event)"
[disabled]="user.id === userService.currentUser.id"
[tooltip]="'user-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
<ng-template #tableItemTemplate let-user="entity">
<div>
<div class="cell">
<redaction-initials-avatar [showYou]="true" [userId]="user.id" [withName]="true"></redaction-initials-avatar>
</div>
<div class="small-label cell">{{ user.email || '-' }}</div>
<div class="center cell">
<mat-slide-toggle (toggleChange)="toggleActive(user)" [checked]="user.isActive" color="primary"></mat-slide-toggle>
</div>
<div class="small-label cell">{{ getDisplayRoles(user) }}</div>
<div class="cell">
<div class="action-buttons">
<iqser-circle-button
(action)="openAddEditUserDialog($event, user)"
[tooltip]="'user-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>
<iqser-circle-button
(action)="openDeleteUsersDialog([user], $event)"
[disabled]="user.id === userService.currentUser.id"
[tooltip]="'user-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>

View File

@ -1,7 +1,3 @@
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell.center {
align-items: center;
}
.right-container {
display: flex;
width: 353px;

View File

@ -1,4 +1,4 @@
import { Component, forwardRef, Injector, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren } from '@angular/core';
import { Component, forwardRef, Injector, OnInit, QueryList, ViewChildren } from '@angular/core';
import { UserService } from '@services/user.service';
import { UserControllerService } from '@redaction/red-ui-http';
import { AdminDialogService } from '../../services/admin-dialog.service';
@ -32,13 +32,14 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
readonly currentUser = this.userService.currentUser;
readonly canDeleteSelected$ = this._canDeleteSelected$;
readonly tableHeaderLabel = _('user-listing.table-header.title');
tableColumnConfigs: TableColumnConfig<User>[];
readonly tableColumnConfigs: TableColumnConfig<User>[] = [
{ label: _('user-listing.table-col-names.name'), width: '2fr' },
{ label: _('user-listing.table-col-names.email') },
{ label: _('user-listing.table-col-names.active'), class: 'flex-center' },
{ label: _('user-listing.table-col-names.roles') }
];
collapsedDetails = false;
chartData: DoughnutChartConfig[] = [];
@ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef<never>;
@ViewChild('emailTemplate', { static: true }) emailTemplate: TemplateRef<never>;
@ViewChild('activeTemplate', { static: true }) activeTemplate: TemplateRef<never>;
@ViewChild('rolesTemplate', { static: true }) rolesTemplate: TemplateRef<never>;
@ViewChildren(InitialsAvatarComponent)
private readonly _avatars: QueryList<InitialsAvatarComponent>;
@ -60,7 +61,6 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
}
async ngOnInit() {
this._configureTableColumns();
await this._loadData();
}
@ -96,15 +96,6 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
this.openDeleteUsersDialog(this.entitiesService.all.filter(u => this.isSelected(u)));
}
private _configureTableColumns() {
this.tableColumnConfigs = [
{ label: _('user-listing.table-col-names.name'), template: this.nameTemplate, width: '2fr' },
{ label: _('user-listing.table-col-names.email'), template: this.emailTemplate },
{ label: _('user-listing.table-col-names.active'), class: 'flex-center', template: this.activeTemplate },
{ label: _('user-listing.table-col-names.roles'), template: this.rolesTemplate }
];
}
private async _loadData() {
this.entitiesService.setEntities(await this.userService.loadAllUsers());
await this.userService.loadAllUsers();

View File

@ -34,45 +34,41 @@
></iqser-circle-button>
</ng-template>
<ng-template #filenameTemplate let-file="entity">
<div class="cell filename">
<span>{{ file.filename }}</span>
</div>
</ng-template>
<ng-template #tableItemTemplate let-file="entity">
<div>
<div class="cell filename">
<span>{{ file.filename }}</span>
</div>
<ng-template #pagesTemplate let-file="entity">
<div class="cell stats-subtitle">
<div class="small-label">
<mat-icon svgIcon="red:pages"></mat-icon>
{{ file.numberOfPages }}
</div>
</div>
</ng-template>
<ng-template #deletedDateTemplate let-file="entity">
<div class="cell">
<span class="small-label">{{ file.softDeleted | date: 'exactDate' }}</span>
</div>
</ng-template>
<ng-template #restoreDateTemplate let-file="entity">
<div class="cell">
<div class="small-label">{{ file.restoreDate | date: 'timeFromNow' }}</div>
<div class="action-buttons">
<iqser-circle-button
(action)="restore([file])"
*ngIf="file.canRestore"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.restore' | translate"
[type]="circleButtonTypes.dark"
icon="red:put-back"
></iqser-circle-button>
<iqser-circle-button
(action)="hardDelete([file])"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
<div class="cell stats-subtitle">
<div class="small-label">
<mat-icon svgIcon="red:pages"></mat-icon>
{{ file.numberOfPages }}
</div>
</div>
<div class="cell">
<span class="small-label">{{ file.softDeleted | date: 'exactDate' }}</span>
</div>
<div class="cell">
<div class="small-label">{{ file.restoreDate | date: 'timeFromNow' }}</div>
<div class="action-buttons">
<iqser-circle-button
(action)="restore([file])"
*ngIf="file.canRestore"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.restore' | translate"
[type]="circleButtonTypes.dark"
icon="red:put-back"
></iqser-circle-button>
<iqser-circle-button
(action)="hardDelete([file])"
[tooltip]="'edit-dossier-dialog.deleted-documents.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash"
></iqser-circle-button>
</div>
</div>
</div>
</ng-template>

View File

@ -9,8 +9,8 @@
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport {
height: calc(100% - 81px) !important;
.cdk-virtual-scroll-content-wrapper .table-item > div.cell.filename span {
@include common-mixins.line-clamp(1);
}
}
.cell.filename span {
@include common-mixins.line-clamp(1);
}

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output } from '@angular/core';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Dossier } from '@state/model/dossier';
import {
@ -42,14 +42,15 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
readonly changed = false;
readonly canRestoreSelected$ = this._canRestoreSelected$;
disabled: boolean;
tableColumnConfigs: TableColumnConfig<FileListItem>[];
readonly tableColumnConfigs: TableColumnConfig<FileListItem>[] = [
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.name'), width: '3fr' },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.pages') },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.deleted-on'), sortByKey: 'softDeleted', width: '2fr' },
{ label: _('edit-dossier-dialog.deleted-documents.table-col-names.time-to-restore'), sortByKey: 'softDeleted', width: '2fr' }
];
readonly tableHeaderLabel = _('edit-dossier-dialog.deleted-documents.table-header.label');
readonly circleButtonTypes = CircleButtonTypes;
readonly deleteRetentionHours = this._configService.values.DELETE_RETENTION_HOURS;
@ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef<never>;
@ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef<never>;
@ViewChild('deletedDateTemplate', { static: true }) deletedDateTemplate: TemplateRef<never>;
@ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef<never>;
constructor(
protected readonly _injector: Injector,
@ -89,7 +90,6 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
}
async ngOnInit() {
this._configureTableColumns();
this._loadingService.start();
const files = await this._filesService.getDeletedFilesFor(this.dossier.id).toPromise();
this.entitiesService.setEntities(this._toListItems(files));
@ -110,32 +110,6 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
disabledFn = (file: FileListItem) => !file.canRestore;
private _configureTableColumns() {
this.tableColumnConfigs = [
{
label: _('edit-dossier-dialog.deleted-documents.table-col-names.name'),
template: this.filenameTemplate,
width: '3fr'
},
{
label: _('edit-dossier-dialog.deleted-documents.table-col-names.pages'),
template: this.pagesTemplate
},
{
label: _('edit-dossier-dialog.deleted-documents.table-col-names.deleted-on'),
template: this.deletedDateTemplate,
sortByKey: 'softDeleted',
width: '2fr'
},
{
label: _('edit-dossier-dialog.deleted-documents.table-col-names.time-to-restore'),
template: this.restoreDateTemplate,
sortByKey: 'softDeleted',
width: '2fr'
}
];
}
private async _restore(files: FileListItem[]): Promise<void> {
const fileIds = files.map(f => f.fileId);
await this._fileManagementController.restoreFiles(fileIds, this.dossier.id).toPromise();

View File

@ -21,66 +21,64 @@
</div>
</section>
<ng-template #filenameTemplate let-item="entity">
<div class="cell filename">
<div [matTooltip]="item.filename" class="table-item-title heading" matTooltipPosition="above">
<span
*ngIf="item.highlights.filename; else defaultFilename"
[innerHTML]="item.highlights.filename[0]"
class="highlights"
></span>
<ng-template #defaultFilename>{{ item.filename }}</ng-template>
</div>
<ng-container *ngIf="item.highlights['sections.text'] as highlights">
<div *ngIf="highlights.length > 0" class="small-label">
<span [innerHTML]="highlights[0]" class="highlights"></span>
<ng-template #tableItemTemplate let-item="entity">
<div>
<div class="cell filename">
<div [matTooltip]="item.filename" class="table-item-title heading" matTooltipPosition="above">
<span
*ngIf="item.highlights.filename; else defaultFilename"
[innerHTML]="item.highlights.filename[0]"
class="highlights"
></span>
<ng-template #defaultFilename>{{ item.filename }}</ng-template>
</div>
<div *ngIf="highlights.length > 1" class="small-label">
<span [innerHTML]="highlights[1]" class="highlights"></span>
<ng-container *ngIf="item.highlights['sections.text'] as highlights">
<div *ngIf="highlights.length > 0" class="small-label">
<span [innerHTML]="highlights[0]" class="highlights"></span>
</div>
<div *ngIf="highlights.length > 1" class="small-label">
<span [innerHTML]="highlights[1]" class="highlights"></span>
</div>
</ng-container>
<div *ngIf="item.unmatched?.length && item.unmatched as unmatched" class="small-label">
<span>
{{ 'search-screen.missing' | translate }}:<span *ngFor="let term of unmatched"
>&nbsp;<s>{{ term }}</s></span
>.&nbsp;{{ 'search-screen.must-contain' | translate }}:
<span
(click)="$event.stopPropagation(); updateNavigation(search$.getValue().query, term)"
*ngFor="let term of unmatched"
>&nbsp;<u>{{ term }}</u></span
>
</span>
</div>
</ng-container>
</div>
<div *ngIf="item.unmatched?.length && item.unmatched as unmatched" class="small-label">
<span>
{{ 'search-screen.missing' | translate }}:<span *ngFor="let term of unmatched"
>&nbsp;<s>{{ term }}</s></span
>.&nbsp;{{ 'search-screen.must-contain' | translate }}:
<span (click)="$event.stopPropagation(); updateNavigation(search$.getValue().query, term)" *ngFor="let term of unmatched"
>&nbsp;<u>{{ term }}</u></span
>
</span>
</div>
</div>
</ng-template>
<ng-template #statusTemplate let-item="entity">
<div class="cell">
<iqser-status-bar
[configs]="[
{
color: item.status,
label: fileStatusTranslations[item.status] | translate,
length: 1,
cssClass: 'all-caps-label'
}
]"
[small]="true"
></iqser-status-bar>
</div>
</ng-template>
<ng-template #dossierTemplate let-item="entity">
<div class="cell small-label">
{{ item.dossierName }}
</div>
</ng-template>
<ng-template #pagesTemplate let-item="entity">
<div class="cell small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ item.numberOfPages }}
<div class="cell">
<iqser-status-bar
[configs]="[
{
color: item.status,
label: fileStatusTranslations[item.status] | translate,
length: 1,
cssClass: 'all-caps-label'
}
]"
[small]="true"
></iqser-status-bar>
</div>
<div class="cell small-label">
{{ item.dossierName }}
</div>
<div class="cell small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
{{ item.numberOfPages }}
</div>
</div>
</div>
</ng-template>

View File

@ -1,11 +1,9 @@
@use 'common-mixins';
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
.highlights {
@include common-mixins.line-clamp(1);
.cell .highlights::ng-deep {
@include common-mixins.line-clamp(1);
em {
background-color: #fffcc4;
}
em {
background-color: #fffcc4;
}
}

View File

@ -1,4 +1,4 @@
import { Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { Component, forwardRef, Injector, OnDestroy } from '@angular/core';
import {
DefaultListingServices,
IListable,
@ -40,17 +40,17 @@ interface SearchInput {
styleUrls: ['./search-screen.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => SearchScreenComponent) }]
})
export class SearchScreenComponent extends ListingComponent<ListItem> implements OnDestroy, OnInit {
export class SearchScreenComponent extends ListingComponent<ListItem> implements OnDestroy {
readonly fileStatusTranslations = fileStatusTranslations;
readonly searchPositions = SearchPositions;
@ViewChild('filenameTemplate', { static: true }) readonly filenameTemplate: TemplateRef<unknown>;
@ViewChild('statusTemplate', { static: true }) readonly statusTemplate: TemplateRef<unknown>;
@ViewChild('dossierTemplate', { static: true }) readonly dossierTemplate: TemplateRef<unknown>;
@ViewChild('pagesTemplate', { static: true }) readonly pagesTemplate: TemplateRef<unknown>;
readonly tableHeaderLabel = _('search-screen.table-header');
tableColumnConfigs: TableColumnConfig<ListItem>[];
readonly tableColumnConfigs: TableColumnConfig<ListItem>[] = [
{ label: _('search-screen.cols.document'), width: '2fr' },
{ label: _('search-screen.cols.status') },
{ label: _('search-screen.cols.dossier') },
{ label: _('search-screen.cols.pages'), width: 'auto' }
];
readonly search$ = new BehaviorSubject<SearchInput>(null);
readonly searchResults$: Observable<ListItem[]> = this.search$.asObservable().pipe(
switchMap(query => this._search(query)),
@ -108,19 +108,6 @@ export class SearchScreenComponent extends ListingComponent<ListItem> implements
this._router.navigate([], { queryParams }).then();
}
ngOnInit(): void {
this._configureTableColumns();
}
private _configureTableColumns() {
this.tableColumnConfigs = [
{ label: _('search-screen.cols.document'), template: this.filenameTemplate, width: '2fr' },
{ label: _('search-screen.cols.status'), template: this.statusTemplate },
{ label: _('search-screen.cols.dossier'), template: this.dossierTemplate },
{ label: _('search-screen.cols.pages'), template: this.pagesTemplate, width: 'auto' }
];
}
private _search(searchInput: SearchInput): Observable<SearchResult> {
return this._searchControllerService.search({
dossierIds: [...searchInput.dossierIds],

View File

@ -1375,7 +1375,7 @@
"table-header": "{length} search {length, plural, one{result} other{results}}"
},
"search": {
"entire-platform": "accross all dossiers",
"entire-platform": "across all dossiers",
"placeholder": "Search documents...",
"this-dossier": "in this dossier"
},