feat: make taskList a composable
This commit is contained in:
parent
5a0c0eff9f
commit
281c922de1
6 changed files with 254 additions and 237 deletions
|
@ -191,7 +191,7 @@ import NamespaceService from '@/services/namespace'
|
||||||
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
import EditLabels from '@/components/tasks/partials/editLabels.vue'
|
||||||
|
|
||||||
import {objectToSnakeCase} from '@/helpers/case'
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
import {getDefaultParams} from '@/components/tasks/mixins/taskList'
|
import {getDefaultParams} from '@/composables/taskList'
|
||||||
|
|
||||||
// FIXME: merge with DEFAULT_PARAMS in taskList.js
|
// FIXME: merge with DEFAULT_PARAMS in taskList.js
|
||||||
const DEFAULT_PARAMS = {
|
const DEFAULT_PARAMS = {
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
import TaskCollectionService from '@/services/taskCollection'
|
|
||||||
|
|
||||||
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
|
||||||
export const getDefaultParams = () => ({
|
|
||||||
sort_by: ['position', 'id'],
|
|
||||||
order_by: ['asc', 'desc'],
|
|
||||||
filter_by: ['done'],
|
|
||||||
filter_value: ['false'],
|
|
||||||
filter_comparator: ['equals'],
|
|
||||||
filter_concat: 'and',
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This mixin provides a base set of methods and properties to get tasks on a list.
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
taskCollectionService: new TaskCollectionService(),
|
|
||||||
tasks: [],
|
|
||||||
|
|
||||||
currentPage: 0,
|
|
||||||
|
|
||||||
loadedList: null,
|
|
||||||
|
|
||||||
searchTerm: '',
|
|
||||||
|
|
||||||
showTaskFilter: false,
|
|
||||||
params: {...getDefaultParams()},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
// Only listen for query path changes
|
|
||||||
'$route.query': {
|
|
||||||
handler: 'loadTasksForPage',
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
'$route.path': 'loadTasksOnSavedFilter',
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async loadTasks(
|
|
||||||
page,
|
|
||||||
search = '',
|
|
||||||
params = null,
|
|
||||||
forceLoading = false,
|
|
||||||
) {
|
|
||||||
// Because this function is triggered every time on topNavigation, we're putting a condition here to only load it when we actually want to show tasks
|
|
||||||
// FIXME: This is a bit hacky -> Cleanup.
|
|
||||||
if (
|
|
||||||
this.$route.name !== 'list.list' &&
|
|
||||||
this.$route.name !== 'list.table' &&
|
|
||||||
!forceLoading
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params === null) {
|
|
||||||
params = this.params
|
|
||||||
}
|
|
||||||
|
|
||||||
if (search !== '') {
|
|
||||||
params.s = search
|
|
||||||
}
|
|
||||||
|
|
||||||
const list = {listId: parseInt(this.$route.params.listId)}
|
|
||||||
|
|
||||||
const currentList = {
|
|
||||||
id: list.listId,
|
|
||||||
params,
|
|
||||||
search,
|
|
||||||
page,
|
|
||||||
}
|
|
||||||
if (JSON.stringify(currentList) === JSON.stringify(this.loadedList) && !forceLoading) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tasks = []
|
|
||||||
this.tasks = await this.taskCollectionService.getAll(list, params, page)
|
|
||||||
this.currentPage = page
|
|
||||||
this.loadedList = JSON.parse(JSON.stringify(currentList))
|
|
||||||
},
|
|
||||||
|
|
||||||
loadTasksForPage(e) {
|
|
||||||
// The page parameter can be undefined, in the case where the user loads a new list from the side bar menu
|
|
||||||
let page = Number(e.page)
|
|
||||||
if (typeof e.page === 'undefined') {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
let search = e.search
|
|
||||||
if (typeof e.search === 'undefined') {
|
|
||||||
search = ''
|
|
||||||
}
|
|
||||||
this.initTasks(page, search)
|
|
||||||
},
|
|
||||||
loadTasksOnSavedFilter() {
|
|
||||||
if (typeof this.$route.params.listId !== 'undefined' && parseInt(this.$route.params.listId) < 0) {
|
|
||||||
this.loadTasks(1, '', null, true)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
112
src/composables/taskList.js
Normal file
112
src/composables/taskList.js
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
import { ref, watch, computed } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
import TaskCollectionService from '@/services/taskCollection'
|
||||||
|
|
||||||
|
// FIXME: merge with DEFAULT_PARAMS in filters.vue
|
||||||
|
export const getDefaultParams = () => ({
|
||||||
|
sort_by: ['position', 'id'],
|
||||||
|
order_by: ['asc', 'desc'],
|
||||||
|
filter_by: ['done'],
|
||||||
|
filter_value: ['false'],
|
||||||
|
filter_comparator: ['equals'],
|
||||||
|
filter_concat: 'and',
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mixin provides a base set of methods and properties to get tasks on a list.
|
||||||
|
*/
|
||||||
|
export function createTaskList(initTasks) {
|
||||||
|
const taskCollectionService = ref(new TaskCollectionService())
|
||||||
|
const loading = computed(() => taskCollectionService.value.loading)
|
||||||
|
const totalPages = computed(() => taskCollectionService.value.totalPages)
|
||||||
|
|
||||||
|
const tasks = ref([])
|
||||||
|
const currentPage = ref(0)
|
||||||
|
const loadedList = ref(null)
|
||||||
|
const searchTerm = ref('')
|
||||||
|
const showTaskFilter = ref(false)
|
||||||
|
const params = ref({...getDefaultParams()})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
async function loadTasks(
|
||||||
|
page = 1,
|
||||||
|
search = '',
|
||||||
|
loadParams = { ...params.value },
|
||||||
|
forceLoading = false,
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Because this function is triggered every time on topNavigation, we're putting a condition here to only load it when we actually want to show tasks
|
||||||
|
// FIXME: This is a bit hacky -> Cleanup.
|
||||||
|
if (
|
||||||
|
route.name !== 'list.list' &&
|
||||||
|
route.name !== 'list.table' &&
|
||||||
|
!forceLoading
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search !== '') {
|
||||||
|
loadParams.s = search
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = {listId: parseInt(route.params.listId)}
|
||||||
|
|
||||||
|
const currentList = {
|
||||||
|
id: list.listId,
|
||||||
|
params: loadParams,
|
||||||
|
search,
|
||||||
|
page,
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
JSON.stringify(currentList) === JSON.stringify(loadedList.value) &&
|
||||||
|
!forceLoading
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.value = []
|
||||||
|
tasks.value = await taskCollectionService.value.getAll(list, loadParams, page)
|
||||||
|
currentPage.value = page
|
||||||
|
loadedList.value = JSON.parse(JSON.stringify(currentList))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTasksForPage(query) {
|
||||||
|
const { page, search } = query
|
||||||
|
initTasks(params)
|
||||||
|
await loadTasks(
|
||||||
|
// The page parameter can be undefined, in the case where the user loads a new list from the side bar menu
|
||||||
|
typeof page === 'undefined' ? 1 : Number(page),
|
||||||
|
search,
|
||||||
|
params.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTasksOnSavedFilter() {
|
||||||
|
if (
|
||||||
|
typeof route.params.listId !== 'undefined' &&
|
||||||
|
parseInt(route.params.listId) < 0
|
||||||
|
) {
|
||||||
|
await loadTasks(1, '', null, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTaskList() {
|
||||||
|
// Only listen for query path changes
|
||||||
|
watch(() => route.query, loadTasksForPage, { immediate: true })
|
||||||
|
watch(() => route.path, loadTasksOnSavedFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
tasks,
|
||||||
|
initTaskList,
|
||||||
|
loading,
|
||||||
|
totalPages,
|
||||||
|
currentPage,
|
||||||
|
showTaskFilter,
|
||||||
|
loadTasks,
|
||||||
|
searchTerm,
|
||||||
|
params,
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,28 +8,28 @@
|
||||||
<router-link
|
<router-link
|
||||||
v-shortcut="'g l'"
|
v-shortcut="'g l'"
|
||||||
:title="$t('keyboardShortcuts.list.switchToListView')"
|
:title="$t('keyboardShortcuts.list.switchToListView')"
|
||||||
:class="{'is-active': currentListType === 'list'}"
|
:class="{'is-active': $route.name === 'list.list'}"
|
||||||
:to="{ name: 'list.list', params: { listId: listId } }">
|
:to="{ name: 'list.list', params: { listId: listId } }">
|
||||||
{{ $t('list.list.title') }}
|
{{ $t('list.list.title') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-shortcut="'g g'"
|
v-shortcut="'g g'"
|
||||||
:title="$t('keyboardShortcuts.list.switchToGanttView')"
|
:title="$t('keyboardShortcuts.list.switchToGanttView')"
|
||||||
:class="{'is-active': currentListType === 'gantt'}"
|
:class="{'is-active': $route.name === 'list.gantt'}"
|
||||||
:to="{ name: 'list.gantt', params: { listId: listId } }">
|
:to="{ name: 'list.gantt', params: { listId: listId } }">
|
||||||
{{ $t('list.gantt.title') }}
|
{{ $t('list.gantt.title') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-shortcut="'g t'"
|
v-shortcut="'g t'"
|
||||||
:title="$t('keyboardShortcuts.list.switchToTableView')"
|
:title="$t('keyboardShortcuts.list.switchToTableView')"
|
||||||
:class="{'is-active': currentListType === 'table'}"
|
:class="{'is-active': $route.name === 'list.table'}"
|
||||||
:to="{ name: 'list.table', params: { listId: listId } }">
|
:to="{ name: 'list.table', params: { listId: listId } }">
|
||||||
{{ $t('list.table.title') }}
|
{{ $t('list.table.title') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link
|
<router-link
|
||||||
v-shortcut="'g k'"
|
v-shortcut="'g k'"
|
||||||
:title="$t('keyboardShortcuts.list.switchToKanbanView')"
|
:title="$t('keyboardShortcuts.list.switchToKanbanView')"
|
||||||
:class="{'is-active': currentListType === 'kanban'}"
|
:class="{'is-active': $route.name === 'list.kanban'}"
|
||||||
:to="{ name: 'list.kanban', params: { listId: listId } }">
|
:to="{ name: 'list.kanban', params: { listId: listId } }">
|
||||||
{{ $t('list.kanban.title') }}
|
{{ $t('list.kanban.title') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
@ -69,11 +69,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentListType() {
|
|
||||||
// default: 'list',
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
|
|
||||||
// Computed property to let "listId" always have a value
|
// Computed property to let "listId" always have a value
|
||||||
listId() {
|
listId() {
|
||||||
return typeof this.$route.params.listId === 'undefined' ? 0 : this.$route.params.listId
|
return typeof this.$route.params.listId === 'undefined' ? 0 : this.$route.params.listId
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="{ 'is-loading': taskCollectionService.loading }"
|
:class="{ 'is-loading': loading }"
|
||||||
class="loader-container is-max-width-desktop list-view"
|
class="loader-container is-max-width-desktop list-view"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<x-button
|
<x-button
|
||||||
:loading="taskCollectionService.loading"
|
:loading="loading"
|
||||||
@click="searchTasks"
|
@click="searchTasks"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
>
|
>
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<nothing v-if="ctaVisible && tasks.length === 0 && !taskCollectionService.loading">
|
<nothing v-if="ctaVisible && tasks.length === 0 && !loading">
|
||||||
{{ $t('list.list.empty') }}
|
{{ $t('list.list.empty') }}
|
||||||
<a @click="focusNewTaskInput()">
|
<a @click="focusNewTaskInput()">
|
||||||
{{ $t('list.list.newTaskCta') }}
|
{{ $t('list.list.newTaskCta') }}
|
||||||
|
@ -118,7 +118,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Pagination
|
<Pagination
|
||||||
:total-pages="taskCollectionService.totalPages"
|
:total-pages="totalPages"
|
||||||
:current-page="currentPage"
|
:current-page="currentPage"
|
||||||
/>
|
/>
|
||||||
</card>
|
</card>
|
||||||
|
@ -130,13 +130,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
import TaskService from '../../../services/task'
|
import TaskService from '../../../services/task'
|
||||||
import TaskModel from '../../../models/task'
|
import TaskModel from '../../../models/task'
|
||||||
|
|
||||||
import EditTask from '../../../components/tasks/edit-task'
|
import EditTask from '../../../components/tasks/edit-task'
|
||||||
import AddTask from '../../../components/tasks/add-task'
|
import AddTask from '../../../components/tasks/add-task'
|
||||||
import SingleTaskInList from '../../../components/tasks/partials/singleTaskInList'
|
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 {saveListView} from '@/helpers/saveListView'
|
||||||
import Rights from '../../../models/constants/rights.json'
|
import Rights from '../../../models/constants/rights.json'
|
||||||
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||||
|
@ -172,8 +175,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
taskService: new TaskService(),
|
taskService: new TaskService(),
|
||||||
isTaskEdit: false,
|
|
||||||
taskEditTask: TaskModel,
|
|
||||||
ctaVisible: false,
|
ctaVisible: false,
|
||||||
showTaskSearch: false,
|
showTaskSearch: false,
|
||||||
|
|
||||||
|
@ -184,9 +185,6 @@ export default {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [
|
|
||||||
taskList,
|
|
||||||
],
|
|
||||||
components: {
|
components: {
|
||||||
Nothing,
|
Nothing,
|
||||||
FilterPopup,
|
FilterPopup,
|
||||||
|
@ -199,15 +197,28 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
const taskEditTask = ref(TaskModel)
|
||||||
showTaskDetail: useShowModal(),
|
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
|
// Save the current list view to local storage
|
||||||
// We use local storage and not vuex here to make it persistent across reloads.
|
// 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: {
|
computed: {
|
||||||
isAlphabeticalSorting() {
|
isAlphabeticalSorting() {
|
||||||
|
@ -247,17 +258,11 @@ export default {
|
||||||
// When clicking on the search button, @blur from the input is fired. If we
|
// 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
|
// 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
|
// 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(() => {
|
setTimeout(() => {
|
||||||
this.showTaskSearch = false
|
this.showTaskSearch = false
|
||||||
}, 200)
|
}, 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() {
|
focusNewTaskInput() {
|
||||||
this.$refs.newTaskInput.$refs.newTaskInput.focus()
|
this.$refs.newTaskInput.$refs.newTaskInput.focus()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<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="filter-container">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<popup>
|
<popup>
|
||||||
|
@ -169,7 +169,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Pagination
|
<Pagination
|
||||||
:total-pages="taskCollectionService.totalPages"
|
:total-pages="totalPages"
|
||||||
:current-page="currentPage"
|
:current-page="currentPage"
|
||||||
/>
|
/>
|
||||||
</card>
|
</card>
|
||||||
|
@ -185,9 +185,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<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 Done from '@/components/misc/Done.vue'
|
||||||
import User from '@/components/misc/user'
|
import User from '@/components/misc/user'
|
||||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel'
|
import PriorityLabel from '@/components/tasks/partials/priorityLabel'
|
||||||
|
@ -200,26 +201,7 @@ import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||||
import Pagination from '@/components/misc/pagination.vue'
|
import Pagination from '@/components/misc/pagination.vue'
|
||||||
import Popup from '@/components/misc/popup'
|
import Popup from '@/components/misc/popup'
|
||||||
|
|
||||||
export default {
|
const ACTIVE_COLUMNS_DEFAULT = {
|
||||||
name: 'Table',
|
|
||||||
components: {
|
|
||||||
Popup,
|
|
||||||
Done,
|
|
||||||
FilterPopup,
|
|
||||||
Sort,
|
|
||||||
Fancycheckbox,
|
|
||||||
DateTableCell,
|
|
||||||
Labels,
|
|
||||||
PriorityLabel,
|
|
||||||
User,
|
|
||||||
Pagination,
|
|
||||||
},
|
|
||||||
mixins: [
|
|
||||||
taskList,
|
|
||||||
],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
activeColumns: {
|
|
||||||
id: true,
|
id: true,
|
||||||
done: true,
|
done: true,
|
||||||
title: true,
|
title: true,
|
||||||
|
@ -233,56 +215,50 @@ export default {
|
||||||
created: false,
|
created: false,
|
||||||
updated: false,
|
updated: false,
|
||||||
createdBy: false,
|
createdBy: false,
|
||||||
},
|
}
|
||||||
sortBy: {
|
|
||||||
|
const SORT_BY_DEFAULT = {
|
||||||
id: 'desc',
|
id: 'desc',
|
||||||
},
|
}
|
||||||
}
|
|
||||||
},
|
function useSavedView(activeColumns, sortBy) {
|
||||||
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')
|
const savedShowColumns = localStorage.getItem('tableViewColumns')
|
||||||
if (savedShowColumns !== null) {
|
if (savedShowColumns !== null) {
|
||||||
this.activeColumns = JSON.parse(savedShowColumns)
|
Object.assign(activeColumns, JSON.parse(savedShowColumns))
|
||||||
}
|
}
|
||||||
|
|
||||||
const savedSortBy = localStorage.getItem('tableViewSortBy')
|
const savedSortBy = localStorage.getItem('tableViewSortBy')
|
||||||
if (savedSortBy !== null) {
|
if (savedSortBy !== null) {
|
||||||
this.sortBy = JSON.parse(savedSortBy)
|
sortBy.value = JSON.parse(savedSortBy)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.params.filter_by = []
|
export default defineComponent({
|
||||||
this.params.filter_value = []
|
name: 'Table',
|
||||||
this.params.filter_comparator = []
|
components: {
|
||||||
|
Popup,
|
||||||
this.initTasks(1)
|
Done,
|
||||||
|
FilterPopup,
|
||||||
|
Sort,
|
||||||
|
Fancycheckbox,
|
||||||
|
DateTableCell,
|
||||||
|
Labels,
|
||||||
|
PriorityLabel,
|
||||||
|
User,
|
||||||
|
Pagination,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
// Save the current list view to local storage
|
const activeColumns = reactive({ ...ACTIVE_COLUMNS_DEFAULT })
|
||||||
// We use local storage and not vuex here to make it persistent across reloads.
|
const sortBy = ref({ ...SORT_BY_DEFAULT })
|
||||||
const route = useRoute()
|
|
||||||
console.log(route.value)
|
useSavedView(activeColumns, sortBy)
|
||||||
saveListView(route.value.params.listId, route.value.name)
|
|
||||||
},
|
function beforeLoad(params) {
|
||||||
methods: {
|
|
||||||
initTasks(page, search = '') {
|
|
||||||
// This makes sure an id sort order is always sorted last.
|
// 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
|
// 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.
|
// precedence over everything else, making any other sort columns pretty useless.
|
||||||
const sortKeys = Object.keys(this.sortBy)
|
|
||||||
let hasIdFilter = false
|
let hasIdFilter = false
|
||||||
|
const sortKeys = Object.keys(sortBy.value)
|
||||||
for (const s of sortKeys) {
|
for (const s of sortKeys) {
|
||||||
if (s === 'id') {
|
if (s === 'id') {
|
||||||
sortKeys.splice(s, 1)
|
sortKeys.splice(s, 1)
|
||||||
|
@ -293,39 +269,70 @@ export default {
|
||||||
if (hasIdFilter) {
|
if (hasIdFilter) {
|
||||||
sortKeys.push('id')
|
sortKeys.push('id')
|
||||||
}
|
}
|
||||||
|
params.value.sort_by = sortKeys
|
||||||
const params = this.params
|
params.value.order_by = sortKeys.map(s => sortBy.value[s])
|
||||||
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]
|
|
||||||
if (typeof order === 'undefined' || order === 'none') {
|
|
||||||
this.sortBy[property] = 'desc'
|
|
||||||
} else if (order === 'desc') {
|
|
||||||
this.sortBy[property] = 'asc'
|
|
||||||
} else {
|
|
||||||
delete this.sortBy[property]
|
|
||||||
}
|
}
|
||||||
this.initTasks(this.currentPage, this.searchTerm)
|
|
||||||
|
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') {
|
||||||
|
sortBy.value[property] = 'desc'
|
||||||
|
} else if (order === 'desc') {
|
||||||
|
sortBy.value[property] = 'asc'
|
||||||
|
} else {
|
||||||
|
delete sortBy.value[property]
|
||||||
|
}
|
||||||
|
beforeLoad(taskList.currentPage.value, taskList.searchTerm.value)
|
||||||
// Save the order to be able to retrieve them later
|
// Save the order to be able to retrieve them later
|
||||||
localStorage.setItem('tableViewSortBy', JSON.stringify(this.sortBy))
|
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,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
saveTaskColumns() {
|
})
|
||||||
localStorage.setItem('tableViewColumns', JSON.stringify(this.activeColumns))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.table-view {
|
.table {
|
||||||
.table {
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
|
@ -337,7 +344,6 @@ export default {
|
||||||
.user {
|
.user {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.columns-filter {
|
.columns-filter {
|
||||||
|
|
Loading…
Reference in a new issue