Merge branch 'dev' into feature-websockets-status

This commit is contained in:
jonaswinkler
2021-01-23 22:22:17 +01:00
163 changed files with 5843 additions and 2520 deletions

View File

@@ -27,6 +27,8 @@ export class DocumentListViewService {
currentPage = 1
currentPageSize: number = this.settings.get(SETTINGS_KEYS.DOCUMENT_LIST_SIZE)
collectionSize: number
rangeSelectionAnchorIndex: number
lastRangeSelectionToIndex: number
/**
* This is the current config for the document list. The service will always remember the last settings used for the document list.
@@ -108,6 +110,7 @@ export class DocumentListViewService {
if (onFinish) {
onFinish()
}
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
this.isReloading = false
},
error => {
@@ -218,6 +221,7 @@ export class DocumentListViewService {
selectNone() {
this.selected.clear()
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
}
reduceSelectionToFilter() {
@@ -249,14 +253,39 @@ export class DocumentListViewService {
return this.selected.has(d.id)
}
setSelected(d: PaperlessDocument, value: boolean) {
if (value) {
this.selected.add(d.id)
} else if (!value) {
this.selected.delete(d.id)
toggleSelected(d: PaperlessDocument): void {
if (this.selected.has(d.id)) this.selected.delete(d.id)
else this.selected.add(d.id)
this.rangeSelectionAnchorIndex = this.documentIndexInCurrentView(d.id)
this.lastRangeSelectionToIndex = null
}
selectRangeTo(d: PaperlessDocument) {
if (this.rangeSelectionAnchorIndex !== null) {
const documentToIndex = this.documentIndexInCurrentView(d.id)
const fromIndex = Math.min(this.rangeSelectionAnchorIndex, documentToIndex)
const toIndex = Math.max(this.rangeSelectionAnchorIndex, documentToIndex)
if (this.lastRangeSelectionToIndex !== null) {
// revert the old selection
this.documents.slice(Math.min(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex), Math.max(this.rangeSelectionAnchorIndex, this.lastRangeSelectionToIndex) + 1).forEach(d => {
this.selected.delete(d.id)
})
}
this.documents.slice(fromIndex, toIndex + 1).forEach(d => {
this.selected.add(d.id)
})
this.lastRangeSelectionToIndex = documentToIndex
} else { // e.g. shift key but was first click
this.toggleSelected(d)
}
}
documentIndexInCurrentView(documentID: number): number {
return this.documents.map(d => d.id).indexOf(documentID)
}
constructor(private documentService: DocumentService, private settings: SettingsService, private router: Router) {
let documentListViewConfigJson = sessionStorage.getItem(DOCUMENT_LIST_SERVICE.CURRENT_VIEW_CONFIG)
if (documentListViewConfigJson) {

View File

@@ -0,0 +1,14 @@
import { ObjectWithId } from 'src/app/data/object-with-id'
import { AbstractPaperlessService } from './abstract-paperless-service'
export abstract class AbstractNameFilterService<T extends ObjectWithId> extends AbstractPaperlessService<T> {
listFiltered(page?: number, pageSize?: number, sortField?: string, sortReverse?: boolean, nameFilter?: string) {
let params = {}
if (nameFilter) {
params = {'name__icontains': nameFilter}
}
return this.list(page, pageSize, sortField, sortReverse, params)
}
}

View File

@@ -1,12 +1,12 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
import { AbstractPaperlessService } from './abstract-paperless-service';
import { AbstractNameFilterService } from './abstract-name-filter-service';
@Injectable({
providedIn: 'root'
})
export class CorrespondentService extends AbstractPaperlessService<PaperlessCorrespondent> {
export class CorrespondentService extends AbstractNameFilterService<PaperlessCorrespondent> {
constructor(http: HttpClient) {
super(http, 'correspondents')

View File

@@ -1,12 +1,12 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
import { AbstractPaperlessService } from './abstract-paperless-service';
import { AbstractNameFilterService } from './abstract-name-filter-service';
@Injectable({
providedIn: 'root'
})
export class DocumentTypeService extends AbstractPaperlessService<PaperlessDocumentType> {
export class DocumentTypeService extends AbstractNameFilterService<PaperlessDocumentType> {
constructor(http: HttpClient) {
super(http, 'document_types')

View File

@@ -28,7 +28,11 @@ export class SearchService {
}
return this.http.get<SearchResult>(`${environment.apiBaseUrl}search/`, {params: httpParams}).pipe(
map(result => {
result.results.forEach(hit => this.documentService.addObservablesToDocument(hit.document))
result.results.forEach(hit => {
if (hit.document) {
this.documentService.addObservablesToDocument(hit.document)
}
})
return result
})
)

View File

@@ -1,12 +1,12 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { PaperlessTag } from 'src/app/data/paperless-tag';
import { AbstractPaperlessService } from './abstract-paperless-service';
import { AbstractNameFilterService } from './abstract-name-filter-service';
@Injectable({
providedIn: 'root'
})
export class TagService extends AbstractPaperlessService<PaperlessTag> {
export class TagService extends AbstractNameFilterService<PaperlessTag> {
constructor(http: HttpClient) {
super(http, 'tags')

View File

@@ -1,5 +1,7 @@
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable, Renderer2, RendererFactory2 } from '@angular/core';
import { Meta } from '@angular/platform-browser';
import { CookieService } from 'ngx-cookie-service';
export interface PaperlessSettings {
key: string
@@ -7,12 +9,21 @@ export interface PaperlessSettings {
default: any
}
export interface LanguageOption {
code: string,
name: string,
englishName?: string
}
export const SETTINGS_KEYS = {
BULK_EDIT_CONFIRMATION_DIALOGS: 'general-settings:bulk-edit:confirmation-dialogs',
BULK_EDIT_APPLY_ON_CLOSE: 'general-settings:bulk-edit:apply-on-close',
DOCUMENT_LIST_SIZE: 'general-settings:documentListSize',
DARK_MODE_USE_SYSTEM: 'general-settings:dark-mode:use-system',
DARK_MODE_ENABLED: 'general-settings:dark-mode:enabled'
DARK_MODE_ENABLED: 'general-settings:dark-mode:enabled',
USE_NATIVE_PDF_VIEWER: 'general-settings:document-details:native-pdf-viewer',
DATE_LOCALE: 'general-settings:date-display:date-locale',
DATE_FORMAT: 'general-settings:date-display:date-format'
}
const SETTINGS: PaperlessSettings[] = [
@@ -20,7 +31,10 @@ const SETTINGS: PaperlessSettings[] = [
{key: SETTINGS_KEYS.BULK_EDIT_APPLY_ON_CLOSE, type: "boolean", default: false},
{key: SETTINGS_KEYS.DOCUMENT_LIST_SIZE, type: "number", default: 50},
{key: SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, type: "boolean", default: true},
{key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: "boolean", default: false}
{key: SETTINGS_KEYS.DARK_MODE_ENABLED, type: "boolean", default: false},
{key: SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, type: "boolean", default: false},
{key: SETTINGS_KEYS.DATE_LOCALE, type: "string", default: ""},
{key: SETTINGS_KEYS.DATE_FORMAT, type: "string", default: "mediumDate"}
]
@Injectable({
@@ -32,7 +46,9 @@ export class SettingsService {
constructor(
private rendererFactory: RendererFactory2,
@Inject(DOCUMENT) private document
@Inject(DOCUMENT) private document,
private cookieService: CookieService,
private meta: Meta
) {
this.renderer = rendererFactory.createRenderer(null, null);
@@ -53,6 +69,35 @@ export class SettingsService {
}
getLanguageOptions(): LanguageOption[] {
return [
{code: "en-US", name: $localize`English (US)`, englishName: "English (US)"},
{code: "de", name: $localize`German`, englishName: "German"},
{code: "nl", name: $localize`Dutch`, englishName: "Dutch"},
{code: "fr", name: $localize`French`, englishName: "French"}
]
}
private getLanguageCookieName() {
let prefix = ""
if (this.meta.getTag('name=cookie_prefix')) {
prefix = this.meta.getTag('name=cookie_prefix').content
}
return `${prefix || ''}django_language`
}
getLanguage(): string {
return this.cookieService.get(this.getLanguageCookieName())
}
setLanguage(language: string) {
if (language) {
this.cookieService.set(this.getLanguageCookieName(), language)
} else {
this.cookieService.delete(this.getLanguageCookieName())
}
}
get(key: string): any {
let setting = SETTINGS.find(s => s.key == key)