mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-11-15 10:26:42 +00:00
We need a tasks notification service
This commit is contained in:
19 files changed
+498
-162
No files matched your search
@@ -7,6 +7,7 @@
|
||||
background-color: var(--pngx-toast-bg);
|
||||
color: var(--bs-body-color);
|
||||
overflow: hidden;
|
||||
transition: background-color .18s ease, border-color .18s ease;
|
||||
|
||||
&.toast-success {
|
||||
--pngx-toast-accent: var(--pngx-toast-success);
|
||||
@@ -23,6 +24,13 @@
|
||||
|
||||
.toast-icon {
|
||||
color: var(--pngx-toast-accent);
|
||||
transition: color .18s ease;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.toast, .toast-icon {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.toast-content {
|
||||
|
||||
@@ -65,6 +65,36 @@ describe('ToastComponent', () => {
|
||||
expect(component.delayRemaining()).toEqual(3000)
|
||||
})
|
||||
|
||||
it('updates its color and icon in place and restarts the countdown', () => {
|
||||
jest.useFakeTimers()
|
||||
fixture.componentRef.setInput('toast', {
|
||||
id: 'task-1',
|
||||
content: 'Queued',
|
||||
delay: 5000,
|
||||
})
|
||||
fixture.detectChanges()
|
||||
component.onShown(component.toast)
|
||||
jest.advanceTimersByTime(4500)
|
||||
const element = fixture.nativeElement.querySelector('ngb-toast')
|
||||
fixture.componentRef.setInput('toast', {
|
||||
id: 'task-1',
|
||||
content: 'Completed',
|
||||
delay: 5000,
|
||||
level: ToastLevel.Success,
|
||||
})
|
||||
fixture.detectChanges()
|
||||
expect(fixture.nativeElement.querySelector('ngb-toast')).toBe(element)
|
||||
expect(element.classList).toContain('toast-success')
|
||||
expect(element.querySelector('[name="check-circle"]')).not.toBeNull()
|
||||
expect(component.delayRemaining()).toBe(5000)
|
||||
const hide = jest.spyOn(component.ngbToast, 'hide')
|
||||
jest.advanceTimersByTime(1000)
|
||||
expect(hide).not.toHaveBeenCalled()
|
||||
jest.advanceTimersByTime(4200)
|
||||
expect(hide).toHaveBeenCalled()
|
||||
jest.useRealTimers()
|
||||
})
|
||||
|
||||
it('should hide the toast when the countdown ends', () => {
|
||||
jest.useFakeTimers()
|
||||
const toast = { content: 'Info', delay: 3000 }
|
||||
|
||||
@@ -5,8 +5,10 @@ import {
|
||||
DestroyRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
inject,
|
||||
signal,
|
||||
@@ -34,7 +36,7 @@ import { Toast, ToastLevel } from 'src/app/services/toast.service'
|
||||
styleUrl: './toast.component.scss',
|
||||
providers: [DatePipe, CustomDatePipe],
|
||||
})
|
||||
export class ToastComponent implements OnInit {
|
||||
export class ToastComponent implements OnInit, OnChanges {
|
||||
private clipboard = inject(Clipboard)
|
||||
private customDatePipe = inject(CustomDatePipe)
|
||||
private destroyRef = inject(DestroyRef)
|
||||
@@ -69,6 +71,12 @@ export class ToastComponent implements OnInit {
|
||||
if (this.autohide) this.delayRemaining.set(this.toast.delay)
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.toast && !changes.toast.firstChange && this.autohide) {
|
||||
this.onShown(this.toast)
|
||||
}
|
||||
}
|
||||
|
||||
get relativeTimestamp(): string {
|
||||
return this.customDatePipe.transform(this.toast.timestamp, 'relative')
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ describe('ToastsComponent', () => {
|
||||
toasts.forEach((t) => toastSubject.next(t))
|
||||
expect(component.toasts().map((t) => t.id)).toEqual(['3', '2', '1'])
|
||||
|
||||
// showing a visible toast again moves it to the top without duplicating
|
||||
// Updating a visible toast preserves its position without duplicating it.
|
||||
toastSubject.next(toasts[1])
|
||||
expect(component.toasts().map((t) => t.id)).toEqual(['1', '3', '2'])
|
||||
expect(component.toasts().map((t) => t.id)).toEqual(['3', '2', '1'])
|
||||
})
|
||||
|
||||
it('should remove a popup when it hides without closing it', () => {
|
||||
|
||||
@@ -32,10 +32,11 @@ export class ToastsComponent {
|
||||
return
|
||||
}
|
||||
this.toasts.update((toasts) =>
|
||||
[toast, ...toasts.filter((t) => t.id !== toast.id)].slice(
|
||||
0,
|
||||
MAX_VISIBLE_TOASTS
|
||||
)
|
||||
toasts.some((existing) => existing.id === toast.id)
|
||||
? toasts.map((existing) =>
|
||||
existing.id === toast.id ? toast : existing
|
||||
)
|
||||
: [toast, ...toasts].slice(0, MAX_VISIBLE_TOASTS)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user