diff --git a/src-ui/src/app/components/admin/settings/settings.component.html b/src-ui/src/app/components/admin/settings/settings.component.html index 305bb8a96..b520e8218 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.html +++ b/src-ui/src/app/components/admin/settings/settings.component.html @@ -112,6 +112,22 @@ +

Sidebar items to show:

+ @for (option of sidebarItemOptions; track option.id) { +
+ + +
+ } + diff --git a/src-ui/src/app/components/admin/settings/settings.component.spec.ts b/src-ui/src/app/components/admin/settings/settings.component.spec.ts index 7b65281d0..08ff5c445 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.spec.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.spec.ts @@ -24,7 +24,7 @@ import { SystemStatus, SystemStatusItemStatus, } from 'src/app/data/system-status' -import { SETTINGS_KEYS } from 'src/app/data/ui-settings' +import { HideableSidebarItemID, SETTINGS_KEYS } from 'src/app/data/ui-settings' import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { PermissionsGuard } from 'src/app/guards/permissions.guard' @@ -209,6 +209,23 @@ describe('SettingsComponent', () => { fixture.detectChanges() } + it('supports configuring sidebar items and canceling changes', () => { + completeSetup() + + component.toggleSidebarItem(HideableSidebarItemID.Workflows, false) + fixture.detectChanges() + + expect(component.settingsForm.value.sidebarHiddenItems).toContain( + HideableSidebarItemID.Workflows + ) + + component.reset() + + expect(component.settingsForm.value.sidebarHiddenItems).not.toContain( + HideableSidebarItemID.Workflows + ) + }) + it('should support tabbed settings & change URL, prevent navigation if dirty confirmation rejected', async () => { completeSetup() const navigateSpy = jest.spyOn(router, 'navigate') @@ -249,6 +266,7 @@ describe('SettingsComponent', () => { it('should support save local settings updating appearance settings and calling API, show error', () => { completeSetup() + component.toggleSidebarItem(HideableSidebarItemID.Workflows, false) const toastErrorSpy = jest.spyOn(toastService, 'showError') const toastSpy = jest.spyOn(toastService, 'show') const storeSpy = jest.spyOn(settingsService, 'storeSettings') @@ -267,7 +285,10 @@ describe('SettingsComponent', () => { expect(toastErrorSpy).toHaveBeenCalled() expect(storeSpy).toHaveBeenCalled() expect(appearanceSettingsSpy).not.toHaveBeenCalled() - expect(setSpy).toHaveBeenCalledTimes(33) + expect(setSpy).toHaveBeenCalledTimes(34) + expect(setSpy).toHaveBeenCalledWith(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [ + HideableSidebarItemID.Workflows, + ]) // succeed storeSpy.mockReturnValueOnce(of(true)) diff --git a/src-ui/src/app/components/admin/settings/settings.component.ts b/src-ui/src/app/components/admin/settings/settings.component.ts index 218f6683c..583b10c38 100644 --- a/src-ui/src/app/components/admin/settings/settings.component.ts +++ b/src-ui/src/app/components/admin/settings/settings.component.ts @@ -39,7 +39,12 @@ import { SystemStatus, SystemStatusItemStatus, } from 'src/app/data/system-status' -import { GlobalSearchType, SETTINGS_KEYS } from 'src/app/data/ui-settings' +import { + GlobalSearchType, + HIDEABLE_SIDEBAR_ITEM_IDS, + HideableSidebarItemID, + SETTINGS_KEYS, +} from 'src/app/data/ui-settings' import { User } from 'src/app/data/user' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe' @@ -102,6 +107,14 @@ const documentDetailFieldOptions = [ { id: DocumentDetailFieldID.Tags, label: $localize`Tags` }, ] +const sidebarItemLabels: Record = { + [HideableSidebarItemID.Dashboard]: $localize`Dashboard`, + [HideableSidebarItemID.SavedViews]: $localize`Saved Views`, + [HideableSidebarItemID.Workflows]: $localize`Workflows`, + [HideableSidebarItemID.Mail]: $localize`Mail`, + [HideableSidebarItemID.Documentation]: $localize`Documentation`, +} + @Component({ selector: 'pngx-settings', templateUrl: './settings.component.html', @@ -149,6 +162,7 @@ export class SettingsComponent bulkEditApplyOnClose: new FormControl(null), documentListItemPerPage: new FormControl(null), slimSidebarEnabled: new FormControl(null), + sidebarHiddenItems: new FormControl([]), darkModeUseSystem: new FormControl(null), darkModeEnabled: new FormControl(null), darkModeInvertThumbs: new FormControl(null), @@ -203,6 +217,10 @@ export class SettingsComponent public readonly PdfEditorEditMode = PdfEditorEditMode public readonly documentDetailFieldOptions = documentDetailFieldOptions + public readonly sidebarItemOptions = HIDEABLE_SIDEBAR_ITEM_IDS.map((id) => ({ + id, + label: sidebarItemLabels[id], + })) get systemStatusHasErrors(): boolean { const status = this.systemStatus() @@ -310,6 +328,7 @@ export class SettingsComponent SETTINGS_KEYS.DOCUMENT_LIST_SIZE ), slimSidebarEnabled: this.settings.get(SETTINGS_KEYS.SLIM_SIDEBAR), + sidebarHiddenItems: this.settings.get(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS), darkModeUseSystem: this.settings.get(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM), darkModeEnabled: this.settings.get(SETTINGS_KEYS.DARK_MODE_ENABLED), darkModeInvertThumbs: this.settings.get( @@ -448,6 +467,22 @@ export class SettingsComponent this.storeSub && this.storeSub.unsubscribe() } + isSidebarItemShown(item: HideableSidebarItemID): boolean { + return !(this.settingsForm.value.sidebarHiddenItems || []).includes(item) + } + + toggleSidebarItem(item: HideableSidebarItemID, checked: boolean): void { + const hiddenItems = new Set( + this.settingsForm.value.sidebarHiddenItems || [] + ) + if (checked) { + hiddenItems.delete(item) + } else { + hiddenItems.add(item) + } + this.settingsForm.controls.sidebarHiddenItems.setValue([...hiddenItems]) + } + public saveSettings() { this.savePending = true const reloadRequired = @@ -473,6 +508,10 @@ export class SettingsComponent SETTINGS_KEYS.SLIM_SIDEBAR, this.settingsForm.value.slimSidebarEnabled ) + this.settings.set( + SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, + this.settingsForm.value.sidebarHiddenItems + ) this.settings.set( SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem diff --git a/src-ui/src/app/services/settings.service.spec.ts b/src-ui/src/app/services/settings.service.spec.ts index be8e393c9..4167858e2 100644 --- a/src-ui/src/app/services/settings.service.spec.ts +++ b/src-ui/src/app/services/settings.service.spec.ts @@ -234,7 +234,7 @@ describe('SettingsService', () => { expect(notesEnabled()).toBeFalsy() }) - it('updates sidebar item visibility', () => { + it('reports whether a sidebar item is hidden', () => { httpTestingController .expectOne(`${environment.apiBaseUrl}ui_settings/`) .flush(ui_settings) @@ -243,19 +243,15 @@ describe('SettingsService', () => { settingsService.sidebarItemIsHidden(HideableSidebarItemID.Workflows) ).toBe(false) - settingsService.updateSidebarItemVisibility( + settingsService.set(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [ HideableSidebarItemID.Workflows, - false - ) + ]) expect( settingsService.sidebarItemIsHidden(HideableSidebarItemID.Workflows) ).toBe(true) - settingsService.updateSidebarItemVisibility( - HideableSidebarItemID.Workflows, - true - ) + settingsService.set(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, []) expect( settingsService.sidebarItemIsHidden(HideableSidebarItemID.Workflows) diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index f012b56de..9b1b47e09 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -314,7 +314,6 @@ export class SettingsService { readonly globalDropzoneEnabled = signal(true) readonly globalDropzoneActive = signal(false) readonly organizingSidebarSavedViews = signal(false) - readonly organizingSidebarItems = signal(false) readonly hiddenSidebarItems = this.getSignal( SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS ) @@ -758,20 +757,6 @@ export class SettingsService { return this.hiddenSidebarItems().includes(item) } - updateSidebarItemVisibility( - item: HideableSidebarItemID, - visible: boolean - ): Observable { - const hiddenItems = new Set(this.hiddenSidebarItems()) - if (visible) { - hiddenItems.delete(item) - } else { - hiddenItems.add(item) - } - this.set(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, [...hiddenItems]) - return this.storeSettings() - } - updateSavedViewsVisibility( dashboardVisibleViewIds: number[], sidebarVisibleViewIds: number[]