Add support for tags and priorities + make default query and mapper

This commit is contained in:
2025-01-17 16:54:47 +01:00
parent 298efc3345
commit 8490e073f6
6 changed files with 50 additions and 21 deletions

View File

@@ -2,6 +2,7 @@ import fs from "fs";
import { BackendSettings } from "../types/config"; import { BackendSettings } from "../types/config";
import { Notification } from "../types/notification"; import { Notification } from "../types/notification";
import { Backend } from "./base"; import { Backend } from "./base";
import { TaskPriority } from "../types/task";
type Config = { type Config = {
url: string; url: string;
@@ -21,9 +22,26 @@ export class NtfySH extends Backend<Config> {
method: 'POST', method: 'POST',
body: notification.text, body: notification.text,
headers: { headers: {
'Title': notification.title, 'Authorization': `Bearer ${token}`,
'Authorization': `Bearer ${token}` 'Title': notification.title ?? "",
'Priority': mapPriority(notification.priority),
'Tags': notification.tags?.join(",") ?? ""
} }
}) })
} }
} }
function mapPriority(priority?: TaskPriority): string {
if (!priority) {
return 'default';
}
return {
[TaskPriority.LOWEST]: 'min',
[TaskPriority.LOW]: 'low',
[TaskPriority.NORMAL]: 'default',
[TaskPriority.MEDIUM]: 'default',
[TaskPriority.HIGH]: 'high',
[TaskPriority.HIGHEST]: 'max',
}[priority];
}

View File

@@ -1,11 +1,13 @@
import fs from "fs"; import fs from "fs";
import { Task } from "../types/task"; import { Task } from "../types/task";
import { Notification, NotificationDatabase } from "../types/notification"; import { Notification, NotificationDatabase } from "../types/notification";
import { jsMapper } from "../util";
/** /**
* Applies the mapper for each task from list, groups them by time and dumps the data into JSON formatted file. * Applies the mapper for each task from list, groups them by time and dumps the data into JSON formatted file.
*/ */
export function dumpDatabase(file: string, tasks: Task[], mapper: string) { export function dumpDatabase(file: string, tasks: Task[], mapper?: string) {
const data = serializeDatabase(tasks, mapper); const data = serializeDatabase(tasks, mapper);
fs.writeFileSync(file, data); fs.writeFileSync(file, data);
} }
@@ -13,8 +15,10 @@ export function dumpDatabase(file: string, tasks: Task[], mapper: string) {
/** /**
* Applies the mapper for each task from list, groups them by time and serializes into JSON format. * Applies the mapper for each task from list, groups them by time and serializes into JSON format.
*/ */
export function serializeDatabase(tasks: Task[], mapper: string): string { export function serializeDatabase(tasks: Task[], mapper?: string): string {
const transformer = new Function("$", `return ${mapper}`) as (task: Task) => Notification; const transformer = mapper
? jsMapper<Task, Notification>(mapper, {})
: defaultMapper;
const output = tasks.map(wrapWithTimeFiller(transformer)).reduce((acc, n) => { const output = tasks.map(wrapWithTimeFiller(transformer)).reduce((acc, n) => {
if (n.time) { if (n.time) {
@@ -37,3 +41,12 @@ function wrapWithTimeFiller(mapper: (task: Task) => Notification): (task: Task)
} }
}; };
} }
function defaultMapper(task: Task): Notification {
return {
title: "Obsidian Tasks Reminder",
text: task.label,
priority: task.priority,
tags: task.tags,
};
}

View File

@@ -5,6 +5,7 @@ import { parse } from "../generated/grammar/task";
import { Task as DefaultTask } from "../model"; import { Task as DefaultTask } from "../model";
import { ParseResult } from "../types/grammar"; import { ParseResult } from "../types/grammar";
import { Task, TaskPriority } from "../types/task"; import { Task, TaskPriority } from "../types/task";
import { jsMapper } from "../util";
/** /**
* Returns all tasks from specified directory and filters them with optional query. * Returns all tasks from specified directory and filters them with optional query.
@@ -20,21 +21,12 @@ export async function loadTasks(directories: string[], query?: string): Promise<
HIGHEST: TaskPriority.HIGHEST HIGHEST: TaskPriority.HIGHEST
}; };
const filter = query && createFilter(query, ctx); const filter = query && jsMapper<Task, boolean>(query, ctx);
const tasks = await Promise.all(directories.map(readTasksFromDirectory)); const tasks = await Promise.all(directories.map(readTasksFromDirectory));
return tasks.flat().filter(t => filter ? filter(t) : true); return tasks.flat().filter(t => filter ? filter(t) : true);
} }
/**
* Creates a filter function for tasks using a query string and context object.
* All context' properties will be passed as variables to the query string.
*/
function createFilter(query: string, context: Record<string, unknown>): (task: Task) => boolean {
const filter = new Function('$', ...Object.keys(context), `return ${query};`);
return (task: Task) => filter(task, ...Object.values(context));
}
/** /**
* Read all files in specific directory and returns all tasks from those files. * Read all files in specific directory and returns all tasks from those files.
*/ */

View File

@@ -1,7 +1,7 @@
export type Config = { export type Config = {
sources: string[]; sources: string[];
query: string; query?: string;
mapper: string; mapper?: string;
databaseFile: string; databaseFile: string;
backend: Record<string, unknown>; backend: Record<string, unknown>;
}; };

View File

@@ -1,9 +1,11 @@
import dayjs, { Dayjs } from "dayjs" import { TaskPriority } from "./task";
export type Notification = { export type Notification = {
time?: string;
title: string;
text: string; text: string;
time?: string;
title?: string;
priority?: TaskPriority;
tags?: string[];
}; };
export type NotificationDatabase = Record<string, Notification[]>; export type NotificationDatabase = Record<string, Notification[]>;

4
src/util/index.ts Normal file
View File

@@ -0,0 +1,4 @@
export function jsMapper<I, O>(code: string, context: Record<string, unknown>): (task: I) => O {
const filter = new Function('$', ...Object.keys(context), `return ${code};`);
return (task: I) => filter(task, ...Object.values(context));
}