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:
parent
3b58756285
commit
d47b13647e
7 changed files with 192 additions and 89 deletions
|
@ -7,6 +7,7 @@ import LabelTaskService from '@/services/labelTask'
|
||||||
import {mapState} from 'vuex'
|
import {mapState} from 'vuex'
|
||||||
import UserService from '@/services/user'
|
import UserService from '@/services/user'
|
||||||
import TaskService from '@/services/task'
|
import TaskService from '@/services/task'
|
||||||
|
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
|
@ -26,7 +27,7 @@ export default {
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
createNewTask(newTaskTitle, bucketId = 0, lId = 0, position = 0) {
|
createNewTask(newTaskTitle, bucketId = 0, lId = 0, position = 0) {
|
||||||
const parsedTask = parseTaskText(newTaskTitle)
|
const parsedTask = parseTaskText(newTaskTitle, getQuickAddMagicMode())
|
||||||
const assignees = []
|
const assignees = []
|
||||||
|
|
||||||
// Uses the following ways to get the list id of the new task:
|
// Uses the following ways to get the list id of the new task:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="available">
|
||||||
<p class="help has-text-grey">
|
<p class="help has-text-grey">
|
||||||
{{ $t('task.quickAddMagic.hint') }}.
|
{{ $t('task.quickAddMagic.hint') }}.
|
||||||
<a @click="() => visible = true">{{ $t('task.quickAddMagic.what') }}</a>
|
<a @click="() => visible = true">{{ $t('task.quickAddMagic.what') }}</a>
|
||||||
|
@ -16,30 +16,30 @@
|
||||||
|
|
||||||
<h3>{{ $t('task.attributes.labels') }}</h3>
|
<h3>{{ $t('task.attributes.labels') }}</h3>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.quickAddMagic.label1', {prefix: '@'}) }}
|
{{ $t('task.quickAddMagic.label1', {prefix: prefixes.label}) }}
|
||||||
{{ $t('task.quickAddMagic.label2') }}
|
{{ $t('task.quickAddMagic.label2') }}
|
||||||
{{ $t('task.quickAddMagic.multiple') }}
|
{{ $t('task.quickAddMagic.multiple') }}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.quickAddMagic.label3') }}
|
{{ $t('task.quickAddMagic.label3') }}
|
||||||
{{ $t('task.quickAddMagic.label4', {prefix: '@'}) }}
|
{{ $t('task.quickAddMagic.label4', {prefix: prefixes.label}) }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>{{ $t('task.attributes.priority') }}</h3>
|
<h3>{{ $t('task.attributes.priority') }}</h3>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.quickAddMagic.priority1', {prefix: '!'}) }}
|
{{ $t('task.quickAddMagic.priority1', {prefix: prefixes.priority}) }}
|
||||||
{{ $t('task.quickAddMagic.priority2') }}
|
{{ $t('task.quickAddMagic.priority2') }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>{{ $t('task.attributes.assignees') }}</h3>
|
<h3>{{ $t('task.attributes.assignees') }}</h3>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.quickAddMagic.assignees', {prefix: '+'}) }}
|
{{ $t('task.quickAddMagic.assignees', {prefix: prefixes.assignee}) }}
|
||||||
{{ $t('task.quickAddMagic.multiple') }}
|
{{ $t('task.quickAddMagic.multiple') }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>{{ $t('list.list.title') }}</h3>
|
<h3>{{ $t('list.list.title') }}</h3>
|
||||||
<p>
|
<p>
|
||||||
{{ $t('task.quickAddMagic.list1', {prefix: '#'}) }}
|
{{ $t('task.quickAddMagic.list1', {prefix: prefixes.list}) }}
|
||||||
{{ $t('task.quickAddMagic.list2') }}
|
{{ $t('task.quickAddMagic.list2') }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -71,12 +71,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
|
||||||
|
import {PREFIXES} from '@/modules/parseTaskText'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'quick-add-magic',
|
name: 'quick-add-magic',
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
|
mode: getQuickAddMagicMode(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
available() {
|
||||||
|
return this.mode !== 'disabled'
|
||||||
|
},
|
||||||
|
prefixes() {
|
||||||
|
return PREFIXES[this.mode]
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
14
src/helpers/quickAddMagicMode.ts
Normal file
14
src/helpers/quickAddMagicMode.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import {PrefixMode} from '@/modules/parseTaskText'
|
||||||
|
|
||||||
|
const key = 'quickAddMagicMode'
|
||||||
|
|
||||||
|
export const setQuickAddMagicMode = (mode: PrefixMode) => {
|
||||||
|
localStorage.setItem(key, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getQuickAddMagicMode = (): PrefixMode => {
|
||||||
|
const mode = localStorage.getItem(key)
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
return PrefixMode[mode] || PrefixMode.Disabled
|
||||||
|
}
|
|
@ -96,6 +96,12 @@
|
||||||
"uploadAvatar": "Upload Avatar",
|
"uploadAvatar": "Upload Avatar",
|
||||||
"statusUpdateSuccess": "Avatar status was updated successfully!",
|
"statusUpdateSuccess": "Avatar status was updated successfully!",
|
||||||
"setSuccess": "The avatar has been set successfully!"
|
"setSuccess": "The avatar has been set successfully!"
|
||||||
|
},
|
||||||
|
"quickAddMagic": {
|
||||||
|
"title": "Quick Add Magic Mode",
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"todoist": "Todoist",
|
||||||
|
"vikunja": "Vikunja"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"deletion": {
|
"deletion": {
|
||||||
|
|
|
@ -8,6 +8,29 @@ describe('Parse Task Text', () => {
|
||||||
expect(parseTaskText('Lorem Ipsum').text).toBe('Lorem Ipsum')
|
expect(parseTaskText('Lorem Ipsum').text).toBe('Lorem Ipsum')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not parse text when disabled', () => {
|
||||||
|
const text = 'Lorem Ipsum today *label +list !2 @user'
|
||||||
|
const result = parseTaskText(text, 'disabled')
|
||||||
|
|
||||||
|
expect(result.text).toBe(text)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should parse text in todoist mode when configured', () => {
|
||||||
|
const result = parseTaskText('Lorem Ipsum today @label #list !2 +user', 'todoist')
|
||||||
|
|
||||||
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
|
const now = new Date()
|
||||||
|
expect(result.date.getFullYear()).toBe(now.getFullYear())
|
||||||
|
expect(result.date.getMonth()).toBe(now.getMonth())
|
||||||
|
expect(result.date.getDate()).toBe(now.getDate())
|
||||||
|
expect(result.labels).toHaveLength(1)
|
||||||
|
expect(result.labels[0]).toBe('label')
|
||||||
|
expect(result.list).toBe('list')
|
||||||
|
expect(result.priority).toBe(2)
|
||||||
|
expect(result.assignees).toHaveLength(1)
|
||||||
|
expect(result.assignees[0]).toBe('user')
|
||||||
|
})
|
||||||
|
|
||||||
describe('Date Parsing', () => {
|
describe('Date Parsing', () => {
|
||||||
it('should not return any date if none was provided', () => {
|
it('should not return any date if none was provided', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum')
|
const result = parseTaskText('Lorem Ipsum')
|
||||||
|
@ -47,8 +70,8 @@ describe('Parse Task Text', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const c in cases) {
|
for (const c in cases) {
|
||||||
it('should recognize today with a time ' + c, () => {
|
it(`should recognize today with a time ${c}`, () => {
|
||||||
const result = parseTaskText('Lorem Ipsum today ' + c)
|
const result = parseTaskText(`Lorem Ipsum today ${c}`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
@ -354,7 +377,7 @@ describe('Parse Task Text', () => {
|
||||||
|
|
||||||
describe('Labels', () => {
|
describe('Labels', () => {
|
||||||
it('should parse labels', () => {
|
it('should parse labels', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum @label1 @label2')
|
const result = parseTaskText('Lorem Ipsum *label1 *label2')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.labels).toHaveLength(2)
|
expect(result.labels).toHaveLength(2)
|
||||||
|
@ -362,7 +385,7 @@ describe('Parse Task Text', () => {
|
||||||
expect(result.labels[1]).toBe('label2')
|
expect(result.labels[1]).toBe('label2')
|
||||||
})
|
})
|
||||||
it('should parse labels from the start', () => {
|
it('should parse labels from the start', () => {
|
||||||
const result = parseTaskText('@label1 Lorem Ipsum @label2')
|
const result = parseTaskText('*label1 Lorem Ipsum *label2')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.labels).toHaveLength(2)
|
expect(result.labels).toHaveLength(2)
|
||||||
|
@ -370,7 +393,7 @@ describe('Parse Task Text', () => {
|
||||||
expect(result.labels[1]).toBe('label2')
|
expect(result.labels[1]).toBe('label2')
|
||||||
})
|
})
|
||||||
it('should resolve duplicate labels', () => {
|
it('should resolve duplicate labels', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum @label1 @label1 @label2')
|
const result = parseTaskText('Lorem Ipsum *label1 *label1 *label2')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.labels).toHaveLength(2)
|
expect(result.labels).toHaveLength(2)
|
||||||
|
@ -378,14 +401,14 @@ describe('Parse Task Text', () => {
|
||||||
expect(result.labels[1]).toBe('label2')
|
expect(result.labels[1]).toBe('label2')
|
||||||
})
|
})
|
||||||
it('should correctly parse labels with spaces in them', () => {
|
it('should correctly parse labels with spaces in them', () => {
|
||||||
const result = parseTaskText(`Lorem @'label with space' Ipsum`)
|
const result = parseTaskText(`Lorem *'label with space' Ipsum`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.labels).toHaveLength(1)
|
expect(result.labels).toHaveLength(1)
|
||||||
expect(result.labels[0]).toBe('label with space')
|
expect(result.labels[0]).toBe('label with space')
|
||||||
})
|
})
|
||||||
it('should correctly parse labels with spaces in them and "', () => {
|
it('should correctly parse labels with spaces in them and "', () => {
|
||||||
const result = parseTaskText('Lorem @"label with space" Ipsum')
|
const result = parseTaskText('Lorem *"label with space" Ipsum')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.labels).toHaveLength(1)
|
expect(result.labels).toHaveLength(1)
|
||||||
|
@ -395,27 +418,27 @@ describe('Parse Task Text', () => {
|
||||||
|
|
||||||
describe('List', () => {
|
describe('List', () => {
|
||||||
it('should parse a list', () => {
|
it('should parse a list', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum #list')
|
const result = parseTaskText('Lorem Ipsum +list')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.list).toBe('list')
|
expect(result.list).toBe('list')
|
||||||
})
|
})
|
||||||
it('should parse a list with a space in it', () => {
|
it('should parse a list with a space in it', () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum #'list with long name'`)
|
const result = parseTaskText(`Lorem Ipsum +'list with long name'`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.list).toBe('list with long name')
|
expect(result.list).toBe('list with long name')
|
||||||
})
|
})
|
||||||
it('should parse a list with a space in it and "', () => {
|
it('should parse a list with a space in it and "', () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum #"list with long name"`)
|
const result = parseTaskText(`Lorem Ipsum +"list with long name"`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.list).toBe('list with long name')
|
expect(result.list).toBe('list with long name')
|
||||||
})
|
})
|
||||||
it('should parse only the first list', () => {
|
it('should parse only the first list', () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum #list1 #list2 #list3`)
|
const result = parseTaskText(`Lorem Ipsum +list1 +list2 +list3`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum #list2 #list3')
|
expect(result.text).toBe('Lorem Ipsum +list2 +list3')
|
||||||
expect(result.list).toBe('list1')
|
expect(result.list).toBe('list1')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -445,14 +468,14 @@ describe('Parse Task Text', () => {
|
||||||
|
|
||||||
describe('Assignee', () => {
|
describe('Assignee', () => {
|
||||||
it('should parse an assignee', () => {
|
it('should parse an assignee', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum +user')
|
const result = parseTaskText('Lorem Ipsum @user')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.assignees).toHaveLength(1)
|
expect(result.assignees).toHaveLength(1)
|
||||||
expect(result.assignees[0]).toBe('user')
|
expect(result.assignees[0]).toBe('user')
|
||||||
})
|
})
|
||||||
it('should parse multiple assignees', () => {
|
it('should parse multiple assignees', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum +user1 +user2 +user3')
|
const result = parseTaskText('Lorem Ipsum @user1 @user2 @user3')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.assignees).toHaveLength(3)
|
expect(result.assignees).toHaveLength(3)
|
||||||
|
@ -461,7 +484,7 @@ describe('Parse Task Text', () => {
|
||||||
expect(result.assignees[2]).toBe('user3')
|
expect(result.assignees[2]).toBe('user3')
|
||||||
})
|
})
|
||||||
it('should parse avoid duplicate assignees', () => {
|
it('should parse avoid duplicate assignees', () => {
|
||||||
const result = parseTaskText('Lorem Ipsum +user1 +user1 +user2')
|
const result = parseTaskText('Lorem Ipsum @user1 @user1 @user2')
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.assignees).toHaveLength(2)
|
expect(result.assignees).toHaveLength(2)
|
||||||
|
@ -469,14 +492,14 @@ describe('Parse Task Text', () => {
|
||||||
expect(result.assignees[1]).toBe('user2')
|
expect(result.assignees[1]).toBe('user2')
|
||||||
})
|
})
|
||||||
it('should parse an assignee with a space in it', () => {
|
it('should parse an assignee with a space in it', () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum +'user with long name'`)
|
const result = parseTaskText(`Lorem Ipsum @'user with long name'`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.assignees).toHaveLength(1)
|
expect(result.assignees).toHaveLength(1)
|
||||||
expect(result.assignees[0]).toBe('user with long name')
|
expect(result.assignees[0]).toBe('user with long name')
|
||||||
})
|
})
|
||||||
it('should parse an assignee with a space in it and "', () => {
|
it('should parse an assignee with a space in it and "', () => {
|
||||||
const result = parseTaskText(`Lorem Ipsum +"user with long name"`)
|
const result = parseTaskText(`Lorem Ipsum @"user with long name"`)
|
||||||
|
|
||||||
expect(result.text).toBe('Lorem Ipsum')
|
expect(result.text).toBe('Lorem Ipsum')
|
||||||
expect(result.assignees).toHaveLength(1)
|
expect(result.assignees).toHaveLength(1)
|
||||||
|
|
|
@ -1,10 +1,31 @@
|
||||||
import {parseDate} from '../helpers/time/parseDate'
|
import {parseDate} from '../helpers/time/parseDate'
|
||||||
import _priorities from '../models/constants/priorities.json'
|
import _priorities from '../models/constants/priorities.json'
|
||||||
|
|
||||||
const LABEL_PREFIX: string = '@'
|
const VIKUNJA_PREFIXES: Prefixes = {
|
||||||
const LIST_PREFIX: string = '#'
|
label: '*',
|
||||||
const PRIORITY_PREFIX: string = '!'
|
list: '+',
|
||||||
const ASSIGNEE_PREFIX: string = '+'
|
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
|
const priorities: Priorites = _priorities
|
||||||
|
|
||||||
|
@ -26,12 +47,19 @@ interface ParsedTaskText {
|
||||||
assignees: string[],
|
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.
|
* Parses task text for dates, assignees, labels, lists, priorities and returns an object with all found intents.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param text
|
||||||
*/
|
*/
|
||||||
export const parseTaskText = (text: string): ParsedTaskText => {
|
export const parseTaskText = (text: string, prefixesMode: PrefixMode = PrefixMode.Default): ParsedTaskText => {
|
||||||
const result: ParsedTaskText = {
|
const result: ParsedTaskText = {
|
||||||
text: text,
|
text: text,
|
||||||
date: null,
|
date: null,
|
||||||
|
@ -41,20 +69,25 @@ export const parseTaskText = (text: string): ParsedTaskText => {
|
||||||
assignees: [],
|
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.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)
|
const {newText, date} = parseDate(text)
|
||||||
result.text = newText
|
result.text = newText
|
||||||
result.date = date
|
result.date = date
|
||||||
|
|
||||||
return cleanupResult(result)
|
return cleanupResult(result, prefixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getItemsFromPrefix = (text: string, prefix: string): string[] => {
|
const getItemsFromPrefix = (text: string, prefix: string): string[] => {
|
||||||
|
@ -82,8 +115,8 @@ const getItemsFromPrefix = (text: string, prefix: string): string[] => {
|
||||||
return Array.from(new Set(items))
|
return Array.from(new Set(items))
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPriority = (text: string): number | null => {
|
const getPriority = (text: string, prefix: string): number | null => {
|
||||||
const ps = getItemsFromPrefix(text, PRIORITY_PREFIX)
|
const ps = getItemsFromPrefix(text, prefix)
|
||||||
if (ps.length === 0) {
|
if (ps.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -112,11 +145,11 @@ const cleanupItemText = (text: string, items: string[], prefix: string): string
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupResult = (result: ParsedTaskText): ParsedTaskText => {
|
const cleanupResult = (result: ParsedTaskText, prefixes: Prefixes): ParsedTaskText => {
|
||||||
result.text = cleanupItemText(result.text, result.labels, LABEL_PREFIX)
|
result.text = cleanupItemText(result.text, result.labels, prefixes.label)
|
||||||
result.text = result.list !== null ? cleanupItemText(result.text, [result.list], LIST_PREFIX) : result.text
|
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)], PRIORITY_PREFIX) : result.text
|
result.text = result.priority !== null ? cleanupItemText(result.text, [String(result.priority)], prefixes.priority) : result.text
|
||||||
result.text = cleanupItemText(result.text, result.assignees, ASSIGNEE_PREFIX)
|
result.text = cleanupItemText(result.text, result.assignees, prefixes.assignee)
|
||||||
result.text = result.text.trim()
|
result.text = result.text.trim()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -77,6 +77,18 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="is-flex is-align-items-center">
|
||||||
|
<span>
|
||||||
|
{{ $t('user.settings.quickAddMagic.title') }}
|
||||||
|
</span>
|
||||||
|
<div class="select ml-2">
|
||||||
|
<select v-model="quickAddMagicMode">
|
||||||
|
<option v-for="set in quickAddMagicPrefixes" :key="set" :value="set">{{ $t(`user.settings.quickAddMagic.${set}`) }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-button
|
<x-button
|
||||||
:loading="userSettingsService.loading"
|
:loading="userSettingsService.loading"
|
||||||
|
@ -289,6 +301,8 @@ import UserSettingsService from '../../services/userSettings'
|
||||||
import UserSettingsModel from '../../models/userSettings'
|
import UserSettingsModel from '../../models/userSettings'
|
||||||
import {playSoundWhenDoneKey} from '@/helpers/playPop'
|
import {playSoundWhenDoneKey} from '@/helpers/playPop'
|
||||||
import {availableLanguages, saveLanguage, getCurrentLanguage} from '../../i18n/setup'
|
import {availableLanguages, saveLanguage, getCurrentLanguage} from '../../i18n/setup'
|
||||||
|
import {getQuickAddMagicMode, setQuickAddMagicMode} from '../../helpers/quickAddMagicMode'
|
||||||
|
import {PrefixMode} from '../../modules/parseTaskText'
|
||||||
|
|
||||||
import {mapState} from 'vuex'
|
import {mapState} from 'vuex'
|
||||||
|
|
||||||
|
@ -318,6 +332,8 @@ export default {
|
||||||
totpDisablePassword: '',
|
totpDisablePassword: '',
|
||||||
playSoundWhenDone: false,
|
playSoundWhenDone: false,
|
||||||
language: getCurrentLanguage(),
|
language: getCurrentLanguage(),
|
||||||
|
quickAddMagicMode: getQuickAddMagicMode(),
|
||||||
|
quickAddMagicPrefixes: PrefixMode,
|
||||||
|
|
||||||
settings: UserSettingsModel,
|
settings: UserSettingsModel,
|
||||||
userSettingsService: new UserSettingsService(),
|
userSettingsService: new UserSettingsService(),
|
||||||
|
@ -333,11 +349,8 @@ export default {
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.settings = this.$store.state.auth.settings
|
this.settings = this.$store.state.auth.settings
|
||||||
|
|
||||||
this.playSoundWhenDone = localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
|
this.playSoundWhenDone = localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
|
||||||
|
|
||||||
this.defaultList = this.$store.getters['lists/getListById'](this.settings.defaultListId)
|
this.defaultList = this.$store.getters['lists/getListById'](this.settings.defaultListId)
|
||||||
|
|
||||||
this.totpStatus()
|
this.totpStatus()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -445,6 +458,7 @@ export default {
|
||||||
updateSettings() {
|
updateSettings() {
|
||||||
localStorage.setItem(playSoundWhenDoneKey, this.playSoundWhenDone)
|
localStorage.setItem(playSoundWhenDoneKey, this.playSoundWhenDone)
|
||||||
saveLanguage(this.language)
|
saveLanguage(this.language)
|
||||||
|
setQuickAddMagicMode(this.quickAddMagicMode)
|
||||||
this.settings.defaultListId = this.defaultList ? this.defaultList.id : 0
|
this.settings.defaultListId = this.defaultList ? this.defaultList.id : 0
|
||||||
|
|
||||||
this.userSettingsService.update(this.settings)
|
this.userSettingsService.update(this.settings)
|
||||||
|
|
Loading…
Reference in a new issue