mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
Merge branch 'dev' into feature/unsaved-changes
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
<div class="modal-body">
|
||||
<app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text>
|
||||
<app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
|
||||
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive" novalidate></app-input-check>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@@ -32,6 +32,6 @@ export class CorrespondentEditDialogComponent extends EditDialogComponent<Paperl
|
||||
match: new FormControl(""),
|
||||
is_insensitive: new FormControl(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ export class CorrespondentListComponent extends GenericListComponent<PaperlessCo
|
||||
constructor(correspondentsService: CorrespondentService, modalService: NgbModal,
|
||||
private list: DocumentListViewService,
|
||||
toastService: ToastService
|
||||
) {
|
||||
) {
|
||||
super(correspondentsService,modalService,CorrespondentEditDialogComponent, toastService)
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
<app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text>
|
||||
<app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
|
||||
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
|
||||
|
||||
</div>
|
||||
|
@@ -13,7 +13,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
})
|
||||
export class DocumentTypeEditDialogComponent extends EditDialogComponent<PaperlessDocumentType> {
|
||||
|
||||
constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) {
|
||||
constructor(service: DocumentTypeService, activeModal: NgbActiveModal, toastService: ToastService) {
|
||||
super(service, activeModal, toastService)
|
||||
}
|
||||
|
||||
|
@@ -49,4 +49,4 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
@@ -1,27 +1,18 @@
|
||||
<app-page-header title="Logs" i18n-title>
|
||||
|
||||
<div ngbDropdown class="btn-group">
|
||||
<button class="btn btn-outline-primary btn-sm" id="dropdownBasic1" ngbDropdownToggle>
|
||||
<svg class="toolbaricon" fill="currentColor">
|
||||
<use xlink:href="assets/bootstrap-icons.svg#funnel" />
|
||||
</svg> <ng-container i18n>Filter</ng-container>
|
||||
|
||||
|
||||
</button>
|
||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||
<button *ngFor="let f of getLevels()" ngbDropdownItem (click)="setLevel(f.id)"
|
||||
[class.active]="level == f.id">{{f.name}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</app-page-header>
|
||||
|
||||
<div class="bg-dark p-3 mb-3 text-light text-monospace" infiniteScroll (scrolled)="onScroll()">
|
||||
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="activeLog" (activeIdChange)="reloadLogs()" class="nav-tabs">
|
||||
<li *ngFor="let logFile of logFiles" [ngbNavItem]="logFile">
|
||||
<a ngbNavLink>{{logFile}}.log</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
|
||||
<div class="bg-dark p-3 text-light text-monospace log-container" #logContainer>
|
||||
<p
|
||||
class="m-0 p-0 log-entry-{{log.level}}"
|
||||
*ngFor="let log of logs">
|
||||
{{log.created | customDate:'short'}}
|
||||
{{getLevelText(log.level)}}
|
||||
{{log.message}}
|
||||
</p>
|
||||
class="m-0 p-0 log-entry-{{getLogLevel(log)}}"
|
||||
*ngFor="let log of logs">{{log}}</p>
|
||||
</div>
|
||||
|
@@ -13,4 +13,14 @@
|
||||
.log-entry-50 {
|
||||
color: lightcoral !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.log-container {
|
||||
overflow-y: scroll;
|
||||
height: calc(100vh - 200px);
|
||||
top: 70px;
|
||||
|
||||
p {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { LOG_LEVELS, LOG_LEVEL_INFO, PaperlessLog } from 'src/app/data/paperless-log';
|
||||
import { Component, ElementRef, OnInit, AfterViewChecked, ViewChild } from '@angular/core';
|
||||
import { LogService } from 'src/app/services/rest/log.service';
|
||||
|
||||
@Component({
|
||||
@@ -7,42 +6,60 @@ import { LogService } from 'src/app/services/rest/log.service';
|
||||
templateUrl: './logs.component.html',
|
||||
styleUrls: ['./logs.component.scss']
|
||||
})
|
||||
export class LogsComponent implements OnInit {
|
||||
export class LogsComponent implements OnInit, AfterViewChecked {
|
||||
|
||||
constructor(private logService: LogService) { }
|
||||
|
||||
logs: PaperlessLog[] = []
|
||||
level: number = LOG_LEVEL_INFO
|
||||
logs: string[] = []
|
||||
|
||||
logFiles: string[] = []
|
||||
|
||||
activeLog: string
|
||||
|
||||
@ViewChild('logContainer') logContainer: ElementRef
|
||||
|
||||
ngOnInit(): void {
|
||||
this.reload()
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.logService.list(1, 50, 'created', true, {'level__gte': this.level}).subscribe(result => this.logs = result.results)
|
||||
}
|
||||
|
||||
getLevelText(level: number) {
|
||||
return LOG_LEVELS.find(l => l.id == level)?.name
|
||||
}
|
||||
|
||||
onScroll() {
|
||||
let lastCreated = null
|
||||
if (this.logs.length > 0) {
|
||||
lastCreated = new Date(this.logs[this.logs.length-1].created).toISOString()
|
||||
}
|
||||
this.logService.list(1, 25, 'created', true, {'created__lt': lastCreated, 'level__gte': this.level}).subscribe(result => {
|
||||
this.logs.push(...result.results)
|
||||
this.logService.list().subscribe(result => {
|
||||
this.logFiles = result
|
||||
if (this.logFiles.length > 0) {
|
||||
this.activeLog = this.logFiles[0]
|
||||
this.reloadLogs()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getLevels() {
|
||||
return LOG_LEVELS
|
||||
ngAfterViewChecked() {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
setLevel(id) {
|
||||
this.level = id
|
||||
this.reload()
|
||||
reloadLogs() {
|
||||
this.logService.get(this.activeLog).subscribe(result => {
|
||||
this.logs = result
|
||||
}, error => {
|
||||
this.logs = []
|
||||
})
|
||||
}
|
||||
|
||||
getLogLevel(log: string) {
|
||||
if (log.indexOf("[DEBUG]") != -1) {
|
||||
return 10
|
||||
} else if (log.indexOf("[WARNING]") != -1) {
|
||||
return 30
|
||||
} else if (log.indexOf("[ERROR]") != -1) {
|
||||
return 40
|
||||
} else if (log.indexOf("[CRITICAL]") != -1) {
|
||||
return 50
|
||||
} else {
|
||||
return 20
|
||||
}
|
||||
}
|
||||
|
||||
scrollToBottom(): void {
|
||||
this.logContainer?.nativeElement.scroll({
|
||||
top: this.logContainer.nativeElement.scrollHeight,
|
||||
left: 0,
|
||||
behavior: 'auto'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@
|
||||
<div class="col">
|
||||
|
||||
<select class="form-control" formControlName="dateLocale">
|
||||
<option *ngFor="let lang of dateLocaleOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> - {{today | date:'shortDate':null:lang.code}}</span></option>
|
||||
<option *ngFor="let lang of dateLocaleOptions" [ngValue]="lang.code">{{lang.name}}<span *ngIf="lang.code"> - {{today | customDate:'shortDate':null:lang.code}}</span></option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
@@ -96,6 +96,7 @@
|
||||
<div class="col">
|
||||
<app-input-check i18n-title title="Use system settings" formControlName="darkModeUseSystem"></app-input-check>
|
||||
<app-input-check [hidden]="settingsForm.value.darkModeUseSystem" i18n-title title="Enable dark mode" formControlName="darkModeEnabled"></app-input-check>
|
||||
<app-input-check i18n-title title="Invert thumbnails in dark mode" formControlName="darkModeInvertThumbs"></app-input-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -110,7 +111,26 @@
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="2">
|
||||
<a ngbNavLink i18n>Notifications</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<h4 i18n>Document processing</h4>
|
||||
|
||||
<div class="form-row form-group">
|
||||
<div class="offset-md-3 col">
|
||||
<app-input-check i18n-title title="Show notifications when new documents are detected" formControlName="notificationsConsumerNewDocument"></app-input-check>
|
||||
<app-input-check i18n-title title="Show notifications when document processing completes successfully" formControlName="notificationsConsumerSuccess"></app-input-check>
|
||||
<app-input-check i18n-title title="Show notifications when document processing fails" formControlName="notificationsConsumerFailed"></app-input-check>
|
||||
<app-input-check i18n-title title="Suppress notifications on dashboard" formControlName="notificationsConsumerSuppressOnDashboard" i18n-hint hint="This will suppress all messages about document processing status on the dashboard."></app-input-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="3">
|
||||
<a ngbNavLink i18n>Saved views</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
@@ -148,7 +168,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3 shadow"></div>
|
||||
<div [ngbNavOutlet]="nav" class="border-left border-right border-bottom p-3 mb-3 shadow-sm"></div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" [disabled]="!(isDirty$ | async)" i18n>Save</button>
|
||||
</form>
|
||||
|
@@ -28,6 +28,10 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
'displayLanguage': new FormControl(null),
|
||||
'dateLocale': new FormControl(null),
|
||||
'dateFormat': new FormControl(null),
|
||||
'notificationsConsumerNewDocument': new FormControl(null),
|
||||
'notificationsConsumerSuccess': new FormControl(null),
|
||||
'notificationsConsumerFailed': new FormControl(null),
|
||||
'notificationsConsumerSuppressOnDashboard': new FormControl(null),
|
||||
})
|
||||
|
||||
savedViews: PaperlessSavedView[]
|
||||
@@ -37,7 +41,7 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
isDirty$: Observable<boolean>
|
||||
|
||||
get computedDateLocale(): string {
|
||||
return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage
|
||||
return this.settingsForm.value.dateLocale || this.settingsForm.value.displayLanguage || this.currentLocale
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -62,6 +66,10 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
'displayLanguage': this.settings.getLanguage(),
|
||||
'dateLocale': this.settings.get(SETTINGS_KEYS.DATE_LOCALE),
|
||||
'dateFormat': this.settings.get(SETTINGS_KEYS.DATE_FORMAT),
|
||||
'notificationsConsumerNewDocument': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT),
|
||||
'notificationsConsumerSuccess': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS),
|
||||
'notificationsConsumerFailed': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED),
|
||||
'notificationsConsumerSuppressOnDashboard': this.settings.get(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD),
|
||||
}
|
||||
|
||||
for (let view of this.savedViews) {
|
||||
@@ -108,9 +116,14 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
this.settings.set(SETTINGS_KEYS.DOCUMENT_LIST_SIZE, this.settingsForm.value.documentListItemPerPage)
|
||||
this.settings.set(SETTINGS_KEYS.DARK_MODE_USE_SYSTEM, this.settingsForm.value.darkModeUseSystem)
|
||||
this.settings.set(SETTINGS_KEYS.DARK_MODE_ENABLED, (this.settingsForm.value.darkModeEnabled == true).toString())
|
||||
this.settings.set(SETTINGS_KEYS.DARK_MODE_THUMB_INVERTED, (this.settingsForm.value.darkModeInvertThumbs == true).toString())
|
||||
this.settings.set(SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER, this.settingsForm.value.useNativePdfViewer)
|
||||
this.settings.set(SETTINGS_KEYS.DATE_LOCALE, this.settingsForm.value.dateLocale)
|
||||
this.settings.set(SETTINGS_KEYS.DATE_FORMAT, this.settingsForm.value.dateFormat)
|
||||
this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT, this.settingsForm.value.notificationsConsumerNewDocument)
|
||||
this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUCCESS, this.settingsForm.value.notificationsConsumerSuccess)
|
||||
this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_FAILED, this.settingsForm.value.notificationsConsumerFailed)
|
||||
this.settings.set(SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD, this.settingsForm.value.notificationsConsumerSuppressOnDashboard)
|
||||
this.settings.setLanguage(this.settingsForm.value.displayLanguage)
|
||||
this.store.next(this.settingsForm.value)
|
||||
this.documentListViewService.updatePageSize()
|
||||
@@ -119,11 +132,15 @@ export class SettingsComponent implements OnInit, OnDestroy, DirtyComponent {
|
||||
}
|
||||
|
||||
get displayLanguageOptions(): LanguageOption[] {
|
||||
return [{code: "", name: $localize`Use system language`}].concat(this.settings.getLanguageOptions())
|
||||
return [
|
||||
{code: "", name: $localize`Use system language`}
|
||||
].concat(this.settings.getLanguageOptions())
|
||||
}
|
||||
|
||||
get dateLocaleOptions(): LanguageOption[] {
|
||||
return [{code: "", name: $localize`Use date format of display language`}].concat(this.settings.getLanguageOptions())
|
||||
return [
|
||||
{code: "", name: $localize`Use date format of display language`}
|
||||
].concat(this.settings.getDateLocaleOptions())
|
||||
}
|
||||
|
||||
get today() {
|
||||
|
@@ -8,19 +8,11 @@
|
||||
<div class="modal-body">
|
||||
<app-input-text i18n-title title="Name" formControlName="name" [error]="error?.name"></app-input-text>
|
||||
|
||||
|
||||
<div class="form-group paperless-input-select">
|
||||
<label for="colour" i18n>Color</label>
|
||||
<ng-select name="colour" formControlName="colour" [items]="getColours()" bindValue="id" bindLabel="name" [clearable]="false">
|
||||
<ng-template ng-option-tmp ng-label-tmp let-item="item">
|
||||
<span class="badge" [style.background]="item.value" [style.color]="item.textColor">{{item.name}}</span>
|
||||
</ng-template>
|
||||
</ng-select>
|
||||
</div>
|
||||
<app-input-color i18n-title title="Color" formControlName="color" [error]="error?.color"></app-input-color>
|
||||
|
||||
<app-input-check i18n-title title="Inbox tag" formControlName="is_inbox_tag" i18n-hint hint="Inbox tags are automatically assigned to all consumed documents."></app-input-check>
|
||||
<app-input-select i18n-title title="Matching algorithm" [items]="getMatchingAlgorithms()" formControlName="matching_algorithm"></app-input-select>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match"></app-input-text>
|
||||
<app-input-text *ngIf="patternRequired" i18n-title title="Matching pattern" formControlName="match" [error]="error?.match"></app-input-text>
|
||||
<app-input-check *ngIf="patternRequired" i18n-title title="Case insensitive" formControlName="is_insensitive"></app-input-check>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@@ -2,9 +2,10 @@ import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { EditDialogComponent } from 'src/app/components/common/edit-dialog/edit-dialog.component';
|
||||
import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { TagService } from 'src/app/services/rest/tag.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { randomColor } from 'src/app/utils/color';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tag-edit-dialog',
|
||||
@@ -13,7 +14,7 @@ import { ToastService } from 'src/app/services/toast.service';
|
||||
})
|
||||
export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
|
||||
|
||||
constructor(service: TagService, activeModal: NgbActiveModal, toastService: ToastService) {
|
||||
constructor(service: TagService, activeModal: NgbActiveModal, toastService: ToastService) {
|
||||
super(service, activeModal, toastService)
|
||||
}
|
||||
|
||||
@@ -28,7 +29,7 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
|
||||
getForm(): FormGroup {
|
||||
return new FormGroup({
|
||||
name: new FormControl(''),
|
||||
colour: new FormControl(1),
|
||||
color: new FormControl(randomColor()),
|
||||
is_inbox_tag: new FormControl(false),
|
||||
matching_algorithm: new FormControl(1),
|
||||
match: new FormControl(""),
|
||||
@@ -36,12 +37,4 @@ export class TagEditDialogComponent extends EditDialogComponent<PaperlessTag> {
|
||||
})
|
||||
}
|
||||
|
||||
getColours() {
|
||||
return TAG_COLOURS
|
||||
}
|
||||
|
||||
getColor(id: number) {
|
||||
return TAG_COLOURS.find(c => c.id == id)
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -26,8 +26,8 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let tag of data">
|
||||
<td scope="row">{{ tag.name }}</td>
|
||||
<td scope="row"><span class="badge" [style.color]="getColor(tag.colour).textColor"
|
||||
[style.background-color]="getColor(tag.colour).value">{{ getColor(tag.colour).name }}</span></td>
|
||||
<td scope="row"><span class="badge" [style.color]="tag.text_color"
|
||||
[style.background-color]="tag.color">{{tag.color}}</span></td>
|
||||
<td scope="row">{{ getMatching(tag) }}</td>
|
||||
<td scope="row">{{ tag.document_count }}</td>
|
||||
<td scope="row">
|
||||
@@ -52,4 +52,4 @@
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { FILTER_HAS_TAG } from 'src/app/data/filter-rule-type';
|
||||
import { TAG_COLOURS, PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service';
|
||||
import { TagService } from 'src/app/services/rest/tag.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
@@ -22,10 +22,6 @@ export class TagListComponent extends GenericListComponent<PaperlessTag> {
|
||||
super(tagService, modalService, TagEditDialogComponent, toastService)
|
||||
}
|
||||
|
||||
getColor(id) {
|
||||
return TAG_COLOURS.find(c => c.id == id)
|
||||
}
|
||||
|
||||
getDeleteMessage(object: PaperlessTag) {
|
||||
return $localize`Do you really want to delete the tag "${object.name}"?`
|
||||
}
|
||||
|
Reference in New Issue
Block a user