File Attributes
- added 'filterable' and 'displayedInFileList' to file attributes - added dynamic filters and columns for new added file attributes
This commit is contained in:
parent
8ce3b1b51e
commit
232f2df003
@ -51,6 +51,18 @@
|
||||
{{ 'add-edit-file-attribute.form.primary' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group mt-0">
|
||||
<mat-checkbox color="primary" formControlName="filterable" name="filterable">
|
||||
{{ 'add-edit-file-attribute.form.filterable' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="red-input-group mt-0">
|
||||
<mat-checkbox color="primary" formControlName="displayedInFileList" name="displayedInFileList">
|
||||
{{ 'add-edit-file-attribute.form.displayedInFileList' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
|
||||
@ -32,7 +32,9 @@ export class AddEditFileAttributeDialogComponent {
|
||||
csvColumnHeader: [this.fileAttribute?.csvColumnHeader, Validators.required],
|
||||
type: [this.fileAttribute?.type || FileAttributeConfig.TypeEnum.TEXT, Validators.required],
|
||||
readonly: [this.fileAttribute ? !this.fileAttribute.editable : false],
|
||||
primaryAttribute: [this.fileAttribute?.primaryAttribute]
|
||||
primaryAttribute: [this.fileAttribute?.primaryAttribute],
|
||||
filterable: [this.fileAttribute?.filterable],
|
||||
displayedInFileList: [this.fileAttribute?.displayedInFileList]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +62,12 @@
|
||||
<div class="small-label">
|
||||
{{ attribute.csvColumnHeader }}
|
||||
</div>
|
||||
<div class="center">
|
||||
<iqser-round-checkbox *ngIf="attribute.filterable" [active]="true" [size]="18"></iqser-round-checkbox>
|
||||
</div>
|
||||
<div class="center">
|
||||
<iqser-round-checkbox *ngIf="attribute.displayedInFileList" [active]="true" [size]="18"></iqser-round-checkbox>
|
||||
</div>
|
||||
<div class="center">
|
||||
<iqser-round-checkbox *ngIf="attribute.primaryAttribute" [active]="true" [size]="18"></iqser-round-checkbox>
|
||||
</div>
|
||||
|
||||
@ -11,7 +11,7 @@ iqser-table-header::ng-deep .header-item {
|
||||
|
||||
.content-container cdk-virtual-scroll-viewport {
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr 1fr 1fr 11px;
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 11px;
|
||||
|
||||
.table-item {
|
||||
> div:not(.scrollbar-placeholder) {
|
||||
@ -36,7 +36,7 @@ iqser-table-header::ng-deep .header-item {
|
||||
}
|
||||
|
||||
&.has-scrollbar:hover ::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr 1fr 1fr;
|
||||
grid-template-columns: auto 2fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,14 @@ export class FileAttributesListingScreenComponent extends ListingComponent<FileA
|
||||
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',
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<section *ngIf="!!currentDossier">
|
||||
<redaction-page-header
|
||||
[actionConfigs]="actionConfigs"
|
||||
[fileAttributeConfigs]="fileAttributeConfigs"
|
||||
[searchPlaceholder]="'dossier-overview.search' | translate"
|
||||
[showCloseButton]="true"
|
||||
>
|
||||
@ -104,6 +105,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let config of displayedInFileListAttributes">
|
||||
{{ fileStatus.fileAttributes.attributeIdToValue[config.id] }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div [class.error]="fileStatus.isError" class="small-label">
|
||||
{{ fileStatus.added | date: 'd MMM. yyyy, hh:mm a' }}
|
||||
|
||||
@ -17,7 +17,7 @@ iqser-table-column-name::ng-deep {
|
||||
|
||||
cdk-virtual-scroll-viewport {
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 3fr 2fr 1fr 2fr 1fr auto 11px;
|
||||
grid-template-columns: auto 3fr 1fr 2fr 1fr 2fr 1fr auto 11px;
|
||||
|
||||
.table-item {
|
||||
> div {
|
||||
@ -67,7 +67,7 @@ cdk-virtual-scroll-viewport {
|
||||
|
||||
&.has-scrollbar:hover {
|
||||
::ng-deep.cdk-virtual-scroll-content-wrapper {
|
||||
grid-template-columns: auto 3fr 2fr 1fr 2fr 1fr auto;
|
||||
grid-template-columns: auto 3fr 1fr 2fr 1fr 2fr 1fr auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { annotationFilterChecker } from '@shared/components/filters/popup-filter/utils/filter-utils';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||
import { FileAttributeConfig } from '@redaction/red-ui-http';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-overview-screen.component.html',
|
||||
@ -50,7 +51,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
hide: !this.currentUser.isManager
|
||||
}
|
||||
];
|
||||
readonly tableColumnConfigs: readonly TableColumnConfig<FileStatusWrapper>[] = [
|
||||
tableColumnConfigs: readonly TableColumnConfig<FileStatusWrapper>[] = [
|
||||
{
|
||||
label: _('dossier-overview.table-col-names.name'),
|
||||
sortByKey: 'filename'
|
||||
@ -79,6 +80,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
];
|
||||
collapsedDetails = false;
|
||||
dossierAttributes: DossierAttributeWithValue[] = [];
|
||||
fileAttributeConfigs: FileAttributeConfig[];
|
||||
protected readonly _primaryKey = 'filename';
|
||||
|
||||
@ViewChild(DossierDetailsComponent, { static: false })
|
||||
@ -106,9 +108,13 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _fileDropOverlayService: FileDropOverlayService,
|
||||
private readonly _dossierAttributesService: DossierAttributesService
|
||||
) {
|
||||
) // private readonly _renderer: Renderer2,
|
||||
// private readonly _elementRef: ElementRef,
|
||||
{
|
||||
super(_injector);
|
||||
this._loadEntitiesFromState();
|
||||
|
||||
this.fileAttributeConfigs = this._appStateService.activeFileAttributesConfig.fileAttributeConfigs;
|
||||
}
|
||||
|
||||
get checkedRequiredFilters() {
|
||||
@ -141,6 +147,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
|
||||
this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier);
|
||||
this.searchService.setSearchKey('filename');
|
||||
this.addDynamicColumns();
|
||||
} catch (e) {
|
||||
} finally {
|
||||
this._loadingService.stop();
|
||||
@ -235,6 +242,25 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
this.collapsedDetails = !this.collapsedDetails;
|
||||
}
|
||||
|
||||
addDynamicColumns() {
|
||||
const dynamicColumns: TableColumnConfig<FileStatusWrapper>[] = [];
|
||||
for (const config of this.displayedInFileListAttributes) {
|
||||
if (config.displayedInFileList) {
|
||||
dynamicColumns.push({ label: config.label });
|
||||
}
|
||||
}
|
||||
this.tableColumnConfigs = [this.tableColumnConfigs[0], ...dynamicColumns, ...this.tableColumnConfigs.slice(1)];
|
||||
|
||||
// const element = this._elementRef.nativeElement.querySelector('.cdk-virtual-scroll-content-wrapper');
|
||||
// this._renderer.setStyle(element, 'grid-template-columns', 'auto 3fr 1fr 2fr 1fr 2fr 1fr auto 11px');
|
||||
// this._renderer.addClass(element, 'has-scrollbar:hover')
|
||||
// console.log('element: ', element);
|
||||
}
|
||||
|
||||
get displayedInFileListAttributes() {
|
||||
return this.fileAttributeConfigs.filter(config => config.displayedInFileList);
|
||||
}
|
||||
|
||||
recentlyModifiedChecker = (file: FileStatusWrapper) =>
|
||||
moment(file.lastUpdated).add(this._appConfigService.getConfig(AppConfigKey.RECENT_PERIOD_IN_HOURS), 'hours').isAfter(moment());
|
||||
|
||||
@ -256,6 +282,8 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
const allDistinctAddedDates = new Set<string>();
|
||||
const allDistinctNeedsWork = new Set<string>();
|
||||
|
||||
const dynamicFilters = new Map<string, Set<string>>();
|
||||
|
||||
this.entitiesService.all.forEach(file => {
|
||||
allDistinctPeople.add(file.currentReviewer);
|
||||
allDistinctFileStatusWrapper.add(file.status);
|
||||
@ -269,6 +297,31 @@ export class DossierOverviewScreenComponent extends ListingComponent<FileStatusW
|
||||
if (file.hasImages) allDistinctNeedsWork.add('image');
|
||||
if (file.hasNone) allDistinctNeedsWork.add('none');
|
||||
if (file.hasAnnotationComments) allDistinctNeedsWork.add('comment');
|
||||
|
||||
// extract values for dynamic filters
|
||||
this.fileAttributeConfigs.forEach(config => {
|
||||
if (config.filterable) {
|
||||
const filterKey = `${config.id}:${config.label}`;
|
||||
let filters = dynamicFilters.get(filterKey);
|
||||
if (!filters) {
|
||||
dynamicFilters.set(filterKey, new Set<string>());
|
||||
filters = dynamicFilters.get(filterKey);
|
||||
}
|
||||
filters.add(file.fileAttributes?.attributeIdToValue[config.id]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
dynamicFilters.forEach((filterValue: Set<string>, filterKey: string) => {
|
||||
const id = filterKey.split(':')[0];
|
||||
const key = filterKey.split(':')[1];
|
||||
this.filterService.addFilterGroup({
|
||||
slug: key,
|
||||
label: key,
|
||||
icon: 'red:template',
|
||||
filters: [...filterValue].map<NestedFilter>((value: string) => ({ key: value, label: value })),
|
||||
checker: (input: FileStatusWrapper, filter: NestedFilter) => filter.label === input.fileAttributes.attributeIdToValue[id]
|
||||
});
|
||||
});
|
||||
|
||||
const statusFilters = [...allDistinctFileStatusWrapper].map<NestedFilter>(item => ({
|
||||
|
||||
@ -5,6 +5,7 @@ import { FilterService, SearchService } from '@iqser/common-ui';
|
||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||
import { combineLatest, Observable, of } from 'rxjs';
|
||||
import { SearchPosition, SearchPositions } from '@shared/components/page-header/models/search-positions.type';
|
||||
import { FileAttributeConfig } from '@redaction/red-ui-http';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-page-header',
|
||||
@ -18,6 +19,7 @@ export class PageHeaderComponent<T> {
|
||||
@Input() showCloseButton: boolean;
|
||||
@Input() actionConfigs: readonly ActionConfig[];
|
||||
@Input() buttonConfigs: readonly ButtonConfig[];
|
||||
@Input() fileAttributeConfigs: readonly FileAttributeConfig[];
|
||||
@Input() searchPlaceholder: string;
|
||||
@Input() searchWidth: number | 'full';
|
||||
@Input() searchPosition: SearchPosition = SearchPositions.afterFilters;
|
||||
|
||||
@ -82,6 +82,8 @@
|
||||
"form": {
|
||||
"column-header": "CSV Column Header",
|
||||
"column-header-placeholder": "Enter CSV Column Header",
|
||||
"displayedInFileList": "Displayed In File List",
|
||||
"filterable": "Filterable",
|
||||
"name": "Attribute Name",
|
||||
"name-placeholder": "Enter Name",
|
||||
"primary": "Set as Primary",
|
||||
@ -928,6 +930,8 @@
|
||||
"search": "Search by attribute name...",
|
||||
"table-col-names": {
|
||||
"csv-column": "CSV Column",
|
||||
"displayed-in-file-list": "Dis. In File List",
|
||||
"filterable": "Filterable",
|
||||
"name": "Name",
|
||||
"primary": "Primary",
|
||||
"primary-info-tooltip": "The value of the attribute set as primary shows up under the file name in the documents list.",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user