From 96eea42a8e9a56b02a3823d382c88b24a2615eab Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 24 Sep 2023 01:55:24 -0700 Subject: [PATCH] Support drag + drop reorder of dashboard saved views --- src-ui/package-lock.json | 13 ++ src-ui/package.json | 1 + src-ui/src/app/app.component.ts | 9 +- src-ui/src/app/app.module.ts | 2 + .../dashboard/dashboard.component.html | 21 +++- .../dashboard/dashboard.component.spec.ts | 116 +++++++++++++++--- .../dashboard/dashboard.component.ts | 63 +++++++++- .../saved-view-widget.component.html | 11 +- .../saved-view-widget.component.spec.ts | 2 + .../saved-view-widget.component.ts | 14 +++ .../statistics-widget.component.spec.ts | 2 + .../upload-file-widget.component.spec.ts | 2 + .../widget-frame/widget-frame.component.html | 18 ++- .../widget-frame/widget-frame.component.scss | 3 + .../widget-frame.component.spec.ts | 3 +- .../widget-frame/widget-frame.component.ts | 17 ++- src-ui/src/app/data/paperless-uisettings.ts | 7 ++ .../src/app/services/settings.service.spec.ts | 19 +++ src-ui/src/app/services/settings.service.ts | 12 ++ 19 files changed, 301 insertions(+), 34 deletions(-) diff --git a/src-ui/package-lock.json b/src-ui/package-lock.json index 16d74407e..e64cadc44 100644 --- a/src-ui/package-lock.json +++ b/src-ui/package-lock.json @@ -27,6 +27,7 @@ "ngx-clipboard": "^16.0.0", "ngx-color": "^9.0.0", "ngx-cookie-service": "^16.0.1", + "ngx-drag-drop": "^16.1.0", "ngx-file-drop": "^16.0.0", "ngx-ui-tour-ng-bootstrap": "^13.0.4", "rxjs": "^7.8.1", @@ -14061,6 +14062,18 @@ "@angular/core": "^16.0.0" } }, + "node_modules/ngx-drag-drop": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/ngx-drag-drop/-/ngx-drag-drop-16.1.0.tgz", + "integrity": "sha512-y2l9pJGD7OupsIRkCElN/JqTgzjg2V9ZxymKGQR7ZjjcdjaP1wKkiFWIgVEvLNtb8wgm10U+9tkGwLClGaHkQA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^16.0.0", + "@angular/core": "^16.0.0" + } + }, "node_modules/ngx-file-drop": { "version": "16.0.0", "resolved": "https://registry.npmjs.org/ngx-file-drop/-/ngx-file-drop-16.0.0.tgz", diff --git a/src-ui/package.json b/src-ui/package.json index d70a59666..2fd5d82ee 100644 --- a/src-ui/package.json +++ b/src-ui/package.json @@ -29,6 +29,7 @@ "ngx-clipboard": "^16.0.0", "ngx-color": "^9.0.0", "ngx-cookie-service": "^16.0.1", + "ngx-drag-drop": "^16.1.0", "ngx-file-drop": "^16.0.0", "ngx-ui-tour-ng-bootstrap": "^13.0.4", "rxjs": "^7.8.1", diff --git a/src-ui/src/app/app.component.ts b/src-ui/src/app/app.component.ts index 0aa9ba210..d0f893da6 100644 --- a/src-ui/src/app/app.component.ts +++ b/src-ui/src/app/app.component.ts @@ -252,9 +252,12 @@ export class AppComponent implements OnInit, OnDestroy { } public get dragDropEnabled(): boolean { - return this.permissionsService.currentUserCan( - PermissionAction.Add, - PermissionType.Document + return ( + this.settings.globalDropzoneEnabled && + this.permissionsService.currentUserCan( + PermissionAction.Add, + PermissionType.Document + ) ) } diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts index 9d9307492..945dfe515 100644 --- a/src-ui/src/app/app.module.ts +++ b/src-ui/src/app/app.module.ts @@ -99,6 +99,7 @@ import { ConsumptionTemplatesComponent } from './components/manage/consumption-t import { ConsumptionTemplateEditDialogComponent } from './components/common/edit-dialog/consumption-template-edit-dialog/consumption-template-edit-dialog.component' import { MailComponent } from './components/manage/mail/mail.component' import { UsersAndGroupsComponent } from './components/admin/users-groups/users-groups.component' +import { DndModule } from 'ngx-drag-drop' import localeAf from '@angular/common/locales/af' import localeAr from '@angular/common/locales/ar' @@ -254,6 +255,7 @@ function initializeApp(settings: SettingsService) { NgSelectModule, ColorSliderModule, TourNgBootstrapModule, + DndModule, ], providers: [ { diff --git a/src-ui/src/app/components/dashboard/dashboard.component.html b/src-ui/src/app/components/dashboard/dashboard.component.html index 492f339a0..7b7116c15 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.html +++ b/src-ui/src/app/components/dashboard/dashboard.component.html @@ -4,7 +4,11 @@
-
+
Loading... @@ -15,12 +19,17 @@
- -
- -
-
+
+ + +
+
diff --git a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts b/src-ui/src/app/components/dashboard/dashboard.component.spec.ts index 6d100510d..f48340205 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.spec.ts +++ b/src-ui/src/app/components/dashboard/dashboard.component.spec.ts @@ -17,12 +17,56 @@ import { NgxFileDropModule } from 'ngx-file-drop' import { RouterTestingModule } from '@angular/router/testing' import { TourNgBootstrapModule, TourService } from 'ngx-ui-tour-ng-bootstrap' import { LogoComponent } from '../common/logo/logo.component' +import { of, throwError } from 'rxjs' +import { DndDropEvent, DndModule } from 'ngx-drag-drop' +import { ToastService } from 'src/app/services/toast.service' +import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' + +const saved_views = [ + { + name: 'Saved View 0', + id: 0, + show_on_dashboard: true, + show_in_sidebar: true, + sort_field: 'name', + sort_reverse: true, + filter_rules: [], + }, + { + name: 'Saved View 1', + id: 1, + show_on_dashboard: false, + show_in_sidebar: false, + sort_field: 'name', + sort_reverse: true, + filter_rules: [], + }, + { + name: 'Saved View 2', + id: 2, + show_on_dashboard: true, + show_in_sidebar: false, + sort_field: 'name', + sort_reverse: true, + filter_rules: [], + }, + { + name: 'Saved View 3', + id: 3, + show_on_dashboard: true, + show_in_sidebar: false, + sort_field: 'name', + sort_reverse: true, + filter_rules: [], + }, +] describe('DashboardComponent', () => { let component: DashboardComponent let fixture: ComponentFixture let settingsService: SettingsService let tourService: TourService + let toastService: ToastService beforeEach(async () => { TestBed.configureTestingModule({ @@ -47,24 +91,13 @@ describe('DashboardComponent', () => { { provide: SavedViewService, useValue: { - dashboardViews: [ - { - id: 1, - name: 'saved view 1', - show_on_dashboard: true, - sort_field: 'added', - sort_reverse: true, - filter_rules: [], - }, - { - id: 2, - name: 'saved view 2', - show_on_dashboard: true, - sort_field: 'created', - sort_reverse: true, - filter_rules: [], - }, - ], + listAll: () => + of({ + all: [saved_views.map((v) => v.id)], + count: saved_views.length, + results: saved_views, + }), + dashboardViews: saved_views.filter((v) => v.show_on_dashboard), }, }, ], @@ -74,6 +107,7 @@ describe('DashboardComponent', () => { NgxFileDropModule, RouterTestingModule, TourNgBootstrapModule, + DndModule, ], }).compileComponents() @@ -82,7 +116,11 @@ describe('DashboardComponent', () => { first_name: 'Foo', last_name: 'Bar', } + jest.spyOn(settingsService, 'get').mockImplementation((key) => { + if (key === SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER) return [0, 2, 3] + }) tourService = TestBed.inject(TourService) + toastService = TestBed.inject(ToastService) fixture = TestBed.createComponent(DashboardComponent) component = fixture.componentInstance @@ -100,7 +138,7 @@ describe('DashboardComponent', () => { it('should show dashboard widgets', () => { expect( fixture.debugElement.queryAll(By.directive(SavedViewWidgetComponent)) - ).toHaveLength(2) + ).toHaveLength(saved_views.filter((v) => v.show_on_dashboard).length) }) it('should end tour service if still running and welcome widget dismissed', () => { @@ -116,4 +154,44 @@ describe('DashboardComponent', () => { component.completeTour() expect(settingsCompleteTourSpy).toHaveBeenCalled() }) + + it('should disable global dropzone on start drag + drop, re-enable after', () => { + expect(settingsService.globalDropzoneEnabled).toBeTruthy() + component.onDragStart(null) + expect(settingsService.globalDropzoneEnabled).toBeFalsy() + component.onDragEnd(null) + expect(settingsService.globalDropzoneEnabled).toBeTruthy() + }) + + it('should update saved view sorting on drag + drop, show info', () => { + const settingsSpy = jest.spyOn(settingsService, 'updateDashboardViewsSort') + const toastSpy = jest.spyOn(toastService, 'showInfo') + jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of(true)) + component.onDrop({ index: 2, data: saved_views[0] } as DndDropEvent) + component.onDragged(saved_views[0]) + expect(settingsSpy).toHaveBeenCalledWith([ + saved_views[2], + saved_views[0], + saved_views[3], + ]) + expect(toastSpy).toHaveBeenCalled() + component.onDrop({ data: saved_views[3] } as DndDropEvent) + }) + + it('should update saved view sorting on drag + drop, show info2', () => { + jest.spyOn(settingsService, 'get').mockImplementation((key) => { + if (key === SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER) return [] + }) + fixture.destroy() + fixture = TestBed.createComponent(DashboardComponent) + component = fixture.componentInstance + fixture.detectChanges() + const toastSpy = jest.spyOn(toastService, 'showError') + jest + .spyOn(settingsService, 'storeSettings') + .mockReturnValue(throwError(() => new Error('unable to save'))) + component.onDrop({ index: 2, data: saved_views[0] } as DndDropEvent) + component.onDragged(saved_views[0]) + expect(toastSpy).toHaveBeenCalled() + }) }) diff --git a/src-ui/src/app/components/dashboard/dashboard.component.ts b/src-ui/src/app/components/dashboard/dashboard.component.ts index 8d47495a8..1ac2b9962 100644 --- a/src-ui/src/app/components/dashboard/dashboard.component.ts +++ b/src-ui/src/app/components/dashboard/dashboard.component.ts @@ -3,6 +3,10 @@ import { SavedViewService } from 'src/app/services/rest/saved-view.service' import { SettingsService } from 'src/app/services/settings.service' import { ComponentWithPermissions } from '../with-permissions/with-permissions.component' import { TourService } from 'ngx-ui-tour-ng-bootstrap' +import { PaperlessSavedView } from 'src/app/data/paperless-saved-view' +import { DndDropEvent } from 'ngx-drag-drop' +import { ToastService } from 'src/app/services/toast.service' +import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings' @Component({ selector: 'pngx-dashboard', @@ -10,12 +14,38 @@ import { TourService } from 'ngx-ui-tour-ng-bootstrap' styleUrls: ['./dashboard.component.scss'], }) export class DashboardComponent extends ComponentWithPermissions { + public dashboardViews: PaperlessSavedView[] = [] constructor( public settingsService: SettingsService, public savedViewService: SavedViewService, - private tourService: TourService + private tourService: TourService, + private toastService: ToastService ) { super() + + this.savedViewService.listAll().subscribe(() => { + const sorted: number[] = this.settingsService.get( + SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER + ) + this.dashboardViews = + sorted?.length > 0 + ? sorted + .map((id) => + this.savedViewService.dashboardViews.find((v) => v.id === id) + ) + .concat( + this.savedViewService.dashboardViews.filter( + (v) => !sorted.includes(v.id) + ) + ) + .filter((v) => v) + : [...this.savedViewService.dashboardViews] + console.log( + this.dashboardViews, + sorted, + this.savedViewService.dashboardViews + ) + }) } get subtitle() { @@ -33,4 +63,35 @@ export class DashboardComponent extends ComponentWithPermissions { this.settingsService.completeTour() } } + + onDragStart(event: DragEvent) { + this.settingsService.globalDropzoneEnabled = false + } + + onDragged(v: PaperlessSavedView) { + const index = this.dashboardViews.indexOf(v) + this.dashboardViews.splice(index, 1) + this.settingsService + .updateDashboardViewsSort(this.dashboardViews) + .subscribe({ + next: () => { + this.toastService.showInfo($localize`Dashboard updated`) + }, + error: (e) => { + this.toastService.showError($localize`Error updating dashboard`, e) + }, + }) + } + + onDragEnd(event: DragEvent) { + this.settingsService.globalDropzoneEnabled = true + } + + onDrop(event: DndDropEvent) { + if (typeof event.index === 'undefined') { + event.index = this.dashboardViews.length + } + + this.dashboardViews.splice(event.index, 0, event.data) + } } diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html index 4013c5085..fdaa7e9e2 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.html @@ -1,4 +1,13 @@ - + Show all diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts index 7b9c5c8b0..c355bdf61 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.spec.ts @@ -28,6 +28,7 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component' import { SavedViewWidgetComponent } from './saved-view-widget.component' import { By } from '@angular/platform-browser' import { SafeUrlPipe } from 'src/app/pipes/safeurl.pipe' +import { DndModule } from 'ngx-drag-drop' const savedView: PaperlessSavedView = { id: 1, @@ -90,6 +91,7 @@ describe('SavedViewWidgetComponent', () => { HttpClientTestingModule, NgbModule, RouterTestingModule.withRoutes(routes), + DndModule, ], }).compileComponents() diff --git a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts index 982aeebaa..f6a5d8c49 100644 --- a/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/saved-view-widget/saved-view-widget.component.ts @@ -1,8 +1,10 @@ import { Component, + EventEmitter, Input, OnDestroy, OnInit, + Output, QueryList, ViewChildren, } from '@angular/core' @@ -51,6 +53,18 @@ export class SavedViewWidgetComponent @Input() savedView: PaperlessSavedView + @Output() + dndStart: EventEmitter = new EventEmitter() + + @Output() + dndMoved: EventEmitter = new EventEmitter() + + @Output() + dndCanceled: EventEmitter = new EventEmitter() + + @Output() + dndEnd: EventEmitter = new EventEmitter() + documents: PaperlessDocument[] = [] unsubscribeNotifier: Subject = new Subject() diff --git a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts index 5bddfaab1..609f0dd7d 100644 --- a/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/statistics-widget/statistics-widget.component.spec.ts @@ -12,6 +12,7 @@ import { RouterTestingModule } from '@angular/router/testing' import { routes } from 'src/app/app-routing.module' import { PermissionsGuard } from 'src/app/guards/permissions.guard' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' +import { DndModule } from 'ngx-drag-drop' describe('StatisticsWidgetComponent', () => { let component: StatisticsWidgetComponent @@ -30,6 +31,7 @@ describe('StatisticsWidgetComponent', () => { HttpClientTestingModule, NgbModule, RouterTestingModule.withRoutes(routes), + DndModule, ], }).compileComponents() diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts index 3afebc7b2..c180af768 100644 --- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.spec.ts @@ -26,6 +26,7 @@ import { PermissionsService } from 'src/app/services/permissions.service' import { UploadDocumentsService } from 'src/app/services/upload-documents.service' import { WidgetFrameComponent } from '../widget-frame/widget-frame.component' import { UploadFileWidgetComponent } from './upload-file-widget.component' +import { DndModule } from 'ngx-drag-drop' describe('UploadFileWidgetComponent', () => { let component: UploadFileWidgetComponent @@ -55,6 +56,7 @@ describe('UploadFileWidgetComponent', () => { RouterTestingModule.withRoutes(routes), NgxFileDropModule, NgbAlertModule, + DndModule, ], }).compileComponents() diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html index 60fa945af..1fb998073 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html @@ -1,7 +1,21 @@ -
+
-
{{title}}
+
+
+ + + +
+
{{title}}
+
Loading...
diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.scss b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.scss index e69de29bb..e68bdef28 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.scss +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.scss @@ -0,0 +1,3 @@ +svg { + cursor: move; +} diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts index a0ff0a50d..74665ea01 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.spec.ts @@ -4,6 +4,7 @@ import { By } from '@angular/platform-browser' import { NgbAlertModule, NgbAlert } from '@ng-bootstrap/ng-bootstrap' import { PermissionsGuard } from 'src/app/guards/permissions.guard' import { WidgetFrameComponent } from './widget-frame.component' +import { DndModule } from 'ngx-drag-drop' @Component({ template: ` @@ -29,7 +30,7 @@ describe('WidgetFrameComponent', () => { TestBed.configureTestingModule({ declarations: [WidgetFrameComponent, WidgetFrameComponent], providers: [PermissionsGuard], - imports: [NgbAlertModule], + imports: [NgbAlertModule, DndModule], }).compileComponents() fixture = TestBed.createComponent(WidgetFrameComponent) diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts index 65f80ed08..e19154dce 100644 --- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts +++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core' +import { Component, EventEmitter, Input, Output } from '@angular/core' @Component({ selector: 'pngx-widget-frame', @@ -13,4 +13,19 @@ export class WidgetFrameComponent { @Input() loading: boolean = false + + @Input() + draggable: any + + @Output() + dndStart: EventEmitter = new EventEmitter() + + @Output() + dndMoved: EventEmitter = new EventEmitter() + + @Output() + dndCanceled: EventEmitter = new EventEmitter() + + @Output() + dndEnd: EventEmitter = new EventEmitter() } diff --git a/src-ui/src/app/data/paperless-uisettings.ts b/src-ui/src/app/data/paperless-uisettings.ts index 064ebcf33..2f1e9e230 100644 --- a/src-ui/src/app/data/paperless-uisettings.ts +++ b/src-ui/src/app/data/paperless-uisettings.ts @@ -41,6 +41,8 @@ export const SETTINGS_KEYS = { 'general-settings:update-checking:backend-setting', SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE: 'general-settings:saved-views:warn-on-unsaved-change', + DASHBOARD_VIEWS_SORT_ORDER: + 'general-settings:saved-views:dashboard-views-sort-order', TOUR_COMPLETE: 'general-settings:tour-complete', DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner', DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users', @@ -180,4 +182,9 @@ export const SETTINGS: PaperlessUiSetting[] = [ type: 'array', default: [], }, + { + key: SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER, + type: 'array', + default: [], + }, ] diff --git a/src-ui/src/app/services/settings.service.spec.ts b/src-ui/src/app/services/settings.service.spec.ts index c0ba16d74..e7d13dffc 100644 --- a/src-ui/src/app/services/settings.service.spec.ts +++ b/src-ui/src/app/services/settings.service.spec.ts @@ -15,6 +15,7 @@ import { SETTINGS_KEYS, } from '../data/paperless-uisettings' import { SettingsService } from './settings.service' +import { PaperlessSavedView } from '../data/paperless-saved-view' describe('SettingsService', () => { let httpTestingController: HttpTestingController @@ -277,4 +278,22 @@ describe('SettingsService', () => { )[0] expect(req.request.method).toEqual('POST') }) + + it('should update saved view sorting', () => { + httpTestingController + .expectOne(`${environment.apiBaseUrl}ui_settings/`) + .flush(ui_settings) + const setSpy = jest.spyOn(settingsService, 'set') + settingsService.updateDashboardViewsSort([ + { id: 1 } as PaperlessSavedView, + { id: 4 } as PaperlessSavedView, + ]) + expect(setSpy).toHaveBeenCalledWith( + SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER, + [1, 4] + ) + httpTestingController + .expectOne(`${environment.apiBaseUrl}ui_settings/`) + .flush(ui_settings) + }) }) diff --git a/src-ui/src/app/services/settings.service.ts b/src-ui/src/app/services/settings.service.ts index bd6404106..7fbb5e575 100644 --- a/src-ui/src/app/services/settings.service.ts +++ b/src-ui/src/app/services/settings.service.ts @@ -26,6 +26,7 @@ import { PaperlessUser } from '../data/paperless-user' import { PermissionsService } from './permissions.service' import { SavedViewService } from './rest/saved-view.service' import { ToastService } from './toast.service' +import { PaperlessSavedView } from '../data/paperless-saved-view' export interface LanguageOption { code: string @@ -54,6 +55,8 @@ export class SettingsService { return this._renderer } + public globalDropzoneEnabled: boolean = true + constructor( rendererFactory: RendererFactory2, @Inject(DOCUMENT) private document, @@ -531,4 +534,13 @@ export class SettingsService { }) } } + + updateDashboardViewsSort( + dashboardViews: PaperlessSavedView[] + ): Observable { + this.set(SETTINGS_KEYS.DASHBOARD_VIEWS_SORT_ORDER, [ + ...new Set(dashboardViews.map((v) => v.id)), + ]) + return this.storeSettings() + } }