diff --git a/apps/red-ui/src/app/models/file/file-status.wrapper.ts b/apps/red-ui/src/app/models/file/file-status.wrapper.ts
index 2d589be23..7fa0c93e6 100644
--- a/apps/red-ui/src/app/models/file/file-status.wrapper.ts
+++ b/apps/red-ui/src/app/models/file/file-status.wrapper.ts
@@ -57,6 +57,9 @@ export class FileStatusWrapper implements FileStatus {
this.primaryAttribute = '-';
}
}
+ if (!this.fileAttributes || !this.fileAttributes.attributeIdToValue) {
+ this.fileAttributes = { attributeIdToValue: {} };
+ }
}
readonly excludedPagesCount = this.excludedPages?.length ?? 0;
@@ -67,7 +70,7 @@ export class FileStatusWrapper implements FileStatus {
readonly hintsOnly = this.hasHints && !this.hasRedactions;
readonly hasNone = !this.hasRedactions && !this.hasHints && !this.hasSuggestions;
- readonly isUnassigned = !this.currentReviewer
+ readonly isUnassigned = !this.currentReviewer;
readonly isError = this.status === FileStatus.StatusEnum.ERROR;
readonly isProcessing = processingStatuses.includes(this.status);
readonly isApproved = this.status === FileStatus.StatusEnum.APPROVED;
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.html
index 58077d3e8..38076491c 100644
--- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.html
+++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.html
@@ -51,6 +51,18 @@
{{ 'add-edit-file-attribute.form.primary' | translate }}
+
+
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts
index 692d3961e..f6b36782f 100644
--- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component.ts
@@ -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]
});
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
index c8d698324..7f708f4a9 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
@@ -62,6 +62,12 @@
{{ attribute.csvColumnHeader }}
+
+
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
index bcf8a931d..404839f0e 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
@@ -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;
}
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
index 358e4737b..7fc0cb789 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
@@ -37,6 +37,14 @@ export class FileAttributesListingScreenComponent extends ListingComponent
@@ -104,6 +105,10 @@
+
+ {{ fileStatus.fileAttributes.attributeIdToValue[config.id] }}
+
+
{{ fileStatus.added | date: 'd MMM. yyyy, hh:mm a' }}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss
index b28ed76bb..a9f7fa903 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss
@@ -1,6 +1,10 @@
@import '../../../../../assets/styles/variables';
@import '../../../../../assets/styles/red-mixins';
+:root {
+ --dynamic-columns: '0';
+}
+
.file-upload-input {
display: none;
}
@@ -17,7 +21,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 repeat(var(--dynamic-columns), 1fr) 2fr 1fr 2fr 1fr auto 11px;
.table-item {
> div {
@@ -67,7 +71,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 repeat(var(--dynamic-columns), 1fr) 2fr 1fr 2fr 1fr auto;
}
}
}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts
index f5b52aa64..18d49231c 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts
@@ -1,4 +1,15 @@
-import { ChangeDetectorRef, Component, ElementRef, HostListener, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import {
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ HostListener,
+ Injector,
+ OnDestroy,
+ OnInit,
+ Renderer2,
+ TemplateRef,
+ ViewChild
+} from '@angular/core';
import { Toaster } from '@services/toaster.service';
import { AppStateService } from '@state/app-state.service';
import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
@@ -30,6 +41,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 +62,7 @@ export class DossierOverviewScreenComponent extends ListingComponent[] = [
+ private readonly _defaultTableConfigs: readonly TableColumnConfig[] = [
{
label: _('dossier-overview.table-col-names.name'),
sortByKey: 'filename'
@@ -77,9 +89,13 @@ export class DossierOverviewScreenComponent extends ListingComponent[] = [];
collapsedDetails = false;
dossierAttributes: DossierAttributeWithValue[] = [];
+ fileAttributeConfigs: FileAttributeConfig[];
protected readonly _primaryKey = 'filename';
+ dynamicColumnsCount = 0;
@ViewChild(DossierDetailsComponent, { static: false })
private readonly _dossierDetailsComponent: DossierDetailsComponent;
@@ -105,10 +121,14 @@ export class DossierOverviewScreenComponent extends ListingComponent config.displayedInFileList);
+ }
+
recentlyModifiedChecker = (file: FileStatusWrapper) =>
moment(file.lastUpdated).add(this._appConfigService.getConfig(AppConfigKey.RECENT_PERIOD_IN_HOURS), 'hours').isAfter(moment());
+ private _configureTableColumns() {
+ const dynamicColumns: TableColumnConfig[] = [];
+ for (const config of this.displayedInFileListAttributes) {
+ if (config.displayedInFileList) {
+ dynamicColumns.push({ label: config.label, notTranslatable: true });
+ }
+ }
+ this.tableColumnConfigs = [this._defaultTableConfigs[0], ...dynamicColumns, ...this._defaultTableConfigs.slice(1)];
+ this.dynamicColumnsCount = dynamicColumns.length;
+ (this._elementRef.nativeElement as HTMLElement).style.setProperty('--dynamic-columns', `${this.dynamicColumnsCount}`);
+ }
+
private _loadEntitiesFromState() {
this.currentDossier = this._appStateService.activeDossier;
if (this.currentDossier) this.entitiesService.setEntities(this.currentDossier.files);
@@ -256,6 +293,8 @@ export class DossierOverviewScreenComponent extends ListingComponent();
const allDistinctNeedsWork = new Set();
+ const dynamicFilters = new Map>();
+
this.entitiesService.all.forEach(file => {
allDistinctPeople.add(file.currentReviewer);
allDistinctFileStatusWrapper.add(file.status);
@@ -269,6 +308,24 @@ export class DossierOverviewScreenComponent extends ListingComponent {
+ if (config.filterable) {
+ const filterKey = `${config.id}:${config.label}`;
+ let filters = dynamicFilters.get(filterKey);
+ if (!filters) {
+ dynamicFilters.set(filterKey, new Set());
+ filters = dynamicFilters.get(filterKey);
+ }
+ let filterValue = file.fileAttributes?.attributeIdToValue[config.id];
+ if (!filterValue) {
+ filterValue = this._translateService.instant('filters.empty');
+ file.fileAttributes.attributeIdToValue[config.id] = '-';
+ }
+ filters.add(filterValue);
+ }
+ });
});
const statusFilters = [...allDistinctFileStatusWrapper].map(item => ({
@@ -322,6 +379,18 @@ export class DossierOverviewScreenComponent extends ListingComponent, 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((value: string) => ({ key: value, label: value })),
+ checker: (input: FileStatusWrapper, filter: NestedFilter) => filter.label === input.fileAttributes.attributeIdToValue[id]
+ });
+ });
+
this.filterService.addFilterGroup({
slug: 'quickFilters',
filters: this._createQuickFilters(),
diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts
index c6fb9a83d..866c188df 100644
--- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts
+++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts
@@ -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 {
@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;
diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json
index 4b001a0b1..7131c849a 100644
--- a/apps/red-ui/src/assets/config/config.json
+++ b/apps/red-ui/src/assets/config/config.json
@@ -1,6 +1,6 @@
{
- "OAUTH_URL": "https://red-staging.iqser.cloud/auth/realms/redaction",
- "API_URL": "https://red-staging.iqser.cloud/redaction-gateway-v1",
+ "OAUTH_URL": "https://dom1.iqser.cloud/auth/realms/redaction",
+ "API_URL": "https://dom1.iqser.cloud/redaction-gateway-v1",
"OAUTH_CLIENT_ID": "redaction",
"BACKEND_APP_VERSION": "4.4.40",
"FRONTEND_APP_VERSION": "1.1",
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index 137125493..6be48809b 100644
--- a/apps/red-ui/src/assets/i18n/en.json
+++ b/apps/red-ui/src/assets/i18n/en.json
@@ -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.",
@@ -1040,7 +1044,8 @@
"filter-by": "Filter:",
"needs-work": "Workload",
"people": "Dossier Member(s)",
- "status": "Status"
+ "status": "Status",
+ "empty": "Empty"
},
"general-config-screen": {
"actions": {