mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 19:17:13 -05:00 
			
		
		
		
	Enhancement: display saved view counts (#10246)
This commit is contained in:
		
							parent
							
								
									1fe8599266
								
							
						
					
					
						commit
						293c84d871
					
				@ -176,6 +176,7 @@
 | 
			
		||||
            <div class="row">
 | 
			
		||||
              <div class="col">
 | 
			
		||||
                <pngx-input-check i18n-title title="Show warning when closing saved views with unsaved changes" formControlName="savedViewsWarnOnUnsavedChange"></pngx-input-check>
 | 
			
		||||
                <pngx-input-check i18n-title title="Show document counts in sidebar saved views" formControlName="sidebarViewsShowCount"></pngx-input-check>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
 | 
			
		||||
import { SafeHtmlPipe } from 'src/app/pipes/safehtml.pipe'
 | 
			
		||||
import { PermissionsService } from 'src/app/services/permissions.service'
 | 
			
		||||
import { GroupService } from 'src/app/services/rest/group.service'
 | 
			
		||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
 | 
			
		||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
			
		||||
import { SettingsService } from 'src/app/services/settings.service'
 | 
			
		||||
import { SystemStatusService } from 'src/app/services/system-status.service'
 | 
			
		||||
@ -72,6 +73,7 @@ describe('SettingsComponent', () => {
 | 
			
		||||
  let groupService: GroupService
 | 
			
		||||
  let modalService: NgbModal
 | 
			
		||||
  let systemStatusService: SystemStatusService
 | 
			
		||||
  let savedViewsService: SavedViewService
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    TestBed.configureTestingModule({
 | 
			
		||||
@ -122,6 +124,7 @@ describe('SettingsComponent', () => {
 | 
			
		||||
    permissionsService = TestBed.inject(PermissionsService)
 | 
			
		||||
    modalService = TestBed.inject(NgbModal)
 | 
			
		||||
    systemStatusService = TestBed.inject(SystemStatusService)
 | 
			
		||||
    savedViewsService = TestBed.inject(SavedViewService)
 | 
			
		||||
    jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
 | 
			
		||||
    jest
 | 
			
		||||
      .spyOn(permissionsService, 'currentUserHasObjectPermissions')
 | 
			
		||||
@ -212,7 +215,7 @@ describe('SettingsComponent', () => {
 | 
			
		||||
    expect(toastErrorSpy).toHaveBeenCalled()
 | 
			
		||||
    expect(storeSpy).toHaveBeenCalled()
 | 
			
		||||
    expect(appearanceSettingsSpy).not.toHaveBeenCalled()
 | 
			
		||||
    expect(setSpy).toHaveBeenCalledTimes(29)
 | 
			
		||||
    expect(setSpy).toHaveBeenCalledTimes(30)
 | 
			
		||||
 | 
			
		||||
    // succeed
 | 
			
		||||
    storeSpy.mockReturnValueOnce(of(true))
 | 
			
		||||
@ -345,4 +348,14 @@ describe('SettingsComponent', () => {
 | 
			
		||||
    component.reset()
 | 
			
		||||
    expect(component.settingsForm.get('themeColor').value).toEqual('')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should trigger maybeRefreshDocumentCounts on settings save', () => {
 | 
			
		||||
    completeSetup()
 | 
			
		||||
    const maybeRefreshSpy = jest.spyOn(
 | 
			
		||||
      savedViewsService,
 | 
			
		||||
      'maybeRefreshDocumentCounts'
 | 
			
		||||
    )
 | 
			
		||||
    settingsService.settingsSaved.emit(true)
 | 
			
		||||
    expect(maybeRefreshSpy).toHaveBeenCalled()
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ import {
 | 
			
		||||
  PermissionsService,
 | 
			
		||||
} from 'src/app/services/permissions.service'
 | 
			
		||||
import { GroupService } from 'src/app/services/rest/group.service'
 | 
			
		||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
 | 
			
		||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
			
		||||
import {
 | 
			
		||||
  LanguageOption,
 | 
			
		||||
@ -117,6 +118,7 @@ export class SettingsComponent
 | 
			
		||||
  permissionsService = inject(PermissionsService)
 | 
			
		||||
  private modalService = inject(NgbModal)
 | 
			
		||||
  private systemStatusService = inject(SystemStatusService)
 | 
			
		||||
  private savedViewsService = inject(SavedViewService)
 | 
			
		||||
 | 
			
		||||
  activeNavID: number
 | 
			
		||||
 | 
			
		||||
@ -152,6 +154,7 @@ export class SettingsComponent
 | 
			
		||||
    notificationsConsumerSuppressOnDashboard: new FormControl(null),
 | 
			
		||||
 | 
			
		||||
    savedViewsWarnOnUnsavedChange: new FormControl(null),
 | 
			
		||||
    sidebarViewsShowCount: new FormControl(null),
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  SettingsNavIDs = SettingsNavIDs
 | 
			
		||||
@ -197,6 +200,7 @@ export class SettingsComponent
 | 
			
		||||
    super()
 | 
			
		||||
    this.settings.settingsSaved.subscribe(() => {
 | 
			
		||||
      if (!this.savePending) this.initialize()
 | 
			
		||||
      this.savedViewsService.maybeRefreshDocumentCounts()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -308,6 +312,9 @@ export class SettingsComponent
 | 
			
		||||
      savedViewsWarnOnUnsavedChange: this.settings.get(
 | 
			
		||||
        SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE
 | 
			
		||||
      ),
 | 
			
		||||
      sidebarViewsShowCount: this.settings.get(
 | 
			
		||||
        SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT
 | 
			
		||||
      ),
 | 
			
		||||
      defaultPermsOwner: this.settings.get(SETTINGS_KEYS.DEFAULT_PERMS_OWNER),
 | 
			
		||||
      defaultPermsViewUsers: this.settings.get(
 | 
			
		||||
        SETTINGS_KEYS.DEFAULT_PERMS_VIEW_USERS
 | 
			
		||||
@ -485,6 +492,10 @@ export class SettingsComponent
 | 
			
		||||
      SETTINGS_KEYS.SAVED_VIEWS_WARN_ON_UNSAVED_CHANGE,
 | 
			
		||||
      this.settingsForm.value.savedViewsWarnOnUnsavedChange
 | 
			
		||||
    )
 | 
			
		||||
    this.settings.set(
 | 
			
		||||
      SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT,
 | 
			
		||||
      this.settingsForm.value.sidebarViewsShowCount
 | 
			
		||||
    )
 | 
			
		||||
    this.settings.set(
 | 
			
		||||
      SETTINGS_KEYS.DEFAULT_PERMS_OWNER,
 | 
			
		||||
      this.settingsForm.value.defaultPermsOwner
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,14 @@
 | 
			
		||||
                    routerLinkActive="active" (click)="closeMenu()" [ngbPopover]="view.name"
 | 
			
		||||
                    [disablePopover]="!slimSidebarEnabled" placement="end" container="body" triggers="mouseenter:mouseleave"
 | 
			
		||||
                    popoverClass="popover-slim">
 | 
			
		||||
                    <i-bs class="me-1" name="funnel"></i-bs><span> {{view.name}}</span>
 | 
			
		||||
                    <i-bs class="me-1" name="funnel"></i-bs><span> {{view.name}}
 | 
			
		||||
                      @if (showSidebarCounts && !slimSidebarEnabled) {
 | 
			
		||||
                        <span><span class="badge bg-info text-dark ms-2 d-inline">{{ savedViewService.getDocumentCount(view) }}</span></span>
 | 
			
		||||
                      }
 | 
			
		||||
                    </span>
 | 
			
		||||
                    @if (showSidebarCounts && slimSidebarEnabled) {
 | 
			
		||||
                      <span class="badge bg-info text-dark position-absolute top-0 end-0 d-none d-md-block">{{ savedViewService.getDocumentCount(view) }}</span>
 | 
			
		||||
                    }
 | 
			
		||||
                  </a>
 | 
			
		||||
                  @if (settingsService.organizingSidebarSavedViews) {
 | 
			
		||||
                    <div class="position-absolute end-0 top-0 px-3 py-2" [class.me-n3]="slimSidebarEnabled" cdkDragHandle>
 | 
			
		||||
 | 
			
		||||
@ -92,6 +92,7 @@ describe('AppFrameComponent', () => {
 | 
			
		||||
  let router: Router
 | 
			
		||||
  let savedViewSpy
 | 
			
		||||
  let modalService: NgbModal
 | 
			
		||||
  let maybeRefreshSpy
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
    TestBed.configureTestingModule({
 | 
			
		||||
@ -113,7 +114,11 @@ describe('AppFrameComponent', () => {
 | 
			
		||||
        {
 | 
			
		||||
          provide: SavedViewService,
 | 
			
		||||
          useValue: {
 | 
			
		||||
            reload: () => {},
 | 
			
		||||
            reload: (fn: any) => {
 | 
			
		||||
              if (fn) {
 | 
			
		||||
                fn()
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            listAll: () =>
 | 
			
		||||
              of({
 | 
			
		||||
                all: [saved_views.map((v) => v.id)],
 | 
			
		||||
@ -121,6 +126,8 @@ describe('AppFrameComponent', () => {
 | 
			
		||||
                results: saved_views,
 | 
			
		||||
              }),
 | 
			
		||||
            sidebarViews: saved_views.filter((v) => v.show_in_sidebar),
 | 
			
		||||
            getDocumentCount: (view: SavedView) => 5,
 | 
			
		||||
            maybeRefreshDocumentCounts: () => {},
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        PermissionsService,
 | 
			
		||||
@ -169,6 +176,7 @@ describe('AppFrameComponent', () => {
 | 
			
		||||
    jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
 | 
			
		||||
 | 
			
		||||
    savedViewSpy = jest.spyOn(savedViewService, 'reload')
 | 
			
		||||
    maybeRefreshSpy = jest.spyOn(savedViewService, 'maybeRefreshDocumentCounts')
 | 
			
		||||
 | 
			
		||||
    fixture = TestBed.createComponent(AppFrameComponent)
 | 
			
		||||
    component = fixture.componentInstance
 | 
			
		||||
@ -359,4 +367,8 @@ describe('AppFrameComponent', () => {
 | 
			
		||||
    expect(toastErrorSpy).toHaveBeenCalledTimes(2)
 | 
			
		||||
    expect(toastInfoSpy).toHaveBeenCalledTimes(3)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should call maybeRefreshDocumentCounts after saved views reload', () => {
 | 
			
		||||
    expect(maybeRefreshSpy).toHaveBeenCalled()
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,9 @@ export class AppFrameComponent
 | 
			
		||||
        PermissionType.SavedView
 | 
			
		||||
      )
 | 
			
		||||
    ) {
 | 
			
		||||
      this.savedViewService.reload()
 | 
			
		||||
      this.savedViewService.reload(() => {
 | 
			
		||||
        this.savedViewService.maybeRefreshDocumentCounts()
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -283,4 +285,8 @@ export class AppFrameComponent
 | 
			
		||||
  onLogout() {
 | 
			
		||||
    this.openDocumentsService.closeAll()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get showSidebarCounts(): boolean {
 | 
			
		||||
    return this.settingsService.get(SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
<pngx-widget-frame
 | 
			
		||||
  *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Document }"
 | 
			
		||||
  [title]="savedView.name"
 | 
			
		||||
  [badge]="count"
 | 
			
		||||
  [loading]="loading"
 | 
			
		||||
  [draggable]="savedView"
 | 
			
		||||
  >
 | 
			
		||||
 | 
			
		||||
@ -118,6 +118,8 @@ export class SavedViewWidgetComponent
 | 
			
		||||
 | 
			
		||||
  displayFields: DisplayField[] = DEFAULT_DASHBOARD_DISPLAY_FIELDS
 | 
			
		||||
 | 
			
		||||
  count: number
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.reload()
 | 
			
		||||
    this.displayMode = this.savedView.display_mode ?? DisplayMode.TABLE
 | 
			
		||||
@ -178,6 +180,7 @@ export class SavedViewWidgetComponent
 | 
			
		||||
        tap((result) => {
 | 
			
		||||
          this.show = true
 | 
			
		||||
          this.documents = result.results
 | 
			
		||||
          this.count = result.count
 | 
			
		||||
        }),
 | 
			
		||||
        delay(500)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
@ -2,13 +2,16 @@
 | 
			
		||||
  <div class="card shadow-sm bg-light fade" [class.show]="show" cdkDrag [cdkDragDisabled]="!draggable" cdkDragPreviewContainer="parent">
 | 
			
		||||
    <div class="card-header">
 | 
			
		||||
      <div class="d-flex justify-content-between align-items-center">
 | 
			
		||||
        <div class="d-flex">
 | 
			
		||||
        <div class="d-flex align-items-center">
 | 
			
		||||
          @if (draggable) {
 | 
			
		||||
            <div class="ms-n2 me-1" cdkDragHandle>
 | 
			
		||||
              <i-bs name="grip-vertical"></i-bs>
 | 
			
		||||
            </div>
 | 
			
		||||
          }
 | 
			
		||||
          <h6 class="card-title mb-0">{{title}}</h6>
 | 
			
		||||
          @if (badge) {
 | 
			
		||||
            <span class="badge bg-info text-dark ms-2">{{badge}}</span>
 | 
			
		||||
          }
 | 
			
		||||
        </div>
 | 
			
		||||
        @if (loading) {
 | 
			
		||||
          <div class="spinner-border spinner-border-sm fw-normal ms-2 me-auto" role="status"></div>
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,9 @@ export class WidgetFrameComponent
 | 
			
		||||
  @Input()
 | 
			
		||||
  cardless: boolean = false
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  badge: string
 | 
			
		||||
 | 
			
		||||
  ngAfterViewInit(): void {
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      this.show = true
 | 
			
		||||
 | 
			
		||||
@ -73,6 +73,7 @@ import { CorrespondentService } from 'src/app/services/rest/correspondent.servic
 | 
			
		||||
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
 | 
			
		||||
import { DocumentTypeService } from 'src/app/services/rest/document-type.service'
 | 
			
		||||
import { DocumentService } from 'src/app/services/rest/document.service'
 | 
			
		||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
 | 
			
		||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
 | 
			
		||||
import { UserService } from 'src/app/services/rest/user.service'
 | 
			
		||||
import { SettingsService } from 'src/app/services/settings.service'
 | 
			
		||||
@ -195,6 +196,7 @@ export class DocumentDetailComponent
 | 
			
		||||
  private hotKeyService = inject(HotKeyService)
 | 
			
		||||
  private componentRouterService = inject(ComponentRouterService)
 | 
			
		||||
  private deviceDetectorService = inject(DeviceDetectorService)
 | 
			
		||||
  private savedViewService = inject(SavedViewService)
 | 
			
		||||
 | 
			
		||||
  @ViewChild('inputTitle')
 | 
			
		||||
  titleInput: TextComponent
 | 
			
		||||
@ -841,6 +843,7 @@ export class DocumentDetailComponent
 | 
			
		||||
          } else {
 | 
			
		||||
            this.openDocumentService.refreshDocument(this.documentId)
 | 
			
		||||
          }
 | 
			
		||||
          this.savedViewService.maybeRefreshDocumentCounts()
 | 
			
		||||
        },
 | 
			
		||||
        error: (error) => {
 | 
			
		||||
          this.networkActive = false
 | 
			
		||||
@ -1188,6 +1191,7 @@ export class DocumentDetailComponent
 | 
			
		||||
  notesUpdated(notes: DocumentNote[]) {
 | 
			
		||||
    this.document.notes = notes
 | 
			
		||||
    this.openDocumentService.refreshDocument(this.documentId)
 | 
			
		||||
    this.savedViewService.maybeRefreshDocumentCounts()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get userIsOwner(): boolean {
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@ import {
 | 
			
		||||
  DocumentService,
 | 
			
		||||
  SelectionDataItem,
 | 
			
		||||
} from 'src/app/services/rest/document.service'
 | 
			
		||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
 | 
			
		||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
 | 
			
		||||
import { TagService } from 'src/app/services/rest/tag.service'
 | 
			
		||||
import { SettingsService } from 'src/app/services/settings.service'
 | 
			
		||||
@ -83,6 +84,7 @@ export class BulkEditorComponent
 | 
			
		||||
  private storagePathService = inject(StoragePathService)
 | 
			
		||||
  private customFieldService = inject(CustomFieldsService)
 | 
			
		||||
  private permissionService = inject(PermissionsService)
 | 
			
		||||
  private savedViewService = inject(SavedViewService)
 | 
			
		||||
 | 
			
		||||
  tagSelectionModel = new FilterableDropdownSelectionModel(true)
 | 
			
		||||
  correspondentSelectionModel = new FilterableDropdownSelectionModel()
 | 
			
		||||
@ -270,6 +272,7 @@ export class BulkEditorComponent
 | 
			
		||||
          this.list.selected.forEach((id) => {
 | 
			
		||||
            this.openDocumentService.refreshDocument(id)
 | 
			
		||||
          })
 | 
			
		||||
          this.savedViewService.maybeRefreshDocumentCounts()
 | 
			
		||||
          if (modal) {
 | 
			
		||||
            modal.close()
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,8 @@ export const SETTINGS_KEYS = {
 | 
			
		||||
    'general-settings:saved-views:dashboard-views-sort-order',
 | 
			
		||||
  SIDEBAR_VIEWS_SORT_ORDER:
 | 
			
		||||
    'general-settings:saved-views:sidebar-views-sort-order',
 | 
			
		||||
  SIDEBAR_VIEWS_SHOW_COUNT:
 | 
			
		||||
    'general-settings:saved-views:sidebar-views-show-count',
 | 
			
		||||
  TOUR_COMPLETE: 'general-settings:tour-complete',
 | 
			
		||||
  DEFAULT_PERMS_OWNER: 'general-settings:permissions:default-owner',
 | 
			
		||||
  DEFAULT_PERMS_VIEW_USERS: 'general-settings:permissions:default-view-users',
 | 
			
		||||
@ -227,6 +229,11 @@ export const SETTINGS: UiSetting[] = [
 | 
			
		||||
    type: 'array',
 | 
			
		||||
    default: [],
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT,
 | 
			
		||||
    type: 'boolean',
 | 
			
		||||
    default: true,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: SETTINGS_KEYS.APP_LOGO,
 | 
			
		||||
    type: 'string',
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ const saved_views = [
 | 
			
		||||
    id: 1,
 | 
			
		||||
    show_on_dashboard: true,
 | 
			
		||||
    show_in_sidebar: true,
 | 
			
		||||
    sort_field: 'name',
 | 
			
		||||
    sort_field: 'title',
 | 
			
		||||
    sort_reverse: true,
 | 
			
		||||
    filter_rules: [],
 | 
			
		||||
  },
 | 
			
		||||
@ -26,7 +26,7 @@ const saved_views = [
 | 
			
		||||
    id: 2,
 | 
			
		||||
    show_on_dashboard: true,
 | 
			
		||||
    show_in_sidebar: true,
 | 
			
		||||
    sort_field: 'name',
 | 
			
		||||
    sort_field: 'created',
 | 
			
		||||
    sort_reverse: true,
 | 
			
		||||
    filter_rules: [],
 | 
			
		||||
  },
 | 
			
		||||
@ -35,7 +35,7 @@ const saved_views = [
 | 
			
		||||
    id: 3,
 | 
			
		||||
    show_on_dashboard: true,
 | 
			
		||||
    show_in_sidebar: true,
 | 
			
		||||
    sort_field: 'name',
 | 
			
		||||
    sort_field: 'added',
 | 
			
		||||
    sort_reverse: true,
 | 
			
		||||
    filter_rules: [],
 | 
			
		||||
  },
 | 
			
		||||
@ -44,7 +44,7 @@ const saved_views = [
 | 
			
		||||
    id: 4,
 | 
			
		||||
    show_on_dashboard: false,
 | 
			
		||||
    show_in_sidebar: false,
 | 
			
		||||
    sort_field: 'name',
 | 
			
		||||
    sort_field: 'owner',
 | 
			
		||||
    sort_reverse: true,
 | 
			
		||||
    filter_rules: [],
 | 
			
		||||
  },
 | 
			
		||||
@ -222,6 +222,43 @@ describe(`Additional service tests for SavedViewService`, () => {
 | 
			
		||||
      })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should accept a callback for reload', () => {
 | 
			
		||||
    const reloadSpy = jest.fn()
 | 
			
		||||
    service.reload(reloadSpy)
 | 
			
		||||
    const req = httpTestingController.expectOne(
 | 
			
		||||
      `${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
 | 
			
		||||
    )
 | 
			
		||||
    req.flush({
 | 
			
		||||
      results: saved_views,
 | 
			
		||||
    })
 | 
			
		||||
    expect(reloadSpy).toHaveBeenCalled()
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should support getting document counts for views', () => {
 | 
			
		||||
    service.maybeRefreshDocumentCounts(saved_views)
 | 
			
		||||
    saved_views.forEach((saved_view) => {
 | 
			
		||||
      const req = httpTestingController.expectOne(
 | 
			
		||||
        `${environment.apiBaseUrl}documents/?page=1&page_size=1&ordering=-${saved_view.sort_field}&fields=id&truncate_content=true`
 | 
			
		||||
      )
 | 
			
		||||
      req.flush({
 | 
			
		||||
        all: [],
 | 
			
		||||
        count: 1,
 | 
			
		||||
        results: [{ id: 1 }],
 | 
			
		||||
      })
 | 
			
		||||
    })
 | 
			
		||||
    expect(service.getDocumentCount(saved_views[0])).toEqual(1)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should not refresh document counts if setting is disabled', () => {
 | 
			
		||||
    jest.spyOn(settingsService, 'get').mockImplementation((key) => {
 | 
			
		||||
      if (key === SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT) return false
 | 
			
		||||
    })
 | 
			
		||||
    service.maybeRefreshDocumentCounts(saved_views)
 | 
			
		||||
    httpTestingController.expectNone(
 | 
			
		||||
      `${environment.apiBaseUrl}documents/?page=1&page_size=1&ordering=-${saved_views[0].sort_field}&fields=id&truncate_content=true`
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    // Dont need to setup again
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,13 @@
 | 
			
		||||
import { HttpClient } from '@angular/common/http'
 | 
			
		||||
import { inject, Injectable } from '@angular/core'
 | 
			
		||||
import { combineLatest, Observable } from 'rxjs'
 | 
			
		||||
import { tap } from 'rxjs/operators'
 | 
			
		||||
import { combineLatest, Observable, Subject } from 'rxjs'
 | 
			
		||||
import { takeUntil, tap } from 'rxjs/operators'
 | 
			
		||||
import { Results } from 'src/app/data/results'
 | 
			
		||||
import { SavedView } from 'src/app/data/saved-view'
 | 
			
		||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
 | 
			
		||||
import { SettingsService } from '../settings.service'
 | 
			
		||||
import { AbstractPaperlessService } from './abstract-paperless-service'
 | 
			
		||||
import { DocumentService } from './document.service'
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root',
 | 
			
		||||
@ -14,9 +15,12 @@ import { AbstractPaperlessService } from './abstract-paperless-service'
 | 
			
		||||
export class SavedViewService extends AbstractPaperlessService<SavedView> {
 | 
			
		||||
  protected http: HttpClient
 | 
			
		||||
  private settingsService = inject(SettingsService)
 | 
			
		||||
  private documentService = inject(DocumentService)
 | 
			
		||||
 | 
			
		||||
  public loading: boolean = true
 | 
			
		||||
  private savedViews: SavedView[] = []
 | 
			
		||||
  private savedViewDocumentCounts: Map<number, number> = new Map()
 | 
			
		||||
  private unsubscribeNotifier: Subject<void> = new Subject<void>()
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super()
 | 
			
		||||
@ -46,8 +50,16 @@ export class SavedViewService extends AbstractPaperlessService<SavedView> {
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public reload() {
 | 
			
		||||
    this.listAll().subscribe()
 | 
			
		||||
  public reload(callback: any = null) {
 | 
			
		||||
    this.listAll()
 | 
			
		||||
      .pipe(
 | 
			
		||||
        tap((r) => {
 | 
			
		||||
          if (callback) {
 | 
			
		||||
            callback(r)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get allViews() {
 | 
			
		||||
@ -110,4 +122,30 @@ export class SavedViewService extends AbstractPaperlessService<SavedView> {
 | 
			
		||||
  delete(o: SavedView) {
 | 
			
		||||
    return super.delete(o).pipe(tap(() => this.reload()))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public maybeRefreshDocumentCounts(views: SavedView[] = this.sidebarViews) {
 | 
			
		||||
    if (!this.settingsService.get(SETTINGS_KEYS.SIDEBAR_VIEWS_SHOW_COUNT)) {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    this.unsubscribeNotifier.next() // clear previous subscriptions
 | 
			
		||||
    views.forEach((view) => {
 | 
			
		||||
      this.documentService
 | 
			
		||||
        .listFiltered(
 | 
			
		||||
          1,
 | 
			
		||||
          1,
 | 
			
		||||
          view.sort_field,
 | 
			
		||||
          view.sort_reverse,
 | 
			
		||||
          view.filter_rules,
 | 
			
		||||
          { fields: 'id', truncate_content: true }
 | 
			
		||||
        )
 | 
			
		||||
        .pipe(takeUntil(this.unsubscribeNotifier))
 | 
			
		||||
        .subscribe((results: Results<Document>) => {
 | 
			
		||||
          this.savedViewDocumentCounts.set(view.id, results.count)
 | 
			
		||||
        })
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getDocumentCount(view: SavedView): number {
 | 
			
		||||
    return this.savedViewDocumentCounts.get(view.id)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user