This repository has been archived on 2024-02-08. You can view files and clone it, but cannot push or open issues or pull requests.
frontend/src/components/quick-actions/quick-actions.vue

222 lines
4.7 KiB
Vue
Raw Normal View History

2021-05-30 11:44:43 +00:00
<template>
2021-05-30 14:28:21 +00:00
<modal v-if="active" class="quick-actions">
<div class="card">
2021-05-30 14:49:02 +00:00
<div class="action-input" :class="{'has-active-cmd': selectedCmd !== null}">
<div class="active-cmd tag" v-if="selectedCmd !== null">
{{ selectedCmd.title }}
2021-05-30 14:46:07 +00:00
</div>
<input
v-focus
class="input"
:class="{'is-loading': loading}"
v-model="query"
:placeholder="placeholder"
@keyup="search"
ref="searchInput"
@keydown.down.prevent="() => select(0, 0)"
2021-05-30 14:49:02 +00:00
@keyup.prevent.delete="() => selectedCmd = null"
2021-05-30 14:46:07 +00:00
/>
</div>
2021-05-30 14:28:21 +00:00
<div class="results">
<div v-for="(r, k) in results" :key="k" class="result">
<span class="result-title">
{{ r.title }}
</span>
<div class="result-items">
<button
v-for="(i, key) in r.items"
:key="key"
:ref="`result-${k}_${key}`"
@keydown.up.prevent="() => select(k, key - 1)"
@keydown.down.prevent="() => select(k, key + 1)"
@click.prevent.stop="() => doAction(r.type, i)"
@keyup.prevent.enter="() => doAction(r.type, i)"
2021-05-30 14:30:11 +00:00
@keyup.prevent.esc="() => $refs.searchInput.focus()"
2021-05-30 14:28:21 +00:00
>
{{ i.title }}
</button>
</div>
</div>
</div>
2021-05-30 11:44:43 +00:00
</div>
</modal>
</template>
<script>
2021-05-30 13:02:56 +00:00
import TaskService from '@/services/task'
const TYPE_LIST = 'list'
const TYPE_TASK = 'task'
2021-05-30 14:49:02 +00:00
const TYPE_CMD = 'cmd'
2021-05-30 14:28:21 +00:00
const TYPE_TEAM = 'team'
2021-05-30 13:02:56 +00:00
2021-05-30 14:49:02 +00:00
const CMD_NEW_TASK = 'newTask'
const CMD_NEW_LIST = 'newList'
const CMD_NEW_NAMESPACE = 'newNamespace'
const CMD_NEW_TEAM = 'newTeam'
2021-05-30 14:46:07 +00:00
2021-05-30 11:44:43 +00:00
export default {
name: 'quick-actions',
data() {
return {
2021-05-30 12:25:14 +00:00
query: '',
2021-05-30 14:49:02 +00:00
availableCmds: [
2021-05-30 13:02:56 +00:00
{
title: 'New task',
2021-05-30 14:49:02 +00:00
action: CMD_NEW_TASK,
2021-05-30 13:02:56 +00:00
},
{
title: 'New list',
2021-05-30 14:49:02 +00:00
action: CMD_NEW_LIST,
2021-05-30 13:02:56 +00:00
},
{
title: 'New namespace',
2021-05-30 14:49:02 +00:00
action: CMD_NEW_NAMESPACE,
2021-05-30 13:02:56 +00:00
},
{
title: 'New Team',
2021-05-30 14:49:02 +00:00
action: CMD_NEW_TEAM,
2021-05-30 13:02:56 +00:00
},
],
2021-05-30 14:49:02 +00:00
selectedCmd: null,
2021-05-30 14:46:07 +00:00
2021-05-30 13:02:56 +00:00
foundTasks: [],
taskSearchTimeout: null,
taskService: null,
foundTeams: [],
2021-05-30 11:44:43 +00:00
}
},
computed: {
active: () => true, // TODO: use state + keyboard shortcut
2021-05-30 12:25:14 +00:00
results() {
2021-05-30 13:02:56 +00:00
const lists = (Object.values(this.$store.state.lists).filter(l => {
2021-05-30 12:25:14 +00:00
return l.title.toLowerCase().includes(this.query.toLowerCase())
2021-05-30 13:02:56 +00:00
}) ?? [])
2021-05-30 14:49:02 +00:00
const cmds = this.availableCmds
2021-05-30 14:28:21 +00:00
.filter(a => a.title.toLowerCase().includes(this.query.toLowerCase()))
2021-05-30 13:02:56 +00:00
2021-05-30 14:28:21 +00:00
return [
{
2021-05-30 14:49:02 +00:00
type: TYPE_CMD,
title: 'Commands',
items: cmds,
2021-05-30 14:28:21 +00:00
},
{
type: TYPE_TASK,
title: 'Tasks',
items: this.foundTasks,
},
{
type: TYPE_LIST,
title: 'Lists',
items: lists,
},
{
type: TYPE_TEAM,
title: 'Teams',
items: this.foundTeams,
},
].filter(i => i.items.length > 0)
2021-05-30 11:44:43 +00:00
},
nothing() {
2021-05-30 12:25:14 +00:00
return this.search === '' || Object.keys(this.results).length === 0
2021-05-30 11:44:43 +00:00
},
2021-05-30 14:28:21 +00:00
loading() {
return this.taskService.loading
},
2021-05-30 14:46:07 +00:00
placeholder() {
2021-05-30 14:49:02 +00:00
if (this.selectedCmd !== null) {
switch (this.selectedCmd.action) {
case CMD_NEW_TASK:
2021-05-30 14:46:07 +00:00
return 'Enter the title of the new task...'
2021-05-30 14:49:02 +00:00
case CMD_NEW_LIST:
2021-05-30 14:46:07 +00:00
return 'Enter the title of the new list...'
2021-05-30 14:49:02 +00:00
case CMD_NEW_TEAM:
2021-05-30 14:46:07 +00:00
return 'Enter the title of the new team...'
2021-05-30 14:49:02 +00:00
case CMD_NEW_NAMESPACE:
2021-05-30 14:46:07 +00:00
return 'Enter the title of the new namespace...'
}
}
return 'Type a command or search...'
},
2021-05-30 11:44:43 +00:00
},
2021-05-30 13:02:56 +00:00
created() {
this.taskService = new TaskService()
},
2021-05-30 11:44:43 +00:00
methods: {
2021-05-30 14:28:21 +00:00
search() {
this.searchTasks()
2021-05-30 13:02:56 +00:00
},
2021-05-30 14:28:21 +00:00
searchTasks() {
if (this.query === '') {
return
}
2021-05-30 13:02:56 +00:00
if (this.taskSearchTimeout !== null) {
clearTimeout(this.taskSearchTimeout)
this.taskSearchTimeout = null
}
this.taskSearchTimeout = setTimeout(() => {
2021-05-30 14:28:21 +00:00
this.taskService.getAll({}, {s: this.query})
2021-05-30 13:02:56 +00:00
.then(r => {
r = r.map(t => {
t.type = TYPE_TASK
return t
})
this.$set(this, 'foundTasks', r)
})
}, 150)
2021-05-30 12:25:14 +00:00
},
2021-05-30 14:46:07 +00:00
doAction(type, item) {
2021-05-30 14:28:21 +00:00
switch (type) {
2021-05-30 13:02:56 +00:00
case TYPE_LIST:
2021-05-30 14:46:07 +00:00
this.$router.push({name: 'list.index', params: {listId: item.id}})
2021-05-30 13:02:56 +00:00
break
case TYPE_TASK:
2021-05-30 14:46:07 +00:00
this.$router.push({name: 'task.detail', params: {id: item.id}})
2021-05-30 13:02:56 +00:00
break
2021-05-30 14:49:02 +00:00
case TYPE_CMD:
2021-05-30 14:46:07 +00:00
this.query = ''
2021-05-30 14:49:02 +00:00
this.selectedCmd = item
2021-05-30 14:46:07 +00:00
this.$refs.searchInput.focus()
2021-05-30 13:02:56 +00:00
break
}
2021-05-30 12:25:14 +00:00
},
2021-05-30 14:28:21 +00:00
select(parentIndex, index) {
if (index < 0 && parentIndex === 0) {
this.$refs.searchInput.focus()
return
}
if (index < 0) {
2021-05-30 14:46:07 +00:00
parentIndex--
2021-05-30 14:28:21 +00:00
index = this.results[parentIndex].items.length - 1
}
let elems = this.$refs[`result-${parentIndex}_${index}`]
if (this.results[parentIndex].items.length === index) {
elems = this.$refs[`result-${parentIndex + 1}_0`]
}
if (typeof elems === 'undefined' || elems.length === 0) {
return
}
if (Array.isArray(elems)) {
elems[0].focus()
return
}
elems.focus()
},
2021-05-30 11:44:43 +00:00
},
}
</script>