mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-18 02:51:30 +03:00
Added filters for notifications
Added notifications for tasks
This commit is contained in:
@@ -2792,11 +2792,13 @@ components:
|
|||||||
- play
|
- play
|
||||||
- retry_download
|
- retry_download
|
||||||
- view_download_error
|
- view_download_error
|
||||||
|
- view_tasks
|
||||||
NotificationType:
|
NotificationType:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- download_complete
|
- download_complete
|
||||||
- download_error
|
- download_error
|
||||||
|
- task_finished
|
||||||
BaseChangePermissionsRequest:
|
BaseChangePermissionsRequest:
|
||||||
required:
|
required:
|
||||||
- permission
|
- permission
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const { uuid } = require('uuidv4');
|
const { uuid } = require('uuidv4');
|
||||||
const db_api = require('./db');
|
const db_api = require('./db');
|
||||||
|
const config_api = require('./config');
|
||||||
|
|
||||||
exports.sendNotification = async (notification) => {
|
exports.sendNotification = async (notification) => {
|
||||||
// TODO: hook into third party service
|
// TODO: hook into third party service
|
||||||
@@ -7,6 +8,15 @@ exports.sendNotification = async (notification) => {
|
|||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.sendTaskNotification = async (task_obj, confirmed) => {
|
||||||
|
// workaround for tasks which are user_uid agnostic
|
||||||
|
const user_uid = config_api.getConfigItem('ytdl_multi_user_mode') ? 'admin' : null;
|
||||||
|
await db_api.removeAllRecords('notifications', {"data.task_key": task_obj.key});
|
||||||
|
const data = {task_key: task_obj.key, task_title: task_obj.title, confirmed: confirmed};
|
||||||
|
const notification = exports.createNotification('task_finished', ['view_tasks'], data, user_uid);
|
||||||
|
return await exports.sendNotification(notification);
|
||||||
|
}
|
||||||
|
|
||||||
exports.sendDownloadNotification = async (file, user_uid) => {
|
exports.sendDownloadNotification = async (file, user_uid) => {
|
||||||
const data = {file_uid: file.uid, file_title: file.title};
|
const data = {file_uid: file.uid, file_title: file.title};
|
||||||
const notification = exports.createNotification('download_complete', ['play'], data, user_uid);
|
const notification = exports.createNotification('download_complete', ['play'], data, user_uid);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const db_api = require('./db');
|
const db_api = require('./db');
|
||||||
|
const notifications_api = require('./notifications');
|
||||||
const youtubedl_api = require('./youtube-dl');
|
const youtubedl_api = require('./youtube-dl');
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
@@ -128,6 +129,8 @@ exports.executeRun = async (task_key) => {
|
|||||||
const data = await TASKS[task_key].run();
|
const data = await TASKS[task_key].run();
|
||||||
await db_api.updateRecord('tasks', {key: task_key}, {data: TASKS[task_key]['confirm'] ? data : null, last_ran: Date.now()/1000, running: false});
|
await db_api.updateRecord('tasks', {key: task_key}, {data: TASKS[task_key]['confirm'] ? data : null, last_ran: Date.now()/1000, running: false});
|
||||||
logger.verbose(`Finished running task ${task_key}`);
|
logger.verbose(`Finished running task ${task_key}`);
|
||||||
|
const task_obj = await db_api.getRecord('tasks', {key: task_key});
|
||||||
|
await notifications_api.sendTaskNotification(task_obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.executeConfirm = async (task_key) => {
|
exports.executeConfirm = async (task_key) => {
|
||||||
@@ -141,6 +144,7 @@ exports.executeConfirm = async (task_key) => {
|
|||||||
await TASKS[task_key].confirm(data);
|
await TASKS[task_key].confirm(data);
|
||||||
await db_api.updateRecord('tasks', {key: task_key}, {confirming: false, last_confirmed: Date.now()/1000, data: null});
|
await db_api.updateRecord('tasks', {key: task_key}, {confirming: false, last_confirmed: Date.now()/1000, data: null});
|
||||||
logger.verbose(`Finished confirming task ${task_key}`);
|
logger.verbose(`Finished confirming task ${task_key}`);
|
||||||
|
await notifications_api.sendTaskNotification(task_obj, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.updateTaskSchedule = async (task_key, schedule) => {
|
exports.updateTaskSchedule = async (task_key, schedule) => {
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ export enum NotificationAction {
|
|||||||
PLAY = 'play',
|
PLAY = 'play',
|
||||||
RETRY_DOWNLOAD = 'retry_download',
|
RETRY_DOWNLOAD = 'retry_download',
|
||||||
VIEW_DOWNLOAD_ERROR = 'view_download_error',
|
VIEW_DOWNLOAD_ERROR = 'view_download_error',
|
||||||
|
VIEW_TASKS = 'view_tasks',
|
||||||
}
|
}
|
||||||
@@ -5,4 +5,5 @@
|
|||||||
export enum NotificationType {
|
export enum NotificationType {
|
||||||
DOWNLOAD_COMPLETE = 'download_complete',
|
DOWNLOAD_COMPLETE = 'download_complete',
|
||||||
DOWNLOAD_ERROR = 'download_error',
|
DOWNLOAD_ERROR = 'download_error',
|
||||||
|
TASK_FINISHED = 'task_finished',
|
||||||
}
|
}
|
||||||
@@ -15,31 +15,36 @@ export class NotificationsListComponent {
|
|||||||
|
|
||||||
NOTIFICATION_PREFIX: { [key in NotificationType]: string } = {
|
NOTIFICATION_PREFIX: { [key in NotificationType]: string } = {
|
||||||
download_complete: $localize`Finished downloading`,
|
download_complete: $localize`Finished downloading`,
|
||||||
download_error: $localize`Download failed`
|
download_error: $localize`Download failed`,
|
||||||
|
task_finished: $localize`Task finished`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attaches string to the end of the notification text
|
// Attaches string to the end of the notification text
|
||||||
NOTIFICATION_SUFFIX_KEY: { [key in NotificationType]: string } = {
|
NOTIFICATION_SUFFIX_KEY: { [key in NotificationType]: string } = {
|
||||||
download_complete: 'file_title',
|
download_complete: 'file_title',
|
||||||
download_error: 'download_url'
|
download_error: 'download_url',
|
||||||
|
task_finished: 'task_title'
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTIFICATION_ACTION_TO_STRING: { [key in NotificationAction]: string } = {
|
NOTIFICATION_ACTION_TO_STRING: { [key in NotificationAction]: string } = {
|
||||||
play: $localize`Play`,
|
play: $localize`Play`,
|
||||||
retry_download: $localize`Retry download`,
|
retry_download: $localize`Retry download`,
|
||||||
view_download_error: $localize`View error`
|
view_download_error: $localize`View error`,
|
||||||
|
view_tasks: $localize`View task`
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTIFICATION_COLOR: { [key in NotificationAction]: string } = {
|
NOTIFICATION_COLOR: { [key in NotificationAction]: string } = {
|
||||||
play: 'primary',
|
play: 'primary',
|
||||||
retry_download: 'primary',
|
retry_download: 'primary',
|
||||||
view_download_error: 'warn'
|
view_download_error: 'warn',
|
||||||
|
view_tasks: 'primary'
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTIFICATION_ICON: { [key in NotificationAction]: string } = {
|
NOTIFICATION_ICON: { [key in NotificationAction]: string } = {
|
||||||
play: 'smart_display',
|
play: 'smart_display',
|
||||||
retry_download: 'restart_alt',
|
retry_download: 'restart_alt',
|
||||||
view_download_error: 'warning'
|
view_download_error: 'warning',
|
||||||
|
view_tasks: 'task'
|
||||||
}
|
}
|
||||||
|
|
||||||
emitNotificationAction(notification: Notification, action: NotificationAction): void {
|
emitNotificationAction(notification: Notification, action: NotificationAction): void {
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
.notification-title {
|
.notification-title {
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
text-align: center
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.notifications-list-parent {
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0px 10px 10px 10px;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
<div *ngIf="notifications !== null && notifications.length === 0" style="text-align: center; margin: 10px;" i18n="No notifications available">No notifications available</div>
|
<div *ngIf="notifications !== null && notifications.length === 0" style="text-align: center; margin: 10px;" i18n="No notifications available">No notifications available</div>
|
||||||
<div style="margin: 10px;" *ngIf="notifications?.length > 0">
|
<div *ngIf="notifications?.length > 0">
|
||||||
<app-notifications-list (notificationAction)="notificationAction($event)" (deleteNotification)="deleteNotification($event)" [notifications]="notifications"></app-notifications-list>
|
<div class="notifications-list-parent">
|
||||||
<button style="margin-top: 15px;" *ngIf="notifications?.length > 0" color="warn" (click)="deleteAllNotifications()" mat-stroked-button>Remove all</button>
|
<mat-chip-listbox [value]="selectedFilters" [multiple]="true" (change)="selectedFiltersChanged($event)">
|
||||||
|
<mat-chip-option *ngFor="let filter of notificationFilters | keyvalue: originalOrder" [value]="filter.key" [selected]="selectedFilters.includes(filter.key)" color="accent">{{filter.value.label}}</mat-chip-option>
|
||||||
|
</mat-chip-listbox>
|
||||||
|
<app-notifications-list (notificationAction)="notificationAction($event)" (deleteNotification)="deleteNotification($event)" [notifications]="filtered_notifications"></app-notifications-list>
|
||||||
|
</div>
|
||||||
|
<button style="margin: 10px 0px 2px 10px;" *ngIf="notifications?.length > 0" color="warn" (click)="deleteAllNotifications()" mat-stroked-button>Remove all</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Component, ElementRef, EventEmitter, OnInit, Output } from '@angular/core';
|
import { Component, ElementRef, EventEmitter, OnInit, Output } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { Notification } from 'api-types';
|
import { Notification, NotificationType } from 'api-types';
|
||||||
import { NotificationAction } from 'api-types/models/NotificationAction';
|
import { NotificationAction } from 'api-types/models/NotificationAction';
|
||||||
|
import { MatChipListboxChange } from '@angular/material/chips';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-notifications',
|
selector: 'app-notifications',
|
||||||
@@ -12,9 +13,27 @@ import { NotificationAction } from 'api-types/models/NotificationAction';
|
|||||||
export class NotificationsComponent implements OnInit {
|
export class NotificationsComponent implements OnInit {
|
||||||
|
|
||||||
notifications: Notification[] = null;
|
notifications: Notification[] = null;
|
||||||
|
filtered_notifications: Notification[] = null;
|
||||||
|
|
||||||
@Output() notificationCount = new EventEmitter<number>();
|
@Output() notificationCount = new EventEmitter<number>();
|
||||||
|
|
||||||
|
notificationFilters: { [key in NotificationType]: {key: string, label: string} } = {
|
||||||
|
download_complete: {
|
||||||
|
key: 'download_complete',
|
||||||
|
label: $localize`Download completed`
|
||||||
|
},
|
||||||
|
download_error: {
|
||||||
|
key: 'download_error',
|
||||||
|
label: $localize`Download error`
|
||||||
|
},
|
||||||
|
task_finished: {
|
||||||
|
key: 'task_finished',
|
||||||
|
label: $localize`Task`
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
selectedFilters = [];
|
||||||
|
|
||||||
constructor(public postsService: PostsService, private router: Router, private elRef: ElementRef) { }
|
constructor(public postsService: PostsService, private router: Router, private elRef: ElementRef) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
@@ -33,7 +52,10 @@ export class NotificationsComponent implements OnInit {
|
|||||||
getNotifications(): void {
|
getNotifications(): void {
|
||||||
this.postsService.getNotifications().subscribe(res => {
|
this.postsService.getNotifications().subscribe(res => {
|
||||||
this.notifications = res['notifications'];
|
this.notifications = res['notifications'];
|
||||||
|
this.notifications.sort((a, b) => b.timestamp - a.timestamp);
|
||||||
this.notificationCount.emit(this.notifications.filter(notification => !notification.read).length);
|
this.notificationCount.emit(this.notifications.filter(notification => !notification.read).length);
|
||||||
|
|
||||||
|
this.filterNotifications();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +73,9 @@ export class NotificationsComponent implements OnInit {
|
|||||||
this.deleteNotification(action_info['notification']['uid']);
|
this.deleteNotification(action_info['notification']['uid']);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case NotificationAction.VIEW_TASKS:
|
||||||
|
this.router.navigate(['tasks']);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error(`Notification action ${action_info['action']} does not exist!`);
|
console.error(`Notification action ${action_info['action']} does not exist!`);
|
||||||
break;
|
break;
|
||||||
@@ -60,6 +85,7 @@ export class NotificationsComponent implements OnInit {
|
|||||||
deleteNotification(uid: string): void {
|
deleteNotification(uid: string): void {
|
||||||
this.postsService.deleteNotification(uid).subscribe(res => {
|
this.postsService.deleteNotification(uid).subscribe(res => {
|
||||||
this.notifications.filter(notification => notification['uid'] !== uid);
|
this.notifications.filter(notification => notification['uid'] !== uid);
|
||||||
|
this.filterNotifications();
|
||||||
this.notificationCount.emit(this.notifications.length);
|
this.notificationCount.emit(this.notifications.length);
|
||||||
this.getNotifications();
|
this.getNotifications();
|
||||||
});
|
});
|
||||||
@@ -68,6 +94,7 @@ export class NotificationsComponent implements OnInit {
|
|||||||
deleteAllNotifications(): void {
|
deleteAllNotifications(): void {
|
||||||
this.postsService.deleteAllNotifications().subscribe(res => {
|
this.postsService.deleteAllNotifications().subscribe(res => {
|
||||||
this.notifications = [];
|
this.notifications = [];
|
||||||
|
this.filtered_notifications = [];
|
||||||
this.getNotifications();
|
this.getNotifications();
|
||||||
});
|
});
|
||||||
this.notificationCount.emit(0);
|
this.notificationCount.emit(0);
|
||||||
@@ -81,4 +108,17 @@ export class NotificationsComponent implements OnInit {
|
|||||||
this.notificationCount.emit(0);
|
this.notificationCount.emit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterNotifications(): void {
|
||||||
|
this.filtered_notifications = this.notifications.filter(notification => this.selectedFilters.length === 0 || this.selectedFilters.includes(notification.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedFiltersChanged(event: MatChipListboxChange): void {
|
||||||
|
this.selectedFilters = event.value;
|
||||||
|
this.filterNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
originalOrder = (): number => {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user