feat(natural language): make natural language prefixes configurable (#795)

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/795
Co-authored-by: konrad <k@knt.li>
Co-committed-by: konrad <k@knt.li>
This commit is contained in:
konrad 2021-09-29 18:30:55 +00:00
parent 3b58756285
commit d47b13647e
7 changed files with 192 additions and 89 deletions

View file

@ -1,10 +1,31 @@
import {parseDate} from '../helpers/time/parseDate'
import _priorities from '../models/constants/priorities.json'
const LABEL_PREFIX: string = '@'
const LIST_PREFIX: string = '#'
const PRIORITY_PREFIX: string = '!'
const ASSIGNEE_PREFIX: string = '+'
const VIKUNJA_PREFIXES: Prefixes = {
label: '*',
list: '+',
priority: '!',
assignee: '@',
}
const TODOIST_PREFIXES: Prefixes = {
label: '@',
list: '#',
priority: '!',
assignee: '+',
}
export enum PrefixMode {
Disabled = 'disabled',
Default = 'vikunja',
Todoist = 'todoist',
}
export const PREFIXES = {
[PrefixMode.Disabled]: undefined,
[PrefixMode.Default]: VIKUNJA_PREFIXES,
[PrefixMode.Todoist]: TODOIST_PREFIXES,
}
const priorities: Priorites = _priorities
@ -26,12 +47,19 @@ interface ParsedTaskText {
assignees: string[],
}
interface Prefixes {
label: string,
list: string,
priority: string,
assignee: string,
}
/**
* Parses task text for dates, assignees, labels, lists, priorities and returns an object with all found intents.
*
* @param text
*/
export const parseTaskText = (text: string): ParsedTaskText => {
export const parseTaskText = (text: string, prefixesMode: PrefixMode = PrefixMode.Default): ParsedTaskText => {
const result: ParsedTaskText = {
text: text,
date: null,
@ -41,20 +69,25 @@ export const parseTaskText = (text: string): ParsedTaskText => {
assignees: [],
}
result.labels = getItemsFromPrefix(text, LABEL_PREFIX)
const prefixes = PREFIXES[prefixesMode]
if (prefixes === undefined) {
return result
}
const lists: string[] = getItemsFromPrefix(text, LIST_PREFIX)
result.labels = getItemsFromPrefix(text, prefixes.label)
const lists: string[] = getItemsFromPrefix(text, prefixes.list)
result.list = lists.length > 0 ? lists[0] : null
result.priority = getPriority(text)
result.priority = getPriority(text, prefixes.priority)
result.assignees = getItemsFromPrefix(text, ASSIGNEE_PREFIX)
result.assignees = getItemsFromPrefix(text, prefixes.assignee)
const {newText, date} = parseDate(text)
result.text = newText
result.date = date
return cleanupResult(result)
return cleanupResult(result, prefixes)
}
const getItemsFromPrefix = (text: string, prefix: string): string[] => {
@ -82,8 +115,8 @@ const getItemsFromPrefix = (text: string, prefix: string): string[] => {
return Array.from(new Set(items))
}
const getPriority = (text: string): number | null => {
const ps = getItemsFromPrefix(text, PRIORITY_PREFIX)
const getPriority = (text: string, prefix: string): number | null => {
const ps = getItemsFromPrefix(text, prefix)
if (ps.length === 0) {
return null
}
@ -112,11 +145,11 @@ const cleanupItemText = (text: string, items: string[], prefix: string): string
return text
}
const cleanupResult = (result: ParsedTaskText): ParsedTaskText => {
result.text = cleanupItemText(result.text, result.labels, LABEL_PREFIX)
result.text = result.list !== null ? cleanupItemText(result.text, [result.list], LIST_PREFIX) : result.text
result.text = result.priority !== null ? cleanupItemText(result.text, [String(result.priority)], PRIORITY_PREFIX) : result.text
result.text = cleanupItemText(result.text, result.assignees, ASSIGNEE_PREFIX)
const cleanupResult = (result: ParsedTaskText, prefixes: Prefixes): ParsedTaskText => {
result.text = cleanupItemText(result.text, result.labels, prefixes.label)
result.text = result.list !== null ? cleanupItemText(result.text, [result.list], prefixes.list) : result.text
result.text = result.priority !== null ? cleanupItemText(result.text, [String(result.priority)], prefixes.priority) : result.text
result.text = cleanupItemText(result.text, result.assignees, prefixes.assignee)
result.text = result.text.trim()
return result