-
+
{{ dict.rank }}
-
+
diff --git a/apps/red-ui/src/app/screens/admin/dictionary-listing-screen/dictionary-listing-screen.component.scss b/apps/red-ui/src/app/screens/admin/dictionary-listing-screen/dictionary-listing-screen.component.scss
index 7ea9ffd49..defb8b5e7 100644
--- a/apps/red-ui/src/app/screens/admin/dictionary-listing-screen/dictionary-listing-screen.component.scss
+++ b/apps/red-ui/src/app/screens/admin/dictionary-listing-screen/dictionary-listing-screen.component.scss
@@ -4,7 +4,7 @@
.header-item {
padding: 0 16px 0 10px;
- .dictionary-actions-container {
+ .attributes-actions-container {
display: flex;
flex: 1;
justify-content: flex-end;
@@ -36,8 +36,7 @@ redaction-table-col-name::ng-deep {
align-items: center;
justify-content: flex-start;
- &.analyzed,
- &.rank {
+ &.center {
justify-content: center;
}
diff --git a/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.html b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.html
new file mode 100644
index 000000000..b56c31b1b
--- /dev/null
+++ b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.html
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ attribute.name }}
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.scss b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.scss
new file mode 100644
index 000000000..92f4a963f
--- /dev/null
+++ b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.scss
@@ -0,0 +1,54 @@
+.page-header .actions {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.header-item {
+ padding: 0 24px 0 10px;
+}
+
+redaction-table-col-name::ng-deep {
+ > div {
+ padding-left: 10px !important;
+ }
+}
+
+.left-container {
+ width: 100vw;
+
+ .header-item {
+ .attributes-actions-container {
+ display: flex;
+ flex: 1;
+ justify-content: flex-end;
+
+ > *:not(:last-child) {
+ margin-right: 16px;
+ }
+ }
+ }
+
+ cdk-virtual-scroll-viewport {
+ ::ng-deep.cdk-virtual-scroll-content-wrapper {
+ grid-template-columns: auto 1fr 1fr 1fr 1fr 11px;
+
+ .table-item {
+ > div:not(.scrollbar-placeholder) {
+ padding-left: 10px;
+ }
+
+ > div {
+ &.center {
+ align-items: center;
+ }
+ }
+ }
+ }
+
+ &.has-scrollbar:hover {
+ ::ng-deep.cdk-virtual-scroll-content-wrapper {
+ grid-template-columns: auto 1fr 1fr 1fr 1fr;
+ }
+ }
+ }
+}
diff --git a/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.ts b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.ts
new file mode 100644
index 000000000..38e6d3856
--- /dev/null
+++ b/apps/red-ui/src/app/screens/admin/file-attributes-listing-screen/file-attributes-listing-screen.component.ts
@@ -0,0 +1,112 @@
+import { Component, OnInit } from '@angular/core';
+import { PermissionsService } from '../../../common/service/permissions.service';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { FileAttribute, FileAttributesControllerService } from '@redaction/red-ui-http';
+import { AppStateService } from '../../../state/app-state.service';
+import { ActivatedRoute } from '@angular/router';
+import { debounce } from '../../../utils/debounce';
+import { SortingOption, SortingService } from '../../../utils/sorting.service';
+
+@Component({
+ selector: 'redaction-file-attributes-listing-screen',
+ templateUrl: './file-attributes-listing-screen.component.html',
+ styleUrls: ['./file-attributes-listing-screen.component.scss']
+})
+export class FileAttributesListingScreenComponent implements OnInit {
+ public searchForm: FormGroup;
+ public attributes: FileAttribute[] = [];
+ public displayedAttributes: FileAttribute[] = [];
+ public selectedFileAttributeIds: string[] = [];
+
+ constructor(
+ public readonly permissionsService: PermissionsService,
+ public readonly _sortingService: SortingService,
+ private readonly _formBuilder: FormBuilder,
+ private readonly _fileAttributesService: FileAttributesControllerService,
+ private readonly _appStateService: AppStateService,
+ private readonly _activatedRoute: ActivatedRoute
+ ) {
+ this._appStateService.activateRuleSet(_activatedRoute.snapshot.params.ruleSetId);
+
+ this.searchForm = this._formBuilder.group({
+ query: ['']
+ });
+
+ this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value));
+ }
+
+ async ngOnInit() {
+ try {
+ const response = await this._fileAttributesService.getFileAttributesConfiguration(this._appStateService.activeRuleSetId).toPromise();
+ this.attributes = response?.fileAttributes || [];
+ } catch (e) {
+ // TODO: Remove
+ this.attributes = [
+ {
+ name: 'Atribut',
+ editable: true,
+ id: '1',
+ visible: true
+ },
+ {
+ name: 'Alt atribut',
+ editable: false,
+ id: '2',
+ visible: true
+ }
+ ];
+ }
+ this.displayedAttributes = [...this.attributes];
+ }
+
+ public get noData(): boolean {
+ return this.displayedAttributes.length === 0;
+ }
+
+ public get sortingOption(): SortingOption {
+ return this._sortingService.getSortingOption('file-attributes-listing');
+ }
+
+ public toggleSort($event) {
+ this._sortingService.toggleSort('file-attributes-listing', $event);
+ }
+
+ @debounce(200)
+ private _executeSearch(value: { query: string }) {
+ this.displayedAttributes = this.attributes.filter((attribute) => attribute.name.toLowerCase().includes(value.query.toLowerCase()));
+ }
+
+ public openAddEditAttributeDialog($event: MouseEvent, attribute?: FileAttribute) {
+ $event.stopPropagation();
+ }
+
+ public toggleAttributeSelected($event: MouseEvent, attribute: FileAttribute) {
+ $event.stopPropagation();
+ const idx = this.selectedFileAttributeIds.indexOf(attribute.id);
+ if (idx === -1) {
+ this.selectedFileAttributeIds.push(attribute.id);
+ } else {
+ this.selectedFileAttributeIds.splice(idx, 1);
+ }
+ }
+
+ public toggleSelectAll() {
+ if (this.areSomeAttributesSelected) {
+ this.selectedFileAttributeIds = [];
+ } else {
+ this.selectedFileAttributeIds = this.displayedAttributes.map((a) => a.id);
+ }
+ }
+
+ public get areAllAttributesSelected() {
+ return this.displayedAttributes.length !== 0 && this.selectedFileAttributeIds.length === this.displayedAttributes.length;
+ }
+
+ public get areSomeAttributesSelected() {
+ return this.selectedFileAttributeIds.length > 0;
+ }
+
+ public isAttributeSelected(attribute: FileAttribute) {
+ return this.selectedFileAttributeIds.indexOf(attribute.id) !== -1;
+ }
+}
diff --git a/apps/red-ui/src/app/screens/admin/watermark-screen/watermark-screen.component.html b/apps/red-ui/src/app/screens/admin/watermark-screen/watermark-screen.component.html
index ea6c8c85b..d4c0ca1ff 100644
--- a/apps/red-ui/src/app/screens/admin/watermark-screen/watermark-screen.component.html
+++ b/apps/red-ui/src/app/screens/admin/watermark-screen/watermark-screen.component.html
@@ -5,14 +5,7 @@
-
+
diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-actions/project-listing-actions.component.html b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-actions/project-listing-actions.component.html
index 55303082c..8d93d75d7 100644
--- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-actions/project-listing-actions.component.html
+++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-actions/project-listing-actions.component.html
@@ -36,5 +36,5 @@
>
-
+
diff --git a/apps/red-ui/src/app/utils/sorting.service.ts b/apps/red-ui/src/app/utils/sorting.service.ts
index 45ffa97a8..b73629bdb 100644
--- a/apps/red-ui/src/app/utils/sorting.service.ts
+++ b/apps/red-ui/src/app/utils/sorting.service.ts
@@ -5,7 +5,7 @@ export class SortingOption {
column: string;
}
-type Screen = 'project-listing' | 'project-overview' | 'dictionary-listing' | 'rule-sets-listing' | 'default-colors';
+type Screen = 'project-listing' | 'project-overview' | 'dictionary-listing' | 'rule-sets-listing' | 'default-colors' | 'file-attributes-listing';
@Injectable({
providedIn: 'root'
@@ -16,7 +16,8 @@ export class SortingService {
'project-overview': { column: 'filename', order: 'asc' },
'dictionary-listing': { column: 'label', order: 'asc' },
'rule-sets-listing': { column: 'name', order: 'asc' },
- 'default-colors': { column: 'key', order: 'asc' }
+ 'default-colors': { column: 'key', order: 'asc' },
+ 'file-attributes-listing': { column: 'name', order: 'asc' }
};
constructor() {}
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index 2f2404fe9..16d75e479 100644
--- a/apps/red-ui/src/assets/i18n/en.json
+++ b/apps/red-ui/src/assets/i18n/en.json
@@ -694,6 +694,24 @@
"modified-on": "Modified on"
}
},
+ "file-attributes-listing": {
+ "search": "Search by attribute name...",
+ "add-new": "New Attribute",
+ "table-header": {
+ "title": "{{length}} file attributes"
+ },
+ "table-col-names": {
+ "name": "Name",
+ "created-by": "Created by",
+ "permissions": "Permissions"
+ },
+ "no-data": "No file attributes.",
+ "read-only": "Read-only",
+ "action": {
+ "edit": "Edit attribute",
+ "delete": "Delete attribute"
+ }
+ },
"user-listing": {
"table-header": {
"title": "{{length}} users"
@@ -748,6 +766,7 @@
},
"rule-editor": "Rule Editor",
"watermark": "Watermark",
+ "file-attributes": "File Attributes",
"pending-changes-guard": "WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.",
"reset-filters": "Reset Filters",
"overwrite-files-dialog": {
diff --git a/apps/red-ui/src/assets/icons/general/read-only.svg b/apps/red-ui/src/assets/icons/general/read-only.svg
new file mode 100644
index 000000000..ff827078c
--- /dev/null
+++ b/apps/red-ui/src/assets/icons/general/read-only.svg
@@ -0,0 +1,19 @@
+
+
diff --git a/apps/red-ui/src/assets/styles/red-tables.scss b/apps/red-ui/src/assets/styles/red-tables.scss
index c5f77f376..34da2ed36 100644
--- a/apps/red-ui/src/assets/styles/red-tables.scss
+++ b/apps/red-ui/src/assets/styles/red-tables.scss
@@ -80,6 +80,10 @@ cdk-virtual-scroll-viewport {
width: 14px;
}
+ redaction-circle-button:not(:last-child) {
+ margin-right: 2px;
+ }
+
&.active {
display: flex;
// compensate for scroll