mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-21 07:18:13 +00:00
Enhancement: add upload count to button, link to tray, reduce notifications (#14501)
This commit is contained in:
1 parent
f8e93a535a
commit
3374debd6a
10 files changed
+125
-18
No files matched your search
@@ -31,11 +31,18 @@
|
||||
[class.mobile-hidden]="mobileSearchHidden()">
|
||||
<div class="col-12 header-search mx-auto d-flex align-items-stretch gap-3">
|
||||
<pngx-global-search class="flex-grow-1"></pngx-global-search>
|
||||
<button *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Document }"
|
||||
class="btn btn-sm header-upload border-0 d-flex align-items-center justify-content-center flex-shrink-0 py-0 px-2" type="button"
|
||||
(click)="fileUpload.click()" aria-label="Upload documents" i18n-aria-label>
|
||||
<i-bs class="d-flex" width="1.1em" height="1.1em" name="file-earmark-arrow-up"></i-bs><span class="ms-2 d-sm-none d-md-inline" i18n>Upload</span>
|
||||
</button>
|
||||
<div *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.Document }" class="btn-group header-upload-group flex-shrink-0">
|
||||
<button class="btn btn-sm header-upload border-0 d-flex align-items-center justify-content-center py-0 px-2" type="button"
|
||||
(click)="fileUpload.click()" aria-label="Upload documents" i18n-aria-label>
|
||||
<i-bs class="d-flex" width="1.1em" height="1.1em" name="file-earmark-arrow-up"></i-bs><span class="ms-2 d-sm-none d-md-inline" i18n>Upload</span>
|
||||
</button>
|
||||
@if (uploadsInProgress > 0) {
|
||||
<button class="btn btn-sm header-upload border-0 d-flex align-items-center py-0 px-2" type="button"
|
||||
(click)="showUploadStatus()" aria-label="Show document processing status" i18n-aria-label>
|
||||
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span><span class="ms-2 small">{{ uploadsInProgress }}</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul ngbNav class="order-sm-3">
|
||||
|
||||
@@ -552,9 +552,22 @@ main {
|
||||
--bs-btn-active-bg: rgba(255, 255, 255, .3);
|
||||
color: var(--pngx-primary-text-contrast) !important; // .navbar .dropdown > .btn in styles.scss
|
||||
|
||||
&:not(:focus) {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, .35), 0 1px 1px rgba(0, 0, 0, .2); // leave room for the .btn:focus ring
|
||||
& + & {
|
||||
border-left: 1px solid rgba(255, 255, 255, .2) !important;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .5);
|
||||
}
|
||||
}
|
||||
|
||||
.header-upload-group {
|
||||
border-radius: var(--bs-border-radius-sm);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, .35), 0 1px 1px rgba(0, 0, 0, .2);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 575.98px) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from '@angular/common/http/testing'
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { BrowserModule } from '@angular/platform-browser'
|
||||
import { BrowserModule, By } from '@angular/platform-browser'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import { NgbModal, NgbModalModule, NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
@@ -34,8 +34,10 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { TasksService } from 'src/app/services/tasks.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { UploadDocumentsService } from 'src/app/services/upload-documents.service'
|
||||
import { WebsocketStatusService } from 'src/app/services/websocket-status.service'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { ProfileEditDialogComponent } from '../common/profile-edit-dialog/profile-edit-dialog.component'
|
||||
import { UploadStatusTrayComponent } from '../common/upload-status-tray/upload-status-tray.component'
|
||||
import { DocumentDetailComponent } from '../document-detail/document-detail.component'
|
||||
import { AppFrameComponent } from './app-frame.component'
|
||||
import { GlobalSearchComponent } from './global-search/global-search.component'
|
||||
@@ -474,10 +476,26 @@ describe('AppFrameComponent', () => {
|
||||
jest.spyOn(input, 'files', 'get').mockReturnValue([file] as any)
|
||||
|
||||
component.onFileSelected({ target: input } as unknown as Event)
|
||||
expect(toastSpy).toHaveBeenCalled()
|
||||
expect(toastSpy).not.toHaveBeenCalled()
|
||||
expect(uploadSpy).toHaveBeenCalledWith([file])
|
||||
})
|
||||
|
||||
it('should show in-progress uploads and expand the status tray', () => {
|
||||
const websocketStatusService = TestBed.inject(WebsocketStatusService)
|
||||
expect(component.uploadsInProgress).toEqual(0)
|
||||
websocketStatusService.newFileUpload('file.pdf')
|
||||
expect(component.uploadsInProgress).toEqual(1)
|
||||
|
||||
fixture.detectChanges()
|
||||
const tray = fixture.debugElement.query(
|
||||
By.directive(UploadStatusTrayComponent)
|
||||
).componentInstance as UploadStatusTrayComponent
|
||||
tray.toggleCollapsed()
|
||||
expect(tray.collapsed()).toBe(true)
|
||||
component.showUploadStatus()
|
||||
expect(tray.collapsed()).toBe(false)
|
||||
})
|
||||
|
||||
it('should not upload when no files are selected from the navbar', () => {
|
||||
const uploadDocumentsService = TestBed.inject(UploadDocumentsService)
|
||||
const uploadSpy = jest.spyOn(uploadDocumentsService, 'uploadFiles')
|
||||
|
||||
@@ -6,7 +6,14 @@ import {
|
||||
moveItemInArray,
|
||||
} from '@angular/cdk/drag-drop'
|
||||
import { NgClass } from '@angular/common'
|
||||
import { Component, HostListener, inject, OnInit, signal } from '@angular/core'
|
||||
import {
|
||||
Component,
|
||||
HostListener,
|
||||
inject,
|
||||
OnInit,
|
||||
signal,
|
||||
viewChild,
|
||||
} from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router'
|
||||
import {
|
||||
@@ -49,6 +56,7 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { TasksService } from 'src/app/services/tasks.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { UploadDocumentsService } from 'src/app/services/upload-documents.service'
|
||||
import { WebsocketStatusService } from 'src/app/services/websocket-status.service'
|
||||
import { environment } from 'src/environments/environment'
|
||||
import { ChatComponent } from '../chat/chat/chat.component'
|
||||
import { SwitchComponent } from '../common/input/switch/switch.component'
|
||||
@@ -105,6 +113,9 @@ export class AppFrameComponent
|
||||
permissionsService = inject(PermissionsService)
|
||||
private djangoMessagesService = inject(DjangoMessagesService)
|
||||
private uploadDocumentsService = inject(UploadDocumentsService)
|
||||
private websocketStatusService = inject(WebsocketStatusService)
|
||||
|
||||
private readonly uploadStatusTray = viewChild(UploadStatusTrayComponent)
|
||||
|
||||
readonly appRemoteVersion = signal<AppRemoteVersion>(null)
|
||||
readonly isMenuCollapsed = signal(true)
|
||||
@@ -522,10 +533,17 @@ export class AppFrameComponent
|
||||
const files = Array.from(input.files ?? [])
|
||||
input.value = ''
|
||||
if (!files.length) return
|
||||
this.toastService.showInfo($localize`Initiating upload...`, 3000)
|
||||
this.uploadDocumentsService.uploadFiles(files)
|
||||
}
|
||||
|
||||
get uploadsInProgress(): number {
|
||||
return this.websocketStatusService.getConsumerStatusNotCompleted().length
|
||||
}
|
||||
|
||||
showUploadStatus() {
|
||||
this.uploadStatusTray()?.expand()
|
||||
}
|
||||
|
||||
onLogout() {
|
||||
this.openDocumentsService.closeAll()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user