-
-
{uploadStatus.length, plural, =1 {Uploading file...} =other {Uploading {{uploadStatus.length}} files...}}
-
0">
-
+
0">{{getStatusSummary()}}
+
+
+
+
+
+ {getStatusHidden().length, plural, =1 {One more document} other {{{getStatusHidden().length}} more documents}}
+ •
+ Show all
+
+
-
\ No newline at end of file
+
+
+
+
+ {{status.filename}}
+ {{status.message}}
+
+
+
+ Open document
+
+
+
+
+
+
+
diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss
index e69de29bb..c13a7bd47 100644
--- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss
+++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.scss
@@ -0,0 +1,35 @@
+@import "/src/theme";
+
+form {
+ position: relative;
+}
+
+.alert-heading {
+ font-size: 80%;
+ font-weight: bold;
+}
+
+.alerts-hidden {
+ .btn {
+ line-height: 1;
+ }
+}
+
+.btn-open {
+ line-height: 1;
+
+ svg {
+ margin-top: -1px;
+ }
+}
+
+.progress {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: auto;
+ mix-blend-mode: soft-light;
+ pointer-events: none;
+}
diff --git a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts
index 2b14a571a..e74e2bc41 100644
--- a/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts
+++ b/src-ui/src/app/components/dashboard/widgets/upload-file-widget/upload-file-widget.component.ts
@@ -1,14 +1,10 @@
import { HttpEventType } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop';
+import { ConsumerStatusService, FileStatus, FileStatusPhase } from 'src/app/services/consumer-status.service';
import { DocumentService } from 'src/app/services/rest/document.service';
-import { ToastService } from 'src/app/services/toast.service';
-
-interface UploadStatus {
- loaded: number
- total: number
-}
+const MAX_ALERTS = 5
@Component({
selector: 'app-upload-file-widget',
@@ -16,8 +12,89 @@ interface UploadStatus {
styleUrls: ['./upload-file-widget.component.scss']
})
export class UploadFileWidgetComponent implements OnInit {
+ alertsExpanded = false
- constructor(private documentService: DocumentService, private toastService: ToastService) { }
+ constructor(
+ private documentService: DocumentService,
+ private consumerStatusService: ConsumerStatusService
+ ) { }
+
+ getStatus() {
+ return this.consumerStatusService.getConsumerStatus().slice(0, MAX_ALERTS)
+ }
+
+ getStatusSummary() {
+ let strings = []
+ let countUploadingAndProcessing = this.consumerStatusService.getConsumerStatusNotCompleted().length
+ let countFailed = this.getStatusFailed().length
+ let countSuccess = this.getStatusSuccess().length
+ if (countUploadingAndProcessing > 0) {
+ strings.push($localize`Processing: ${countUploadingAndProcessing}`)
+ }
+ if (countFailed > 0) {
+ strings.push($localize`Failed: ${countFailed}`)
+ }
+ if (countSuccess > 0) {
+ strings.push($localize`Added: ${countSuccess}`)
+ }
+ return strings.join($localize`:this string is used to separate processing, failed and added on the file upload widget:, `)
+ }
+
+ getStatusHidden() {
+ if (this.consumerStatusService.getConsumerStatus().length < MAX_ALERTS) return []
+ else return this.consumerStatusService.getConsumerStatus().slice(MAX_ALERTS)
+ }
+
+ getStatusUploading() {
+ return this.consumerStatusService.getConsumerStatus(FileStatusPhase.UPLOADING)
+ }
+
+ getStatusFailed() {
+ return this.consumerStatusService.getConsumerStatus(FileStatusPhase.FAILED)
+ }
+
+ getStatusSuccess() {
+ return this.consumerStatusService.getConsumerStatus(FileStatusPhase.SUCCESS)
+ }
+
+ getStatusCompleted() {
+ return this.consumerStatusService.getConsumerStatusCompleted()
+ }
+ getTotalUploadProgress() {
+ let current = 0
+ let max = 0
+
+ this.getStatusUploading().forEach(status => {
+ current += status.currentPhaseProgress
+ max += status.currentPhaseMaxProgress
+ })
+
+ return current / Math.max(max, 1)
+ }
+
+ isFinished(status: FileStatus) {
+ return status.phase == FileStatusPhase.FAILED || status.phase == FileStatusPhase.SUCCESS
+ }
+
+ getStatusColor(status: FileStatus) {
+ switch (status.phase) {
+ case FileStatusPhase.PROCESSING:
+ case FileStatusPhase.UPLOADING:
+ return "primary"
+ case FileStatusPhase.FAILED:
+ return "danger"
+ case FileStatusPhase.SUCCESS:
+ return "success"
+ }
+ }
+
+ dismiss(status: FileStatus) {
+ this.consumerStatusService.dismiss(status)
+ }
+
+ dismissCompleted() {
+ this.consumerStatusService.dismissCompleted()
+ }
ngOnInit(): void {
}
@@ -28,54 +105,39 @@ export class UploadFileWidgetComponent implements OnInit {
public fileLeave(event){
}
- uploadStatus: UploadStatus[] = []
- completedFiles = 0
-
- uploadVisible = false
-
- get loadedSum() {
- return this.uploadStatus.map(s => s.loaded).reduce((a,b) => a+b, this.completedFiles > 0 ? 1 : 0)
- }
-
- get totalSum() {
- return this.uploadStatus.map(s => s.total).reduce((a,b) => a+b, 1)
- }
-
public dropped(files: NgxFileDropEntry[]) {
for (const droppedFile of files) {
if (droppedFile.fileEntry.isFile) {
- let uploadStatusObject: UploadStatus = {loaded: 0, total: 1}
- this.uploadStatus.push(uploadStatusObject)
- this.uploadVisible = true
const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
fileEntry.file((file: File) => {
let formData = new FormData()
formData.append('document', file, file.name)
+ let status = this.consumerStatusService.newFileUpload(file.name)
+
+ status.message = $localize`Connecting...`
this.documentService.uploadDocument(formData).subscribe(event => {
if (event.type == HttpEventType.UploadProgress) {
- uploadStatusObject.loaded = event.loaded
- uploadStatusObject.total = event.total
+ status.updateProgress(FileStatusPhase.UPLOADING, event.loaded, event.total)
+ status.message = $localize`Uploading...`
} else if (event.type == HttpEventType.Response) {
- this.uploadStatus.splice(this.uploadStatus.indexOf(uploadStatusObject), 1)
- this.completedFiles += 1
- this.toastService.showInfo($localize`The document has been uploaded and will be processed by the consumer shortly.`)
+ status.taskId = event.body["task_id"]
+ status.message = $localize`Upload complete, waiting...`
}
-
+
}, error => {
- this.uploadStatus.splice(this.uploadStatus.indexOf(uploadStatusObject), 1)
- this.completedFiles += 1
switch (error.status) {
case 400: {
- this.toastService.showInfo($localize`There was an error while uploading the document: ${error.error.document}`)
+ this.consumerStatusService.fail(status, error.error.document)
break;
}
default: {
- this.toastService.showInfo($localize`An error has occurred while uploading the document. Sorry!`)
+ this.consumerStatusService.fail(status, $localize`HTTP error: ${error.status} ${error.statusText}`)
break;
}
}
+
})
});
}
diff --git a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html
index 6320189cc..17c7ffe1e 100644
--- a/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html
+++ b/src-ui/src/app/components/dashboard/widgets/welcome-widget/welcome-widget.component.html
@@ -13,4 +13,4 @@
Consult the documentation on how to use these features. The section on basic usage also has some information on how to use paperless in general.
-
\ No newline at end of file
+
diff --git a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html
index 1d7d2d906..1cd440306 100644
--- a/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html
+++ b/src-ui/src/app/components/dashboard/widgets/widget-frame/widget-frame.component.html
@@ -4,9 +4,9 @@
{{title}}
-
+