mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-11-15 10:26:42 +00:00
Better info for bulk tasks
This commit is contained in:
3 files changed
+142
-2
No files matched your search
@@ -180,6 +180,11 @@
|
||||
@if (taskShowsSeparateTypeLabel(task)) {
|
||||
<span class="me-2">{{ task.task_type_display }}</span>
|
||||
}
|
||||
@let documentCount = taskDocumentCount(task);
|
||||
@if (documentCount !== null) {
|
||||
<span class="me-2" i18n>{documentCount, plural, =1 {1 document} other {{{ documentCount }} documents}}</span>
|
||||
<span class="me-2" aria-hidden="true">·</span>
|
||||
}
|
||||
<span class="text-nowrap"><pngx-bs-icon class="me-1" width="1em" height="1em" name="box-arrow-in-right"></pngx-bs-icon>{{ task.trigger_source_display }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -895,6 +895,96 @@ describe('TasksComponent', () => {
|
||||
expect(sanityTaskRow.nativeElement.textContent).toContain('System')
|
||||
})
|
||||
|
||||
it.each([
|
||||
['modify_tags', 12, 'Update tags', '12 documents'],
|
||||
['run_workflow', 1, 'Run workflow', '1 document'],
|
||||
['delete', 3, 'Move to trash', '3 documents'],
|
||||
])(
|
||||
'shows the operation, document count and outcome for %s',
|
||||
(operation, count, label, summary) => {
|
||||
const task: PaperlessTask = {
|
||||
...tasks[4],
|
||||
task_type:
|
||||
operation === 'delete'
|
||||
? PaperlessTaskType.BulkDelete
|
||||
: PaperlessTaskType.BulkUpdate,
|
||||
task_type_display:
|
||||
operation === 'delete' ? 'Bulk Delete' : 'Bulk Update',
|
||||
trigger_source: PaperlessTaskTriggerSource.WebUI,
|
||||
trigger_source_display: 'Web UI',
|
||||
input_data: { operation, document_count: count },
|
||||
result_data: { operation, document_count: count },
|
||||
}
|
||||
component.setSection(TaskSection.Completed)
|
||||
flushTaskLists(25, 1, [task])
|
||||
fixture.detectChanges()
|
||||
|
||||
const name = fixture.nativeElement.querySelector('tbody .name-col')
|
||||
expect(name.textContent).toContain(label)
|
||||
expect(name.textContent).toContain(summary)
|
||||
expect(name.textContent).toContain('Web UI')
|
||||
expect(name.textContent).not.toContain(task.task_type_display)
|
||||
expect(
|
||||
name.closest('tr').querySelector('.results-col').textContent
|
||||
).toContain('Completed')
|
||||
}
|
||||
)
|
||||
|
||||
it('shows operation context while work is pending without reporting completion', () => {
|
||||
const task = {
|
||||
...tasks[2],
|
||||
task_type: PaperlessTaskType.BulkUpdate,
|
||||
task_type_display: 'Bulk Update',
|
||||
input_data: { operation: 'reprocess', document_count: 1 },
|
||||
}
|
||||
component.setSection(TaskSection.InProgress)
|
||||
flushTaskLists(25, 1, [task])
|
||||
fixture.detectChanges()
|
||||
|
||||
const name = fixture.nativeElement.querySelector('tbody .name-col')
|
||||
expect(name.textContent).toContain('Document reprocessing')
|
||||
expect(name.textContent).toContain('1 document')
|
||||
expect(component.taskResultMessage(task)).toBeNull()
|
||||
})
|
||||
|
||||
it.each([{}, { operation: 'future_operation' }])(
|
||||
'preserves the fallback for legacy or unknown operation data: %j',
|
||||
(input_data) => {
|
||||
const task = {
|
||||
...tasks[4],
|
||||
task_type: PaperlessTaskType.BulkUpdate,
|
||||
task_type_display: 'Bulk Update',
|
||||
input_data,
|
||||
result_data: {},
|
||||
}
|
||||
expect(component.taskDisplayName(task)).toBe('Bulk Update')
|
||||
expect(component.taskDocumentCount(task)).toBeNull()
|
||||
expect(component.taskResultMessage(task)).toBeNull()
|
||||
}
|
||||
)
|
||||
|
||||
it.each([-1, 1.5, '2', null, undefined])(
|
||||
'does not display an invalid document count: %s',
|
||||
(document_count) => {
|
||||
expect(
|
||||
component.taskDocumentCount({
|
||||
...tasks[4],
|
||||
input_data: { operation: 'modify_tags', document_count },
|
||||
})
|
||||
).toBeNull()
|
||||
}
|
||||
)
|
||||
|
||||
it('retains error details for failed operation tasks', () => {
|
||||
expect(
|
||||
component.taskResultMessage({
|
||||
...tasks[0],
|
||||
input_data: { operation: 'modify_tags', document_count: 12 },
|
||||
result_data: { error_message: 'Insufficient permissions' },
|
||||
})
|
||||
).toBe('Insufficient permissions')
|
||||
})
|
||||
|
||||
it('should filter tasks by result', () => {
|
||||
component.setSection(TaskSection.NeedsAttention)
|
||||
component.filterTargetID = 1
|
||||
|
||||
@@ -56,6 +56,27 @@ const FILTER_TARGETS = [
|
||||
{ id: TaskFilterTargetID.TaskId, name: $localize`Task ID` },
|
||||
]
|
||||
|
||||
const OPERATION_LABELS: Record<string, string> = {
|
||||
set_correspondent: $localize`Set correspondent`,
|
||||
set_document_type: $localize`Set document type`,
|
||||
set_storage_path: $localize`Set storage path`,
|
||||
add_tag: $localize`Add tag`,
|
||||
remove_tag: $localize`Remove tag`,
|
||||
modify_tags: $localize`Update tags`,
|
||||
modify_custom_fields: $localize`Update custom fields`,
|
||||
set_permissions: $localize`Set permissions`,
|
||||
delete: $localize`Move to trash`,
|
||||
reprocess: $localize`Document reprocessing`,
|
||||
run_workflow: $localize`Run workflow`,
|
||||
rotate: $localize`Rotate documents`,
|
||||
merge: $localize`Merge documents`,
|
||||
merge_as_versions: $localize`Merge as versions`,
|
||||
split: $localize`Split documents`,
|
||||
delete_pages: $localize`Delete pages`,
|
||||
edit_pdf: $localize`Edit PDF`,
|
||||
remove_password: $localize`Remove password`,
|
||||
}
|
||||
|
||||
const SECTION_LABELS = {
|
||||
[TaskSection.All]: $localize`All`,
|
||||
[TaskSection.NeedsAttention]: $localize`Needs attention`,
|
||||
@@ -414,11 +435,28 @@ export class TasksComponent
|
||||
}
|
||||
|
||||
taskDisplayName(task: PaperlessTask): string {
|
||||
return task.input_data?.filename?.toString() || task.task_type_display
|
||||
return (
|
||||
task.input_data?.filename?.toString() ||
|
||||
this.taskOperationLabel(task) ||
|
||||
task.task_type_display
|
||||
)
|
||||
}
|
||||
|
||||
taskShowsSeparateTypeLabel(task: PaperlessTask): boolean {
|
||||
return this.taskDisplayName(task) !== task.task_type_display
|
||||
return (
|
||||
!this.taskOperationLabel(task) &&
|
||||
this.taskDisplayName(task) !== task.task_type_display
|
||||
)
|
||||
}
|
||||
|
||||
private taskOperationLabel(task: PaperlessTask): string | null {
|
||||
const label = OPERATION_LABELS[task.input_data?.operation]
|
||||
return typeof label === 'string' ? label : null
|
||||
}
|
||||
|
||||
taskDocumentCount(task: PaperlessTask): number | null {
|
||||
const count = task.input_data?.document_count
|
||||
return Number.isInteger(count) && count >= 0 ? count : null
|
||||
}
|
||||
|
||||
taskResultMessage(task: PaperlessTask): string | null {
|
||||
@@ -446,6 +484,13 @@ export class TasksComponent
|
||||
return errorMessage
|
||||
}
|
||||
|
||||
if (
|
||||
task.status === PaperlessTaskStatus.Success &&
|
||||
this.taskOperationLabel(task)
|
||||
) {
|
||||
return $localize`Completed`
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user