feat: provide listId prop via router
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ListWrapper class="list-gantt">
|
||||
<ListWrapper class="list-gantt" :list-id="props.listId" viewName="gantt">
|
||||
<template #header>
|
||||
<div class="gantt-options p-4">
|
||||
<fancycheckbox class="is-block" v-model="showTaskswithoutDates">
|
||||
@ -54,7 +54,7 @@
|
||||
:date-from="dateFrom"
|
||||
:date-to="dateTo"
|
||||
:day-width="dayWidth"
|
||||
:list-id="Number($route.params.listId)"
|
||||
:list-id="props.listId"
|
||||
:show-taskswithout-dates="showTaskswithoutDates"
|
||||
/>
|
||||
|
||||
@ -64,16 +64,23 @@
|
||||
</ListWrapper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import flatPickr from 'vue-flatpickr-component'
|
||||
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
import ListWrapper from './ListWrapper'
|
||||
import GanttChart from '@/components/tasks/gantt-component'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox'
|
||||
import ListWrapper from './ListWrapper.vue'
|
||||
import GanttChart from '@/components/tasks/gantt-component.vue'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
|
||||
const props = defineProps({
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const DEFAULT_DAY_COUNT = 35
|
||||
|
||||
@ -85,7 +92,7 @@ const dateFrom = ref(new Date((new Date()).setDate(now.value.getDate() - 15)))
|
||||
const dateTo = ref(new Date((new Date()).setDate(now.value.getDate() + 30)))
|
||||
|
||||
const {t} = useI18n()
|
||||
const {store} = useStore()
|
||||
const store = useStore()
|
||||
const flatPickerConfig = computed(() => ({
|
||||
altFormat: t('date.altFormatShort'),
|
||||
altInput: true,
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ListWrapper class="list-kanban">
|
||||
<ListWrapper class="list-kanban" :list-id="listId" viewName="kanban">
|
||||
<template #header>
|
||||
<div class="filter-container" v-if="isSavedFilter">
|
||||
<div class="items">
|
||||
@ -263,6 +263,14 @@ export default {
|
||||
FilterPopup,
|
||||
draggable,
|
||||
},
|
||||
|
||||
props: {
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
taskContainerRefs: {},
|
||||
@ -310,7 +318,7 @@ export default {
|
||||
},
|
||||
loadBucketParameter() {
|
||||
return {
|
||||
listId: this.$route.params.listId,
|
||||
listId: this.listId,
|
||||
params: this.params,
|
||||
}
|
||||
},
|
||||
@ -350,16 +358,11 @@ export default {
|
||||
|
||||
methods: {
|
||||
loadBuckets() {
|
||||
// Prevent trying to load buckets if the task popup view is active
|
||||
if (this.$route.name !== 'list.kanban') {
|
||||
return
|
||||
}
|
||||
|
||||
const {listId, params} = this.loadBucketParameter
|
||||
|
||||
this.collapsedBuckets = getCollapsedBucketState(listId)
|
||||
|
||||
console.debug(`Loading buckets, loadedListId = ${this.loadedListId}, $route.params =`, this.$route.params)
|
||||
console.debug(`Loading buckets, loadedListId = ${this.loadedListId}, $attrs = ${this.$attrs} $route.params =`, this.$route.params)
|
||||
|
||||
this.$store.dispatch('kanban/loadBucketsForList', {listId, params})
|
||||
},
|
||||
@ -434,7 +437,7 @@ export default {
|
||||
const task = await this.$store.dispatch('tasks/createNewTask', {
|
||||
title: this.newTaskText,
|
||||
bucketId,
|
||||
listId: this.$route.params.listId,
|
||||
listId: this.listId,
|
||||
})
|
||||
this.newTaskText = ''
|
||||
this.$store.commit('kanban/addTaskToBucket', task)
|
||||
@ -456,7 +459,7 @@ export default {
|
||||
|
||||
const newBucket = new BucketModel({
|
||||
title: this.newBucketTitle,
|
||||
listId: parseInt(this.$route.params.listId),
|
||||
listId: this.listId,
|
||||
})
|
||||
|
||||
await this.$store.dispatch('kanban/createBucket', newBucket)
|
||||
@ -476,7 +479,7 @@ export default {
|
||||
async deleteBucket() {
|
||||
const bucket = new BucketModel({
|
||||
id: this.bucketToDelete,
|
||||
listId: parseInt(this.$route.params.listId),
|
||||
listId: this.listId,
|
||||
})
|
||||
|
||||
try {
|
||||
@ -564,7 +567,7 @@ export default {
|
||||
|
||||
collapseBucket(bucket) {
|
||||
this.collapsedBuckets[bucket.id] = true
|
||||
saveCollapsedBucketState(this.$route.params.listId, this.collapsedBuckets)
|
||||
saveCollapsedBucketState(this.listId, this.collapsedBuckets)
|
||||
},
|
||||
unCollapseBucket(bucket) {
|
||||
if (!this.collapsedBuckets[bucket.id]) {
|
||||
@ -572,7 +575,7 @@ export default {
|
||||
}
|
||||
|
||||
this.collapsedBuckets[bucket.id] = false
|
||||
saveCollapsedBucketState(this.$route.params.listId, this.collapsedBuckets)
|
||||
saveCollapsedBucketState(this.listId, this.collapsedBuckets)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ListWrapper class="list-list">
|
||||
<ListWrapper class="list-list" :list-id="listId" viewName="list">
|
||||
<template #header>
|
||||
<div
|
||||
class="filter-container"
|
||||
@ -132,9 +132,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import { ref, toRef, defineComponent } from 'vue'
|
||||
|
||||
import ListWrapper from './ListWrapper'
|
||||
import ListWrapper from './ListWrapper.vue'
|
||||
import EditTask from '@/components/tasks/edit-task'
|
||||
import AddTask from '@/components/tasks/add-task'
|
||||
import SingleTaskInList from '@/components/tasks/partials/singleTaskInList'
|
||||
@ -167,8 +167,16 @@ function sortTasks(tasks) {
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'List',
|
||||
|
||||
props: {
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
ctaVisible: false,
|
||||
@ -192,19 +200,17 @@ export default {
|
||||
Pagination,
|
||||
},
|
||||
|
||||
setup() {
|
||||
setup(props) {
|
||||
const taskEditTask = ref(null)
|
||||
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
|
||||
}
|
||||
// function beforeLoad() {
|
||||
// taskEditTask.value = null
|
||||
// isTaskEdit.value = false
|
||||
// }
|
||||
|
||||
const taskList = useTaskList(beforeLoad)
|
||||
|
||||
taskList.initTaskList()
|
||||
const taskList = useTaskList(toRef(props, 'listId'))
|
||||
|
||||
return {
|
||||
taskEditTask,
|
||||
@ -312,7 +318,7 @@ export default {
|
||||
this.tasks[e.newIndex] = updatedTask
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ListWrapper class="list-table">
|
||||
<ListWrapper class="list-table" :list-id="listId" viewName="table">
|
||||
<template #header>
|
||||
<div class="filter-container">
|
||||
<div class="items">
|
||||
@ -15,50 +15,47 @@
|
||||
</template>
|
||||
<template #content="{isOpen}">
|
||||
<card class="columns-filter" :class="{'is-open': isOpen}">
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.id">#</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.done">
|
||||
<fancycheckbox v-model="activeColumns.id">#</fancycheckbox>
|
||||
<fancycheckbox v-model="activeColumns.done">
|
||||
{{ $t('task.attributes.done') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.title">
|
||||
<fancycheckbox v-model="activeColumns.title">
|
||||
{{ $t('task.attributes.title') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.priority">
|
||||
<fancycheckbox v-model="activeColumns.priority">
|
||||
{{ $t('task.attributes.priority') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.labels">
|
||||
<fancycheckbox v-model="activeColumns.labels">
|
||||
{{ $t('task.attributes.labels') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.assignees">
|
||||
<fancycheckbox v-model="activeColumns.assignees">
|
||||
{{ $t('task.attributes.assignees') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.dueDate">
|
||||
<fancycheckbox v-model="activeColumns.dueDate">
|
||||
{{ $t('task.attributes.dueDate') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.startDate">
|
||||
<fancycheckbox v-model="activeColumns.startDate">
|
||||
{{ $t('task.attributes.startDate') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.endDate">
|
||||
<fancycheckbox v-model="activeColumns.endDate">
|
||||
{{ $t('task.attributes.endDate') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.percentDone">
|
||||
<fancycheckbox v-model="activeColumns.percentDone">
|
||||
{{ $t('task.attributes.percentDone') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.created">
|
||||
<fancycheckbox v-model="activeColumns.created">
|
||||
{{ $t('task.attributes.created') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.updated">
|
||||
<fancycheckbox v-model="activeColumns.updated">
|
||||
{{ $t('task.attributes.updated') }}
|
||||
</fancycheckbox>
|
||||
<fancycheckbox @change="saveTaskColumns" v-model="activeColumns.createdBy">
|
||||
<fancycheckbox v-model="activeColumns.createdBy">
|
||||
{{ $t('task.attributes.createdBy') }}
|
||||
</fancycheckbox>
|
||||
</card>
|
||||
</template>
|
||||
</popup>
|
||||
<filter-popup
|
||||
v-model="params"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
<filter-popup v-model="params" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -182,21 +179,23 @@
|
||||
</ListWrapper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, toRaw } from 'vue'
|
||||
<script setup lang="ts">
|
||||
import { toRef, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import ListWrapper from './ListWrapper'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
|
||||
import ListWrapper from './ListWrapper.vue'
|
||||
import Done from '@/components/misc/Done.vue'
|
||||
import User from '@/components/misc/user'
|
||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel'
|
||||
import Labels from '@/components/tasks/partials/labels'
|
||||
import DateTableCell from '@/components/tasks/partials/date-table-cell'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox'
|
||||
import Sort from '@/components/tasks/partials/sort'
|
||||
import User from '@/components/misc/user.vue'
|
||||
import PriorityLabel from '@/components/tasks/partials/priorityLabel.vue'
|
||||
import Labels from '@/components/tasks/partials/labels.vue'
|
||||
import DateTableCell from '@/components/tasks/partials/date-table-cell.vue'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
import Sort from '@/components/tasks/partials/sort.vue'
|
||||
import FilterPopup from '@/components/list/partials/filter-popup.vue'
|
||||
import Pagination from '@/components/misc/pagination.vue'
|
||||
import Popup from '@/components/misc/popup'
|
||||
import Popup from '@/components/misc/popup.vue'
|
||||
|
||||
import { useTaskList } from '@/composables/taskList'
|
||||
|
||||
@ -216,57 +215,27 @@ const ACTIVE_COLUMNS_DEFAULT = {
|
||||
createdBy: false,
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
let hasIdFilter = false
|
||||
const sortKeys = Object.keys(sortBy.value)
|
||||
for (const s of sortKeys) {
|
||||
if (s === 'id') {
|
||||
sortKeys.splice(s, 1)
|
||||
hasIdFilter = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasIdFilter) {
|
||||
sortKeys.push('id')
|
||||
}
|
||||
params.value.sort_by = sortKeys
|
||||
params.value.order_by = sortKeys.map(s => sortBy.value[s])
|
||||
}
|
||||
const activeColumns = useStorage('tableViewColumns', { ...ACTIVE_COLUMNS_DEFAULT })
|
||||
const sortBy = useStorage('tableViewSortBy', { ...SORT_BY_DEFAULT })
|
||||
|
||||
const {
|
||||
tasks,
|
||||
loading,
|
||||
params,
|
||||
loadTasks,
|
||||
totalPages,
|
||||
currentPage,
|
||||
searchTerm,
|
||||
initTaskList,
|
||||
} = useTaskList(beforeLoad)
|
||||
} = useTaskList(toRef(props, 'listId'))
|
||||
|
||||
Object.assign(params.value, {
|
||||
filter_by: [],
|
||||
@ -274,8 +243,19 @@ Object.assign(params.value, {
|
||||
filter_comparator: [],
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
// FIXME: by doing this we can have multiple sort orders
|
||||
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]
|
||||
}
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const taskDetailRoutes = computed(() => Object.fromEntries(
|
||||
tasks.value.map(({id}) => ([
|
||||
id,
|
||||
@ -286,26 +266,6 @@ const taskDetailRoutes = computed(() => Object.fromEntries(
|
||||
},
|
||||
])),
|
||||
))
|
||||
|
||||
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(currentPage.value, searchTerm.value)
|
||||
// Save the order to be able to retrieve them later
|
||||
localStorage.setItem('tableViewSortBy', JSON.stringify(sortBy.value))
|
||||
}
|
||||
|
||||
function saveTaskColumns() {
|
||||
localStorage.setItem('tableViewColumns', JSON.stringify(toRaw(activeColumns)))
|
||||
}
|
||||
|
||||
initTaskList()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -8,28 +8,28 @@
|
||||
<router-link
|
||||
v-shortcut="'g l'"
|
||||
:title="$t('keyboardShortcuts.list.switchToListView')"
|
||||
:class="{'is-active': $route.name === 'list.list'}"
|
||||
:class="{'is-active': viewName === 'list'}"
|
||||
:to="{ name: 'list.list', params: { listId } }">
|
||||
{{ $t('list.list.title') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-shortcut="'g g'"
|
||||
:title="$t('keyboardShortcuts.list.switchToGanttView')"
|
||||
:class="{'is-active': $route.name === 'list.gantt'}"
|
||||
:class="{'is-active': viewName === 'gantt'}"
|
||||
:to="{ name: 'list.gantt', params: { listId } }">
|
||||
{{ $t('list.gantt.title') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-shortcut="'g t'"
|
||||
:title="$t('keyboardShortcuts.list.switchToTableView')"
|
||||
:class="{'is-active': $route.name === 'list.table'}"
|
||||
:class="{'is-active': viewName === 'table'}"
|
||||
:to="{ name: 'list.table', params: { listId } }">
|
||||
{{ $t('list.table.title') }}
|
||||
</router-link>
|
||||
<router-link
|
||||
v-shortcut="'g k'"
|
||||
:title="$t('keyboardShortcuts.list.switchToKanbanView')"
|
||||
:class="{'is-active': $route.name === 'list.kanban'}"
|
||||
:class="{'is-active': viewName === 'kanban'}"
|
||||
:to="{ name: 'list.kanban', params: { listId } }">
|
||||
{{ $t('list.kanban.title') }}
|
||||
</router-link>
|
||||
@ -46,11 +46,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import {ref, shallowRef, computed, watchEffect} from 'vue'
|
||||
import {useRoute} from 'vue-router'
|
||||
|
||||
import Message from '@/components/misc/message'
|
||||
import Message from '@/components/misc/message.vue'
|
||||
|
||||
import ListModel from '@/models/list'
|
||||
import ListService from '@/services/list'
|
||||
@ -63,11 +63,22 @@ import {saveListView} from '@/helpers/saveListView'
|
||||
import {saveListToHistory} from '@/modules/listHistory'
|
||||
import { useTitle } from '@/composables/useTitle'
|
||||
|
||||
const props = defineProps({
|
||||
listId: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
viewName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// Save the current list view to local storage
|
||||
// We use local storage and not vuex here to make it persistent across reloads.
|
||||
saveListView(route.params.listId, route.name)
|
||||
saveListView(props.listId, props.viewName)
|
||||
|
||||
const listService = shallowRef(new ListService())
|
||||
const loadedListId = ref(0)
|
||||
@ -80,14 +91,12 @@ const currentList = computed(() => {
|
||||
} : store.state.currentList
|
||||
})
|
||||
|
||||
// Computed property to let "listId" always have a value
|
||||
const listId = computed(() => typeof route.params.listId === 'undefined' ? 0 : parseInt(route.params.listId))
|
||||
// call again the method if the listId changes
|
||||
watchEffect(() => loadList(listId.value))
|
||||
watchEffect(() => loadList(props.listId))
|
||||
|
||||
useTitle(() => currentList.value.id ? getListTitle(currentList.value) : '')
|
||||
|
||||
async function loadList(listIdToLoad) {
|
||||
async function loadList(listIdToLoad: number) {
|
||||
const listData = {id: listIdToLoad}
|
||||
saveListToHistory(listData)
|
||||
|
||||
@ -97,8 +106,8 @@ async function loadList(listIdToLoad) {
|
||||
// We don't do this for the table view because that does not change tasks.
|
||||
// FIXME: remove this
|
||||
if (
|
||||
route.name === 'list.list' ||
|
||||
route.name === 'list.gantt'
|
||||
props.viewName === 'list.list' ||
|
||||
props.viewName === 'list.gantt'
|
||||
) {
|
||||
store.commit('kanban/setListId', 0)
|
||||
}
|
||||
@ -116,7 +125,7 @@ async function loadList(listIdToLoad) {
|
||||
return
|
||||
}
|
||||
|
||||
console.debug(`Loading list, $route.name = ${route.name}, $route.params =`, route.params, `, loadedListId = ${loadedListId.value}, currentList = `, currentList.value)
|
||||
console.debug(`Loading list, props.viewName = ${props.viewName}, $route.params =`, route.params, `, loadedListId = ${loadedListId.value}, currentList = `, currentList.value)
|
||||
|
||||
// We create an extra list object instead of creating it in list.value because that would trigger a ui update which would result in bad ux.
|
||||
const list = new ListModel(listData)
|
||||
@ -124,7 +133,7 @@ async function loadList(listIdToLoad) {
|
||||
const loadedList = await listService.value.get(list)
|
||||
await store.dispatch(CURRENT_LIST, loadedList)
|
||||
} finally {
|
||||
loadedListId.value = listId.value
|
||||
loadedListId.value = props.listId
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user