From b050fab77ff00352de6a19edc7d2ae389497657f Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 13 Feb 2026 09:36:12 -0800 Subject: [PATCH] Enhancement: consolidate management lists into document attributes section (#12045) --- src-ui/e2e/dashboard/dashboard.spec.ts | 4 +- .../permissions/global-permissions.spec.ts | 18 +- src-ui/src/app/app-routing.module.ts | 105 +++---- src-ui/src/app/app.component.ts | 4 +- .../app-frame/app-frame.component.html | 92 ++++--- .../app-frame/app-frame.component.scss | 9 + .../app-frame/app-frame.component.spec.ts | 106 +++++++- .../app-frame/app-frame.component.ts | 61 ++++- .../custom-fields.component.html | 12 - .../custom-fields.component.scss | 0 .../custom-fields.component.spec.ts | 11 +- .../custom-fields/custom-fields.component.ts | 26 +- .../document-attributes.component.html | 78 ++++++ .../document-attributes.component.scss | 0 .../document-attributes.component.spec.ts | 189 +++++++++++++ .../document-attributes.component.ts | 256 ++++++++++++++++++ .../correspondent-list.component.spec.ts | 2 +- .../correspondent-list.component.ts | 17 +- .../document-type-list.component.spec.ts | 2 +- .../document-type-list.component.ts | 15 +- .../management-list.component.html | 71 +---- .../management-list.component.scss | 0 .../management-list.component.spec.ts | 14 +- .../management-list.component.ts | 33 +-- .../storage-path-list.component.spec.ts | 2 +- .../storage-path-list.component.ts | 15 +- .../tag-list/tag-list.component.spec.ts | 6 +- .../tag-list/tag-list.component.ts | 15 +- src-ui/src/app/data/ui-settings.ts | 11 + .../src/app/guards/permissions.guard.spec.ts | 48 ++++ src-ui/src/app/guards/permissions.guard.ts | 8 + src-ui/src/main.ts | 2 + 32 files changed, 969 insertions(+), 263 deletions(-) rename src-ui/src/app/components/manage/{ => document-attributes}/custom-fields/custom-fields.component.html (88%) rename src-ui/src/app/components/manage/{ => document-attributes}/custom-fields/custom-fields.component.scss (100%) rename src-ui/src/app/components/manage/{ => document-attributes}/custom-fields/custom-fields.component.spec.ts (92%) rename src-ui/src/app/components/manage/{ => document-attributes}/custom-fields/custom-fields.component.ts (82%) create mode 100644 src-ui/src/app/components/manage/document-attributes/document-attributes.component.html create mode 100644 src-ui/src/app/components/manage/document-attributes/document-attributes.component.scss create mode 100644 src-ui/src/app/components/manage/document-attributes/document-attributes.component.spec.ts create mode 100644 src-ui/src/app/components/manage/document-attributes/document-attributes.component.ts rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/correspondent-list/correspondent-list.component.spec.ts (97%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/correspondent-list/correspondent-list.component.ts (77%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/document-type-list/document-type-list.component.spec.ts (96%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/document-type-list/document-type-list.component.ts (70%) rename src-ui/src/app/components/manage/{ => document-attributes}/management-list/management-list.component.html (64%) rename src-ui/src/app/components/manage/{ => document-attributes}/management-list/management-list.component.scss (100%) rename src-ui/src/app/components/manage/{ => document-attributes}/management-list/management-list.component.spec.ts (97%) rename src-ui/src/app/components/manage/{ => document-attributes}/management-list/management-list.component.ts (91%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/storage-path-list/storage-path-list.component.spec.ts (96%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/storage-path-list/storage-path-list.component.ts (73%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/tag-list/tag-list.component.spec.ts (96%) rename src-ui/src/app/components/manage/{ => document-attributes/management-list}/tag-list/tag-list.component.ts (79%) diff --git a/src-ui/e2e/dashboard/dashboard.spec.ts b/src-ui/e2e/dashboard/dashboard.spec.ts index 2ee8c1f35..801f431f3 100644 --- a/src-ui/e2e/dashboard/dashboard.spec.ts +++ b/src-ui/e2e/dashboard/dashboard.spec.ts @@ -52,11 +52,11 @@ test('dashboard saved view document links', async ({ page }) => { test('test slim sidebar', async ({ page }) => { await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' }) await page.goto('/dashboard') - await page.locator('#sidebarMenu').getByRole('button').click() + await page.locator('.sidebar-slim-toggler').click() await expect( page.getByRole('link', { name: 'Dashboard' }).getByText('Dashboard') ).toBeHidden() - await page.locator('#sidebarMenu').getByRole('button').click() + await page.locator('.sidebar-slim-toggler').click() await expect( page.getByRole('link', { name: 'Dashboard' }).getByText('Dashboard') ).toBeVisible() diff --git a/src-ui/e2e/permissions/global-permissions.spec.ts b/src-ui/e2e/permissions/global-permissions.spec.ts index e5bc98edf..7021b6d9b 100644 --- a/src-ui/e2e/permissions/global-permissions.spec.ts +++ b/src-ui/e2e/permissions/global-permissions.spec.ts @@ -33,9 +33,9 @@ test('should not allow user to view correspondents', async ({ page }) => { await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/dashboard') await expect( - page.getByRole('link', { name: 'Correspondents' }) + page.getByRole('link', { name: 'Attributes' }) ).not.toBeAttached() - await page.goto('/correspondents') + await page.goto('/attributes/correspondents') await expect(page.locator('body')).toHaveText( /You don't have permissions to do that/i ) @@ -44,8 +44,10 @@ test('should not allow user to view correspondents', async ({ page }) => { test('should not allow user to view tags', async ({ page }) => { await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/dashboard') - await expect(page.getByRole('link', { name: 'Tags' })).not.toBeAttached() - await page.goto('/tags') + await expect( + page.getByRole('link', { name: 'Attributes' }) + ).not.toBeAttached() + await page.goto('/attributes/tags') await expect(page.locator('body')).toHaveText( /You don't have permissions to do that/i ) @@ -55,9 +57,9 @@ test('should not allow user to view document types', async ({ page }) => { await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/dashboard') await expect( - page.getByRole('link', { name: 'Document Types' }) + page.getByRole('link', { name: 'Attributes' }) ).not.toBeAttached() - await page.goto('/documenttypes') + await page.goto('/attributes/documenttypes') await expect(page.locator('body')).toHaveText( /You don't have permissions to do that/i ) @@ -67,9 +69,9 @@ test('should not allow user to view storage paths', async ({ page }) => { await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/dashboard') await expect( - page.getByRole('link', { name: 'Storage Paths' }) + page.getByRole('link', { name: 'Attributes' }) ).not.toBeAttached() - await page.goto('/storagepaths') + await page.goto('/attributes/storagepaths') await expect(page.locator('body')).toHaveText( /You don't have permissions to do that/i ) diff --git a/src-ui/src/app/app-routing.module.ts b/src-ui/src/app/app-routing.module.ts index f65514f74..66864a0d5 100644 --- a/src-ui/src/app/app-routing.module.ts +++ b/src-ui/src/app/app-routing.module.ts @@ -11,13 +11,9 @@ import { DashboardComponent } from './components/dashboard/dashboard.component' import { DocumentAsnComponent } from './components/document-asn/document-asn.component' import { DocumentDetailComponent } from './components/document-detail/document-detail.component' import { DocumentListComponent } from './components/document-list/document-list.component' -import { CorrespondentListComponent } from './components/manage/correspondent-list/correspondent-list.component' -import { CustomFieldsComponent } from './components/manage/custom-fields/custom-fields.component' -import { DocumentTypeListComponent } from './components/manage/document-type-list/document-type-list.component' +import { DocumentAttributesComponent } from './components/manage/document-attributes/document-attributes.component' import { MailComponent } from './components/manage/mail/mail.component' import { SavedViewsComponent } from './components/manage/saved-views/saved-views.component' -import { StoragePathListComponent } from './components/manage/storage-path-list/storage-path-list.component' -import { TagListComponent } from './components/manage/tag-list/tag-list.component' import { WorkflowsComponent } from './components/manage/workflows/workflows.component' import { NotFoundComponent } from './components/not-found/not-found.component' import { DirtyDocGuard } from './guards/dirty-doc.guard' @@ -106,52 +102,76 @@ export const routes: Routes = [ }, }, { - path: 'tags', - component: TagListComponent, + path: 'attributes', + component: DocumentAttributesComponent, canActivate: [PermissionsGuard], data: { - requiredPermission: { - action: PermissionAction.View, - type: PermissionType.Tag, - }, - componentName: 'TagListComponent', + requiredPermissionAny: [ + { action: PermissionAction.View, type: PermissionType.Tag }, + { + action: PermissionAction.View, + type: PermissionType.Correspondent, + }, + { + action: PermissionAction.View, + type: PermissionType.DocumentType, + }, + { action: PermissionAction.View, type: PermissionType.StoragePath }, + { action: PermissionAction.View, type: PermissionType.CustomField }, + ], + componentName: 'DocumentAttributesComponent', }, }, { - path: 'documenttypes', - component: DocumentTypeListComponent, + path: 'attributes/:section', + component: DocumentAttributesComponent, canActivate: [PermissionsGuard], data: { - requiredPermission: { - action: PermissionAction.View, - type: PermissionType.DocumentType, - }, - componentName: 'DocumentTypeListComponent', + requiredPermissionAny: [ + { action: PermissionAction.View, type: PermissionType.Tag }, + { + action: PermissionAction.View, + type: PermissionType.Correspondent, + }, + { + action: PermissionAction.View, + type: PermissionType.DocumentType, + }, + { action: PermissionAction.View, type: PermissionType.StoragePath }, + { action: PermissionAction.View, type: PermissionType.CustomField }, + ], + componentName: 'DocumentAttributesComponent', }, }, + { + path: 'documentproperties', + redirectTo: '/attributes', + pathMatch: 'full', + }, + { + path: 'documentproperties/:section', + redirectTo: '/attributes/:section', + pathMatch: 'full', + }, + { + path: 'tags', + redirectTo: '/attributes/tags', + pathMatch: 'full', + }, { path: 'correspondents', - component: CorrespondentListComponent, - canActivate: [PermissionsGuard], - data: { - requiredPermission: { - action: PermissionAction.View, - type: PermissionType.Correspondent, - }, - componentName: 'CorrespondentListComponent', - }, + redirectTo: '/attributes/correspondents', + pathMatch: 'full', + }, + { + path: 'documenttypes', + redirectTo: '/attributes/documenttypes', + pathMatch: 'full', }, { path: 'storagepaths', - component: StoragePathListComponent, - canActivate: [PermissionsGuard], - data: { - requiredPermission: { - action: PermissionAction.View, - type: PermissionType.StoragePath, - }, - componentName: 'StoragePathListComponent', - }, + redirectTo: '/attributes/storagepaths', + pathMatch: 'full', }, { path: 'logs', @@ -239,15 +259,8 @@ export const routes: Routes = [ }, { path: 'customfields', - component: CustomFieldsComponent, - canActivate: [PermissionsGuard], - data: { - requiredPermission: { - action: PermissionAction.View, - type: PermissionType.CustomField, - }, - componentName: 'CustomFieldsComponent', - }, + redirectTo: '/attributes/customfields', + pathMatch: 'full', }, { path: 'workflows', diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index 818f8eab0..543d2ecaa 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -195,8 +195,8 @@ export class AppComponent implements OnInit, OnDestroy { }, { anchorId: 'tour.tags', - content: $localize`Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.`, - route: '/tags', + content: $localize`Attributes like tags, correspondents, document types, storage paths and custom fields can all be managed here. They can also be created from the document edit view.`, + route: '/attributes/tags', backdropConfig: { offset: 0, }, diff --git a/src-ui/src/app/components/app-frame/app-frame.component.html b/src-ui/src/app/components/app-frame/app-frame.component.html index 62a2e16cc..13bf9069c 100644 --- a/src-ui/src/app/components/app-frame/app-frame.component.html +++ b/src-ui/src/app/components/app-frame/app-frame.component.html @@ -175,44 +175,60 @@ Manage