Task Search (#52)
Add hiding the search Add actually searching for tasks Fix jumping search button on page load Add search button Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/52
This commit is contained in:
parent
c8130bef61
commit
309f75b19d
5 changed files with 85 additions and 2 deletions
|
@ -4,7 +4,7 @@
|
||||||
<router-link :to="{ name: 'editList', params: { id: list.id } }" class="icon settings is-medium">
|
<router-link :to="{ name: 'editList', params: { id: list.id } }" class="icon settings is-medium">
|
||||||
<icon icon="cog" size="2x"/>
|
<icon icon="cog" size="2x"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
<h1>{{ list.title }}</h1>
|
<h1 :style="{ 'opacity': list.title === '' ? '0': '1' }">{{ list.title === '' ? 'Loading...': list.title}}</h1>
|
||||||
<div class="switch-view">
|
<div class="switch-view">
|
||||||
<router-link :to="{ name: 'showList', params: { id: list.id } }" :class="{'is-active': $route.params.type !== 'gantt'}">List</router-link>
|
<router-link :to="{ name: 'showList', params: { id: list.id } }" :class="{'is-active': $route.params.type !== 'gantt'}">List</router-link>
|
||||||
<router-link :to="{ name: 'showListWithType', params: { id: list.id, type: 'gantt' } }" :class="{'is-active': $route.params.type === 'gantt'}">Gantt</router-link>
|
<router-link :to="{ name: 'showListWithType', params: { id: list.id, type: 'gantt' } }" :class="{'is-active': $route.params.type === 'gantt'}">Gantt</router-link>
|
||||||
|
|
|
@ -1,5 +1,36 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="loader-container" :class="{ 'is-loading': listService.loading || taskCollectionService.loading}">
|
<div class="loader-container" :class="{ 'is-loading': listService.loading || taskCollectionService.loading}">
|
||||||
|
<div class="search">
|
||||||
|
<div class="field has-addons" :class="{ 'hidden': !showTaskSearch }">
|
||||||
|
<div class="control has-icons-left has-icons-right">
|
||||||
|
<input
|
||||||
|
class="input"
|
||||||
|
type="text"
|
||||||
|
placeholder="Search"
|
||||||
|
v-focus
|
||||||
|
v-model="searchTerm"
|
||||||
|
@keyup.enter="searchTasks"
|
||||||
|
@blur="hideSearchBar()"/>
|
||||||
|
<span class="icon is-left">
|
||||||
|
<icon icon="search"/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<button
|
||||||
|
class="button noshadow is-primary"
|
||||||
|
@click="searchTasks"
|
||||||
|
:class="{'is-loading': taskCollectionService.loading}"
|
||||||
|
:disabled="searchTerm === ''">
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="button" @click="showTaskSearch = !showTaskSearch" v-if="!showTaskSearch">
|
||||||
|
<span class="icon">
|
||||||
|
<icon icon="search"/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<form @submit.prevent="addTask()">
|
<form @submit.prevent="addTask()">
|
||||||
<div class="field is-grouped task-add">
|
<div class="field is-grouped task-add">
|
||||||
<p class="control has-icons-left is-expanded" :class="{ 'is-loading': taskService.loading}">
|
<p class="control has-icons-left is-expanded" :class="{ 'is-loading': taskService.loading}">
|
||||||
|
@ -115,6 +146,9 @@
|
||||||
isTaskEdit: false,
|
isTaskEdit: false,
|
||||||
taskEditTask: TaskModel,
|
taskEditTask: TaskModel,
|
||||||
newTaskText: '',
|
newTaskText: '',
|
||||||
|
|
||||||
|
showTaskSearch: false,
|
||||||
|
searchTerm: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -159,8 +193,11 @@
|
||||||
this.error(e, this)
|
this.error(e, this)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadTasks(page) {
|
loadTasks(page, search = '') {
|
||||||
const params = {sort_by: ['done', 'id'], order_by: ['asc', 'desc']}
|
const params = {sort_by: ['done', 'id'], order_by: ['asc', 'desc']}
|
||||||
|
if (search !== '') {
|
||||||
|
params.s = search
|
||||||
|
}
|
||||||
this.taskCollectionService.getAll({listID: this.$route.params.id}, params, page)
|
this.taskCollectionService.getAll({listID: this.$route.params.id}, params, page)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
this.$set(this, 'tasks', r)
|
this.$set(this, 'tasks', r)
|
||||||
|
@ -262,6 +299,22 @@
|
||||||
return 0
|
return 0
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
searchTasks() {
|
||||||
|
if (this.searchTerm === '') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loadTasks(1, this.searchTerm)
|
||||||
|
},
|
||||||
|
hideSearchBar() {
|
||||||
|
// This is a workaround.
|
||||||
|
// When clicking on the search button, @blur from the input is fired. If we
|
||||||
|
// would then directly hide the whole search bar directly, no click event
|
||||||
|
// from the button gets fired. To prevent this, we wait 200ms until we hide
|
||||||
|
// everything so the button has a chance of firering the search event.
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showTaskSearch = false
|
||||||
|
}, 200)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -62,6 +62,7 @@ import { faAlignLeft } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faPaperclip } from '@fortawesome/free-solid-svg-icons'
|
import { faPaperclip } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faClock } from '@fortawesome/free-regular-svg-icons'
|
import { faClock } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { faHistory } from '@fortawesome/free-solid-svg-icons'
|
import { faHistory } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||||
|
|
||||||
library.add(faSignOutAlt)
|
library.add(faSignOutAlt)
|
||||||
|
@ -98,6 +99,7 @@ library.add(faAlignLeft)
|
||||||
library.add(faPaperclip)
|
library.add(faPaperclip)
|
||||||
library.add(faClock)
|
library.add(faClock)
|
||||||
library.add(faHistory)
|
library.add(faHistory)
|
||||||
|
library.add(faSearch)
|
||||||
|
|
||||||
Vue.component('icon', FontAwesomeIcon)
|
Vue.component('icon', FontAwesomeIcon)
|
||||||
|
|
||||||
|
|
|
@ -34,3 +34,28 @@
|
||||||
padding: 10px 1em;
|
padding: 10px 1em;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search {
|
||||||
|
max-width: 300px;
|
||||||
|
margin-top: -78px;
|
||||||
|
float: right;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.field {
|
||||||
|
transition: width $transition;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -152,3 +152,6 @@
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.control.has-icons-left .icon, .control.has-icons-right .icon {
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue