1
0

feat: make taskList a composable

This commit is contained in:
Dominik Pschenitschni
2021-10-25 22:17:23 +02:00
parent 5a0c0eff9f
commit 281c922de1
6 changed files with 254 additions and 237 deletions

View File

@ -8,28 +8,28 @@
<router-link
v-shortcut="'g l'"
:title="$t('keyboardShortcuts.list.switchToListView')"
:class="{'is-active': currentListType === 'list'}"
:class="{'is-active': $route.name === 'list.list'}"
:to="{ name: 'list.list', params: { listId: listId } }">
{{ $t('list.list.title') }}
</router-link>
<router-link
v-shortcut="'g g'"
:title="$t('keyboardShortcuts.list.switchToGanttView')"
:class="{'is-active': currentListType === 'gantt'}"
:class="{'is-active': $route.name === 'list.gantt'}"
:to="{ name: 'list.gantt', params: { listId: listId } }">
{{ $t('list.gantt.title') }}
</router-link>
<router-link
v-shortcut="'g t'"
:title="$t('keyboardShortcuts.list.switchToTableView')"
:class="{'is-active': currentListType === 'table'}"
:class="{'is-active': $route.name === 'list.table'}"
:to="{ name: 'list.table', params: { listId: listId } }">
{{ $t('list.table.title') }}
</router-link>
<router-link
v-shortcut="'g k'"
:title="$t('keyboardShortcuts.list.switchToKanbanView')"
:class="{'is-active': currentListType === 'kanban'}"
:class="{'is-active': $route.name === 'list.kanban'}"
:to="{ name: 'list.kanban', params: { listId: listId } }">
{{ $t('list.kanban.title') }}
</router-link>
@ -69,11 +69,6 @@ export default {
},
},
computed: {
currentListType() {
// default: 'list',
return ''
},
// Computed property to let "listId" always have a value
listId() {
return typeof this.$route.params.listId === 'undefined' ? 0 : this.$route.params.listId

View File

@ -1,6 +1,6 @@
<template>
<div
:class="{ 'is-loading': taskCollectionService.loading }"
:class="{ 'is-loading': loading }"
class="loader-container is-max-width-desktop list-view"
>
<div
@ -26,7 +26,7 @@
</div>
<div class="control">
<x-button
:loading="taskCollectionService.loading"
:loading="loading"
@click="searchTasks"
:shadow="false"
>
@ -59,7 +59,7 @@
/>
</template>
<nothing v-if="ctaVisible && tasks.length === 0 && !taskCollectionService.loading">
<nothing v-if="ctaVisible && tasks.length === 0 && !loading">
{{ $t('list.list.empty') }}
<a @click="focusNewTaskInput()">
{{ $t('list.list.newTaskCta') }}
@ -117,8 +117,8 @@
/>
</div>
<Pagination
:total-pages="taskCollectionService.totalPages"
<Pagination
:total-pages="totalPages"
:current-page="currentPage"
/>
</card>
@ -130,13 +130,16 @@
</template>
<script>
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import TaskService from '../../../services/task'
import TaskModel from '../../../models/task'
import EditTask from '../../../components/tasks/edit-task'
import AddTask from '../../../components/tasks/add-task'
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList'
import taskList from '../../../components/tasks/mixins/taskList'
import { createTaskList } from '@/composables/taskList'
import {saveListView} from '@/helpers/saveListView'
import Rights from '../../../models/constants/rights.json'
import FilterPopup from '@/components/list/partials/filter-popup.vue'
@ -172,8 +175,6 @@ export default {
data() {
return {
taskService: new TaskService(),
isTaskEdit: false,
taskEditTask: TaskModel,
ctaVisible: false,
showTaskSearch: false,
@ -184,9 +185,6 @@ export default {
},
}
},
mixins: [
taskList,
],
components: {
Nothing,
FilterPopup,
@ -199,15 +197,28 @@ export default {
},
setup() {
return {
showTaskDetail: useShowModal(),
}
},
const taskEditTask = ref(TaskModel)
const isTaskEdit = ref(false)
// This function initializes the tasks page and loads the first page of tasks
function beforeLoad() {
taskEditTask.value = null
isTaskEdit.value = false
}
const taskList = createTaskList(beforeLoad)
created() {
// Save the current list view to local storage
// We use local storage and not vuex here to make it persistent across reloads.
saveListView(this.$route.params.listId, this.$route.name)
const route = useRoute()
saveListView(route.params.listId, route.name)
return {
taskEditTask,
isTaskEdit,
showTaskDetail: useShowModal(),
...taskList,
}
},
computed: {
isAlphabeticalSorting() {
@ -247,17 +258,11 @@ export default {
// 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.
// everything so the button has a chance of firing the search event.
setTimeout(() => {
this.showTaskSearch = false
}, 200)
},
// This function initializes the tasks page and loads the first page of tasks
initTasks(page, search = '') {
this.taskEditTask = null
this.isTaskEdit = false
this.loadTasks(page, search)
},
focusNewTaskInput() {
this.$refs.newTaskInput.$refs.newTaskInput.focus()
},

View File

@ -1,5 +1,5 @@
<template>
<div :class="{'is-loading': taskCollectionService.loading}" class="table-view loader-container">
<div :class="{'is-loading': loading}" class="table-view loader-container">
<div class="filter-container">
<div class="items">
<popup>
@ -169,7 +169,7 @@
</div>
<Pagination
:total-pages="taskCollectionService.totalPages"
:total-pages="totalPages"
:current-page="currentPage"
/>
</card>
@ -185,9 +185,10 @@
</template>
<script>
import {useRoute} from 'vue-router'
import { defineComponent, ref, reactive, computed, toRaw } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import taskList from '@/components/tasks/mixins/taskList'
import { createTaskList } from '@/composables/taskList'
import Done from '@/components/misc/Done.vue'
import User from '@/components/misc/user'
import PriorityLabel from '@/components/tasks/partials/priorityLabel'
@ -200,7 +201,39 @@ import FilterPopup from '@/components/list/partials/filter-popup.vue'
import Pagination from '@/components/misc/pagination.vue'
import Popup from '@/components/misc/popup'
export default {
const ACTIVE_COLUMNS_DEFAULT = {
id: true,
done: true,
title: true,
priority: false,
labels: true,
assignees: true,
dueDate: true,
startDate: false,
endDate: false,
percentDone: false,
created: false,
updated: false,
createdBy: false,
}
const SORT_BY_DEFAULT = {
id: 'desc',
}
function useSavedView(activeColumns, sortBy) {
const savedShowColumns = localStorage.getItem('tableViewColumns')
if (savedShowColumns !== null) {
Object.assign(activeColumns, JSON.parse(savedShowColumns))
}
const savedSortBy = localStorage.getItem('tableViewSortBy')
if (savedSortBy !== null) {
sortBy.value = JSON.parse(savedSortBy)
}
}
export default defineComponent({
name: 'Table',
components: {
Popup,
@ -214,75 +247,18 @@ export default {
User,
Pagination,
},
mixins: [
taskList,
],
data() {
return {
activeColumns: {
id: true,
done: true,
title: true,
priority: false,
labels: true,
assignees: true,
dueDate: true,
startDate: false,
endDate: false,
percentDone: false,
created: false,
updated: false,
createdBy: false,
},
sortBy: {
id: 'desc',
},
}
},
computed: {
taskDetailRoutes() {
const taskDetailRoutes = {}
this.tasks.forEach(({id}) => {
taskDetailRoutes[id] = {
name: 'task.detail',
params: { id },
state: { backgroundView: this.$router.currentRoute.value.fullPath },
}
})
return taskDetailRoutes
},
},
created() {
const savedShowColumns = localStorage.getItem('tableViewColumns')
if (savedShowColumns !== null) {
this.activeColumns = JSON.parse(savedShowColumns)
}
const savedSortBy = localStorage.getItem('tableViewSortBy')
if (savedSortBy !== null) {
this.sortBy = JSON.parse(savedSortBy)
}
this.params.filter_by = []
this.params.filter_value = []
this.params.filter_comparator = []
this.initTasks(1)
},
setup() {
// Save the current list view to local storage
// We use local storage and not vuex here to make it persistent across reloads.
const route = useRoute()
console.log(route.value)
saveListView(route.value.params.listId, route.value.name)
},
methods: {
initTasks(page, search = '') {
const activeColumns = reactive({ ...ACTIVE_COLUMNS_DEFAULT })
const sortBy = ref({ ...SORT_BY_DEFAULT })
useSavedView(activeColumns, sortBy)
function beforeLoad(params) {
// This makes sure an id sort order is always sorted last.
// When tasks would be sorted first by id and then by whatever else was specified, the id sort takes
// precedence over everything else, making any other sort columns pretty useless.
const sortKeys = Object.keys(this.sortBy)
let hasIdFilter = false
const sortKeys = Object.keys(sortBy.value)
for (const s of sortKeys) {
if (s === 'id') {
sortKeys.splice(s, 1)
@ -293,50 +269,80 @@ export default {
if (hasIdFilter) {
sortKeys.push('id')
}
const params = this.params
params.sort_by = []
params.order_by = []
sortKeys.map(s => {
params.sort_by.push(s)
params.order_by.push(this.sortBy[s])
})
this.loadTasks(page, search, params)
},
sort(property) {
const order = this.sortBy[property]
params.value.sort_by = sortKeys
params.value.order_by = sortKeys.map(s => sortBy.value[s])
}
const taskList = createTaskList(beforeLoad)
Object.assign(taskList.params.value, {
filter_by: [],
filter_value: [],
filter_comparator: [],
})
const router = useRouter()
const taskDetailRoutes = computed(() => Object.fromEntries(
taskList.tasks.value.map(({id}) => ([
id,
{
name: 'task.detail',
params: { id },
state: { backgroundView: router.currentRoute.value.fullPath },
},
])),
))
// Save the current list view to local storage
// We use local storage and not vuex here to make it persistent across reloads.
const route = useRoute()
saveListView(route.params.listId, route.name)
function sort(property) {
const order = sortBy.value[property]
if (typeof order === 'undefined' || order === 'none') {
this.sortBy[property] = 'desc'
sortBy.value[property] = 'desc'
} else if (order === 'desc') {
this.sortBy[property] = 'asc'
sortBy.value[property] = 'asc'
} else {
delete this.sortBy[property]
delete sortBy.value[property]
}
this.initTasks(this.currentPage, this.searchTerm)
beforeLoad(taskList.currentPage.value, taskList.searchTerm.value)
// Save the order to be able to retrieve them later
localStorage.setItem('tableViewSortBy', JSON.stringify(this.sortBy))
},
saveTaskColumns() {
localStorage.setItem('tableViewColumns', JSON.stringify(this.activeColumns))
},
localStorage.setItem('tableViewSortBy', JSON.stringify(sortBy.value))
}
function saveTaskColumns() {
localStorage.setItem('tableViewColumns', JSON.stringify(toRaw(activeColumns)))
}
taskList.initTaskList()
return {
...taskList,
sortBy,
activeColumns,
sort,
saveTaskColumns,
taskDetailRoutes,
}
},
}
})
</script>
<style lang="scss" scoped>
.table-view {
.table {
background: transparent;
overflow-x: auto;
overflow-y: hidden;
.table {
background: transparent;
overflow-x: auto;
overflow-y: hidden;
th {
white-space: nowrap;
}
th {
white-space: nowrap;
}
.user {
margin: 0;
}
.user {
margin: 0;
}
}