mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Feature: loading preview, better text popup preview (#8011)
This commit is contained in:
@@ -5,7 +5,11 @@
|
||||
</div>
|
||||
} @else {
|
||||
@if (renderAsObject) {
|
||||
<object [data]="previewURL | safeUrl" width="100%" class="bg-light" [class.p-2]="!isPdf" [class.pdf]="isPdf"></object>
|
||||
@if (previewText) {
|
||||
<div class="bg-light p-3 overflow-auto whitespace-preserve" width="100%">{{previewText}}</div>
|
||||
} @else {
|
||||
<object [data]="previewURL | safeUrl" width="100%" class="bg-light" [class.p-2]="!isPdf"></object>
|
||||
}
|
||||
} @else {
|
||||
@if (requiresPassword) {
|
||||
<div class="w-100 h-100 position-relative">
|
||||
|
@@ -7,33 +7,3 @@
|
||||
::ng-deep .popover.popover-preview {
|
||||
max-width: 32rem;
|
||||
}
|
||||
|
||||
// https://github.com/paperless-ngx/paperless-ngx/issues/7920
|
||||
// TODO: remove me
|
||||
@mixin ff_txt {
|
||||
.preview-popup-container {
|
||||
width: 30rem !important;
|
||||
height: 22rem !important;
|
||||
background-color: #e7e7e7;
|
||||
}
|
||||
|
||||
object:not(.pdf) {
|
||||
mix-blend-mode: difference;
|
||||
background: white !important;
|
||||
&.p-2 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
html[data-bs-theme='dark'] {
|
||||
@include ff_txt;
|
||||
}
|
||||
html[data-bs-theme='auto'] {
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
@include ff_txt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,13 +9,20 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||
import { PdfViewerModule } from 'ng2-pdf-viewer'
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
||||
import {
|
||||
HttpClient,
|
||||
provideHttpClient,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http'
|
||||
import { of, throwError } from 'rxjs'
|
||||
|
||||
const doc = {
|
||||
id: 10,
|
||||
title: 'Document 10',
|
||||
content: 'Cupcake ipsum dolor sit amet ice cream.',
|
||||
original_file_name: 'sample.pdf',
|
||||
archived_file_name: 'sample.pdf',
|
||||
mime_type: 'application/pdf',
|
||||
}
|
||||
|
||||
describe('PreviewPopupComponent', () => {
|
||||
@@ -23,6 +30,7 @@ describe('PreviewPopupComponent', () => {
|
||||
let fixture: ComponentFixture<PreviewPopupComponent>
|
||||
let settingsService: SettingsService
|
||||
let documentService: DocumentService
|
||||
let http: HttpClient
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -35,23 +43,22 @@ describe('PreviewPopupComponent', () => {
|
||||
})
|
||||
settingsService = TestBed.inject(SettingsService)
|
||||
documentService = TestBed.inject(DocumentService)
|
||||
http = TestBed.inject(HttpClient)
|
||||
jest
|
||||
.spyOn(documentService, 'getPreviewUrl')
|
||||
.mockImplementation((id) => doc.original_file_name)
|
||||
fixture = TestBed.createComponent(PreviewPopupComponent)
|
||||
component = fixture.componentInstance
|
||||
component.document = doc
|
||||
component.document = { ...doc }
|
||||
fixture.detectChanges()
|
||||
})
|
||||
|
||||
it('should guess if file is pdf by file name', () => {
|
||||
expect(component.isPdf).toBeTruthy()
|
||||
component.document.archived_file_name = 'sample.pdf'
|
||||
it('should correctly report if document is pdf', () => {
|
||||
expect(component.isPdf).toBeTruthy()
|
||||
component.document.mime_type = 'application/msword'
|
||||
expect(component.isPdf).toBeTruthy() // still has archive file
|
||||
component.document.archived_file_name = undefined
|
||||
component.document.original_file_name = 'sample.txt'
|
||||
expect(component.isPdf).toBeFalsy()
|
||||
component.document.original_file_name = 'sample.pdf'
|
||||
})
|
||||
|
||||
it('should return settings for native PDF viewer', () => {
|
||||
@@ -84,6 +91,8 @@ describe('PreviewPopupComponent', () => {
|
||||
|
||||
it('should fall back to object for non-pdf', () => {
|
||||
component.document.original_file_name = 'sample.png'
|
||||
component.document.mime_type = 'image/png'
|
||||
component.document.archived_file_name = undefined
|
||||
fixture.detectChanges()
|
||||
expect(fixture.debugElement.query(By.css('object'))).not.toBeNull()
|
||||
})
|
||||
@@ -95,4 +104,22 @@ describe('PreviewPopupComponent', () => {
|
||||
'Error loading preview'
|
||||
)
|
||||
})
|
||||
|
||||
it('should get text content from http if appropriate', () => {
|
||||
component.document = {
|
||||
...doc,
|
||||
original_file_name: 'sample.txt',
|
||||
mime_type: 'text/plain',
|
||||
}
|
||||
const httpSpy = jest.spyOn(http, 'get')
|
||||
httpSpy.mockReturnValueOnce(
|
||||
throwError(() => new Error('Error getting preview'))
|
||||
)
|
||||
component.init()
|
||||
expect(httpSpy).toHaveBeenCalled()
|
||||
expect(component.error).toBeTruthy()
|
||||
httpSpy.mockReturnValueOnce(of('Preview text'))
|
||||
component.init()
|
||||
expect(component.previewText).toEqual('Preview text')
|
||||
})
|
||||
})
|
||||
|
@@ -1,4 +1,6 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { Component, Input, OnDestroy } from '@angular/core'
|
||||
import { first, Subject, takeUntil } from 'rxjs'
|
||||
import { Document } from 'src/app/data/document'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
@@ -9,14 +11,26 @@ import { SettingsService } from 'src/app/services/settings.service'
|
||||
templateUrl: './preview-popup.component.html',
|
||||
styleUrls: ['./preview-popup.component.scss'],
|
||||
})
|
||||
export class PreviewPopupComponent {
|
||||
export class PreviewPopupComponent implements OnDestroy {
|
||||
private _document: Document
|
||||
@Input()
|
||||
document: Document
|
||||
set document(document: Document) {
|
||||
this._document = document
|
||||
this.init()
|
||||
}
|
||||
|
||||
get document(): Document {
|
||||
return this._document
|
||||
}
|
||||
|
||||
unsubscribeNotifier: Subject<any> = new Subject()
|
||||
|
||||
error = false
|
||||
|
||||
requiresPassword: boolean = false
|
||||
|
||||
previewText: string
|
||||
|
||||
get renderAsObject(): boolean {
|
||||
return (this.isPdf && this.useNativePdfViewer) || !this.isPdf
|
||||
}
|
||||
@@ -30,18 +44,38 @@ export class PreviewPopupComponent {
|
||||
}
|
||||
|
||||
get isPdf(): boolean {
|
||||
// We dont have time to retrieve metadata, make a best guess by file name
|
||||
return (
|
||||
this.document?.original_file_name?.endsWith('.pdf') ||
|
||||
this.document?.archived_file_name?.endsWith('.pdf')
|
||||
this.document?.archived_file_name?.length > 0 ||
|
||||
this.document?.mime_type?.includes('pdf')
|
||||
)
|
||||
}
|
||||
|
||||
constructor(
|
||||
private settingsService: SettingsService,
|
||||
private documentService: DocumentService
|
||||
private documentService: DocumentService,
|
||||
private http: HttpClient
|
||||
) {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeNotifier.next(this)
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.document.mime_type?.includes('text')) {
|
||||
this.http
|
||||
.get(this.previewURL, { responseType: 'text' })
|
||||
.pipe(first(), takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe({
|
||||
next: (res) => {
|
||||
this.previewText = res.toString()
|
||||
},
|
||||
error: (err) => {
|
||||
this.error = err
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onError(event: any) {
|
||||
if (event.name == 'PasswordException') {
|
||||
this.requiresPassword = true
|
||||
|
Reference in New Issue
Block a user