feat: implement modals with vue router 4

This is an implementation of the modals with the new possibilities of vue router 3.

See: https://github.com/vuejs/vue-router/issues/703#issuecomment-865066913 for a better explanation
and the linked example implementation: https://github.com/vuejs/vue-router-next/blob/master/e2e/modal/index.ts
This commit is contained in:
Dominik Pschenitschni 2021-10-03 15:54:24 +02:00
parent 29d8422e94
commit 5a0c0eff9f
Signed by: dpschen
GPG Key ID: B257AC0149F43A77
15 changed files with 152 additions and 284 deletions

View File

@ -20,8 +20,9 @@
<quick-actions/> <quick-actions/>
<router-view/> <router-view :route="routeWithModal"/>
<!-- TODO: is this still used? -->
<router-view name="popup" v-slot="{ Component }"> <router-view name="popup" v-slot="{ Component }">
<transition name="modal"> <transition name="modal">
<component :is="Component" /> <component :is="Component" />
@ -50,6 +51,24 @@ import {CURRENT_LIST, KEYBOARD_SHORTCUTS_ACTIVE, MENU_ACTIVE} from '@/store/muta
import Navigation from '@/components/home/navigation.vue' import Navigation from '@/components/home/navigation.vue'
import QuickActions from '@/components/quick-actions/quick-actions.vue' import QuickActions from '@/components/quick-actions/quick-actions.vue'
function useRouteWithModal() {
const router = useRouter()
const route = useRoute()
const historyState = computed(() => route.fullPath && window.history.state)
const routeWithModal = computed(() => {
if (historyState.value.backgroundView) {
return router.resolve(historyState.value.backgroundView)
} else {
return route
}
})
return { routeWithModal }
}
useRouteWithModal()
const store = useStore() const store = useStore()
const background = computed(() => store.state.background) const background = computed(() => store.state.background)

View File

@ -29,9 +29,10 @@
<script> <script>
import Filters from '@/components/list/partials/filters' import Filters from '@/components/list/partials/filters'
import {getDefaultParams} from '@/components/tasks/mixins/taskList'
import Popup from '@/components/misc/popup' import Popup from '@/components/misc/popup'
import {getDefaultParams} from '@/composables/taskList'
export default { export default {
name: 'filter-popup', name: 'filter-popup',
components: { components: {

View File

@ -6,7 +6,9 @@
<message> <message>
{{ {{
s.available($route) ? $t('keyboardShortcuts.currentPageOnly') : $t('keyboardShortcuts.allPages') s?.available($route)
? $t('keyboardShortcuts.currentPageOnly')
: $t('keyboardShortcuts.allPages')
}} }}
</message> </message>
@ -17,7 +19,8 @@
class="shortcut-keys" class="shortcut-keys"
is="dd" is="dd"
:keys="sc.keys" :keys="sc.keys"
:combination="typeof sc.combination !== 'undefined' ? $t(`keyboardShortcuts.${sc.combination}`) : null"/> :combination="typeof sc.combination !== 'undefined' ? $t(`keyboardShortcuts.${sc.combination}`) : null"
/>
</template> </template>
</dl> </dl>
</template> </template>
@ -25,28 +28,17 @@
</modal> </modal>
</template> </template>
<script> <script lang="ts" setup>
import {KEYBOARD_SHORTCUTS_ACTIVE} from '@/store/mutation-types' import {store} from '@/store'
import Shortcut from '@/components/misc/shortcut.vue'
import Message from '@/components/misc/message'
import {KEYBOARD_SHORTCUTS} from './shortcuts'
export default { import Shortcut from '@/components/misc/shortcut.vue'
name: 'keyboard-shortcuts', import Message from '@/components/misc/message.vue'
components: {
Message, import {KEYBOARD_SHORTCUTS_ACTIVE} from '@/store/mutation-types'
Shortcut, import {KEYBOARD_SHORTCUTS as shortcuts} from './shortcuts'
},
data() { function close() {
return { store.commit(KEYBOARD_SHORTCUTS_ACTIVE, false)
shortcuts: KEYBOARD_SHORTCUTS,
}
},
methods: {
close() {
this.$store.commit(KEYBOARD_SHORTCUTS_ACTIVE, false)
},
},
} }
</script> </script>

View File

@ -5,7 +5,6 @@ const ctrl = isAppleDevice() ? '⌘' : 'ctrl'
export const KEYBOARD_SHORTCUTS = [ export const KEYBOARD_SHORTCUTS = [
{ {
title: 'keyboardShortcuts.general', title: 'keyboardShortcuts.general',
available: () => null,
shortcuts: [ shortcuts: [
{ {
title: 'keyboardShortcuts.toggleMenu', title: 'keyboardShortcuts.toggleMenu',
@ -55,13 +54,7 @@ export const KEYBOARD_SHORTCUTS = [
}, },
{ {
title: 'keyboardShortcuts.task.title', title: 'keyboardShortcuts.task.title',
available: (route) => [ available: (route) => route.name === 'task.detail',
'task.detail',
'task.list.detail',
'task.gantt.detail',
'task.kanban.detail',
'task.detail',
].includes(route.name),
shortcuts: [ shortcuts: [
{ {
title: 'keyboardShortcuts.task.assign', title: 'keyboardShortcuts.task.assign',

View File

@ -67,7 +67,7 @@
<router-link <router-link
class="mt-2 has-text-centered is-block" class="mt-2 has-text-centered is-block"
:to="{name: 'task.detail', params: {id: taskEditTask.id}}" :to="taskDetailRoute"
> >
{{ $t('task.openDetail') }} {{ $t('task.openDetail') }}
</router-link> </router-link>
@ -102,6 +102,15 @@ export default {
taskEditTask: TaskModel, taskEditTask: TaskModel,
} }
}, },
computed: {
taskDetailRoute() {
return {
name: 'task.detail',
params: { id: this.taskEditTask.id },
state: { backgroundView: this.$router.currentRoute.value.fullPath },
}
},
},
components: { components: {
ColorPicker, ColorPicker,
Reminders, Reminders,

View File

@ -7,8 +7,8 @@
'has-light-text': !colorIsDark(task.hexColor) && task.hexColor !== `#${task.defaultColor}` && task.hexColor !== task.defaultColor, 'has-light-text': !colorIsDark(task.hexColor) && task.hexColor !== `#${task.defaultColor}` && task.hexColor !== task.defaultColor,
}" }"
:style="{'background-color': task.hexColor !== '#' && task.hexColor !== `#${task.defaultColor}` ? task.hexColor : false}" :style="{'background-color': task.hexColor !== '#' && task.hexColor !== `#${task.defaultColor}` ? task.hexColor : false}"
@click.ctrl="() => toggleTaskDone(task)"
@click.exact="() => $router.push({ name: 'task.kanban.detail', params: { id: task.id } })" @click.exact="() => $router.push({ name: 'task.kanban.detail', params: { id: task.id } })"
@click.ctrl="() => toggleTaskDone(task)"
@click.meta="() => toggleTaskDone(task)" @click.meta="() => toggleTaskDone(task)"
> >
<span class="task-id"> <span class="task-id">
@ -112,6 +112,13 @@ export default {
this.loadingInternal = false this.loadingInternal = false
} }
}, },
openTaskDetail() {
this.$router.push({
name: 'task.detail',
params: { id: this.task.id },
state: { backgroundView: this.$router.currentRoute.value.fullPath },
})
},
}, },
} }
</script> </script>

View File

@ -8,7 +8,7 @@
> >
</span> </span>
<router-link <router-link
:to="{ name: taskDetailRoute, params: { id: task.id } }" :to="taskDetailRoute"
:class="{ 'done': task.done}" :class="{ 'done': task.done}"
class="tasktext"> class="tasktext">
<span> <span>
@ -126,10 +126,6 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
taskDetailRoute: {
type: String,
default: 'task.list.detail',
},
showList: { showList: {
type: Boolean, type: Boolean,
default: false, default: false,
@ -167,6 +163,13 @@ export default {
title: '', title: '',
} : this.$store.state.currentList } : this.$store.state.currentList
}, },
taskDetailRoute() {
return {
name: 'task.detail',
params: { id: this.task.id },
state: { backgroundView: this.$router.currentRoute.value.fullPath },
}
},
}, },
methods: { methods: {
async markAsDone(checked) { async markAsDone(checked) {

View File

@ -13,7 +13,6 @@ import DataExportDownload from '../views/user/DataExportDownload'
// Tasks // Tasks
import ShowTasksInRangeComponent from '../views/tasks/ShowTasksInRange' import ShowTasksInRangeComponent from '../views/tasks/ShowTasksInRange'
import LinkShareAuthComponent from '../views/sharing/LinkSharingAuth' import LinkShareAuthComponent from '../views/sharing/LinkSharingAuth'
import TaskDetailViewModal from '../views/tasks/TaskDetailViewModal'
import TaskDetailView from '../views/tasks/TaskDetailView' import TaskDetailView from '../views/tasks/TaskDetailView'
import ListNamespaces from '../views/namespaces/ListNamespaces' import ListNamespaces from '../views/namespaces/ListNamespaces'
// Team Handling // Team Handling
@ -315,204 +314,21 @@ const router = createRouter({
path: '/lists/:listId/list', path: '/lists/:listId/list',
name: 'list.list', name: 'list.list',
component: List, component: List,
children: [
{
path: '/tasks/:id',
name: 'task.list.detail',
component: TaskDetailViewModal,
},
{
path: '/lists/:listId/settings/edit',
name: 'list.list.settings.edit',
component: ListSettingEdit,
},
{
path: '/lists/:listId/settings/background',
name: 'list.list.settings.background',
component: ListSettingBackground,
},
{
path: '/lists/:listId/settings/duplicate',
name: 'list.list.settings.duplicate',
component: ListSettingDuplicate,
},
{
path: '/lists/:listId/settings/share',
name: 'list.list.settings.share',
component: ListSettingShare,
},
{
path: '/lists/:listId/settings/delete',
name: 'list.list.settings.delete',
component: ListSettingDelete,
},
{
path: '/lists/:listId/settings/archive',
name: 'list.list.settings.archive',
component: ListSettingArchive,
},
{
path: '/lists/:listId/settings/edit',
name: 'filter.list.settings.edit',
component: FilterEdit,
},
{
path: '/lists/:listId/settings/delete',
name: 'filter.list.settings.delete',
component: FilterDelete,
},
],
}, },
{ {
path: '/lists/:listId/gantt', path: '/lists/:listId/gantt',
name: 'list.gantt', name: 'list.gantt',
component: Gantt, component: Gantt,
children: [
{
path: '/tasks/:id',
name: 'task.gantt.detail',
component: TaskDetailViewModal,
},
{
path: '/lists/:listId/settings/edit',
name: 'list.gantt.settings.edit',
component: ListSettingEdit,
},
{
path: '/lists/:listId/settings/background',
name: 'list.gantt.settings.background',
component: ListSettingBackground,
},
{
path: '/lists/:listId/settings/duplicate',
name: 'list.gantt.settings.duplicate',
component: ListSettingDuplicate,
},
{
path: '/lists/:listId/settings/share',
name: 'list.gantt.settings.share',
component: ListSettingShare,
},
{
path: '/lists/:listId/settings/delete',
name: 'list.gantt.settings.delete',
component: ListSettingDelete,
},
{
path: '/lists/:listId/settings/archive',
name: 'list.gantt.settings.archive',
component: ListSettingArchive,
},
{
path: '/lists/:listId/settings/edit',
name: 'filter.gantt.settings.edit',
component: FilterEdit,
},
{
path: '/lists/:listId/settings/delete',
name: 'filter.gantt.settings.delete',
component: FilterDelete,
},
],
}, },
{ {
path: '/lists/:listId/table', path: '/lists/:listId/table',
name: 'list.table', name: 'list.table',
component: Table, component: Table,
children: [
{
path: '/lists/:listId/settings/edit',
name: 'list.table.settings.edit',
component: ListSettingEdit,
},
{
path: '/lists/:listId/settings/background',
name: 'list.table.settings.background',
component: ListSettingBackground,
},
{
path: '/lists/:listId/settings/duplicate',
name: 'list.table.settings.duplicate',
component: ListSettingDuplicate,
},
{
path: '/lists/:listId/settings/share',
name: 'list.table.settings.share',
component: ListSettingShare,
},
{
path: '/lists/:listId/settings/delete',
name: 'list.table.settings.delete',
component: ListSettingDelete,
},
{
path: '/lists/:listId/settings/archive',
name: 'list.table.settings.archive',
component: ListSettingArchive,
},
{
path: '/lists/:listId/settings/edit',
name: 'filter.table.settings.edit',
component: FilterEdit,
},
{
path: '/lists/:listId/settings/delete',
name: 'filter.table.settings.delete',
component: FilterDelete,
},
],
}, },
{ {
path: '/lists/:listId/kanban', path: '/lists/:listId/kanban',
name: 'list.kanban', name: 'list.kanban',
component: Kanban, component: Kanban,
children: [
{
path: '/tasks/:id',
name: 'task.kanban.detail',
component: TaskDetailViewModal,
},
{
path: '/lists/:listId/settings/edit',
name: 'list.kanban.settings.edit',
component: ListSettingEdit,
},
{
path: '/lists/:listId/settings/background',
name: 'list.kanban.settings.background',
component: ListSettingBackground,
},
{
path: '/lists/:listId/settings/duplicate',
name: 'list.kanban.settings.duplicate',
component: ListSettingDuplicate,
},
{
path: '/lists/:listId/settings/share',
name: 'list.kanban.settings.share',
component: ListSettingShare,
},
{
path: '/lists/:listId/settings/delete',
name: 'list.kanban.settings.delete',
component: ListSettingDelete,
},
{
path: '/lists/:listId/settings/archive',
name: 'list.kanban.settings.archive',
component: ListSettingArchive,
},
{
path: '/lists/:listId/settings/edit',
name: 'filter.kanban.settings.edit',
component: FilterEdit,
},
{
path: '/lists/:listId/settings/delete',
name: 'filter.kanban.settings.delete',
component: FilterDelete,
},
],
}, },
], ],
}, },

View File

@ -51,6 +51,10 @@
</div> </div>
</div> </div>
<ShowTasks class="mt-4" :show-all="true" v-if="hasLists" :key="showTasksKey"/> <ShowTasks class="mt-4" :show-all="true" v-if="hasLists" :key="showTasksKey"/>
<transition name="modal">
<task-detail-view-modal v-if="showTaskDetail" />
</transition>
</div> </div>
</template> </template>
@ -67,6 +71,9 @@ import {getHistory} from '@/modules/listHistory'
import {parseDateOrNull} from '@/helpers/parseDateOrNull' import {parseDateOrNull} from '@/helpers/parseDateOrNull'
import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate' import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate'
import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation' import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation'
import TaskDetailViewModal, { useShowModal } from '@/views/tasks/TaskDetailViewModal.vue'
const showTaskDetail = useShowModal()
const welcome = useDateTimeSalutation() const welcome = useDateTimeSalutation()

View File

@ -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': $route.name.includes('list.list')}" :class="{'is-active': currentListType === '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': $route.name.includes('list.gantt')}" :class="{'is-active': currentListType === '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': $route.name.includes('list.table')}" :class="{'is-active': currentListType === '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': $route.name.includes('list.kanban')}" :class="{'is-active': currentListType === '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,6 +69,11 @@ 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
@ -113,11 +118,11 @@ export default {
this.$store.commit('kanban/setListId', 0) this.$store.commit('kanban/setListId', 0)
} }
// When clicking again on a list in the menu, there would be no list view selected which means no list // // When clicking again on a list in the menu, there would be no list view selected which means no list
// at all. Users will then have to click on the list view menu again which is quite confusing. // // at all. Users will then have to click on the list view menu again which is quite confusing.
if (this.$route.name === 'list.index') { // if (this.$route.name === 'list.index') {
return this.replaceListView() // return this.replaceListView()
} // }
// Don't load the list if we either already loaded it or aren't dealing with a list at all currently and // Don't load the list if we either already loaded it or aren't dealing with a list at all currently and
// the currently loaded list has the right set. // the currently loaded list has the right set.

View File

@ -52,13 +52,9 @@
:show-taskswithout-dates="showTaskswithoutDates" :show-taskswithout-dates="showTaskswithoutDates"
/> />
<!-- This router view is used to show the task popup while keeping the gantt chart itself --> <transition name="modal">
<router-view v-slot="{ Component }"> <task-detail-view-modal v-if="showTaskDetail" />
<transition name="modal"> </transition>
<component :is="Component" />
</transition>
</router-view>
</card> </card>
</div> </div>
</template> </template>
@ -69,12 +65,20 @@ import flatPickr from 'vue-flatpickr-component'
import Fancycheckbox from '../../../components/input/fancycheckbox' import Fancycheckbox from '../../../components/input/fancycheckbox'
import {saveListView} from '@/helpers/saveListView' import {saveListView} from '@/helpers/saveListView'
import TaskDetailViewModal, { useShowModal } from '@/views/tasks/TaskDetailViewModal.vue'
export default { export default {
name: 'Gantt', name: 'Gantt',
components: { components: {
Fancycheckbox, Fancycheckbox,
flatPickr, flatPickr,
GanttChart, GanttChart,
TaskDetailViewModal,
},
setup() {
return {
showTaskDetail: useShowModal(),
}
}, },
created() { created() {
// Save the current list view to local storage // Save the current list view to local storage

View File

@ -204,18 +204,12 @@
</div> </div>
</div> </div>
<!-- This router view is used to show the task popup while keeping the kanban board itself -->
<router-view v-slot="{ Component }">
<transition name="modal">
<component :is="Component"/>
</transition>
</router-view>
<transition name="modal"> <transition name="modal">
<task-detail-view-modal v-if="showTaskDetail" />
<modal <modal
v-else-if="showBucketDeleteModal"
@close="showBucketDeleteModal = false" @close="showBucketDeleteModal = false"
@submit="deleteBucket()" @submit="deleteBucket()"
v-if="showBucketDeleteModal"
> >
<template #header><span>{{ $t('list.kanban.deleteHeaderBucket') }}</span></template> <template #header><span>{{ $t('list.kanban.deleteHeaderBucket') }}</span></template>
@ -242,6 +236,7 @@ import Dropdown from '@/components/misc/dropdown.vue'
import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveCollapsedBucketState' import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveCollapsedBucketState'
import {calculateItemPosition} from '../../../helpers/calculateItemPosition' import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
import KanbanCard from '@/components/tasks/partials/kanban-card' import KanbanCard from '@/components/tasks/partials/kanban-card'
import TaskDetailViewModal, { useShowModal } from '@/views/tasks/TaskDetailViewModal.vue'
const DRAG_OPTIONS = { const DRAG_OPTIONS = {
// sortable options // sortable options
@ -261,6 +256,7 @@ export default {
Dropdown, Dropdown,
FilterPopup, FilterPopup,
draggable, draggable,
TaskDetailViewModal,
}, },
data() { data() {
return { return {
@ -296,6 +292,13 @@ export default {
}, },
} }
}, },
setup() {
return {
showTaskDetail: useShowModal(),
}
},
created() { 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.

View File

@ -90,7 +90,6 @@
:disabled="!canWrite" :disabled="!canWrite"
:the-task="t" :the-task="t"
@taskUpdated="updateTasks" @taskUpdated="updateTasks"
task-detail-route="task.detail"
> >
<template v-if="canWrite"> <template v-if="canWrite">
<span class="icon handle"> <span class="icon handle">
@ -124,12 +123,9 @@
/> />
</card> </card>
<!-- This router view is used to show the task popup while keeping the kanban board itself --> <transition name="modal">
<router-view v-slot="{ Component }"> <task-detail-view-modal v-if="showTaskDetail" />
<transition name="modal"> </transition>
<component :is="Component"/>
</transition>
</router-view>
</div> </div>
</template> </template>
@ -147,8 +143,8 @@ import FilterPopup from '@/components/list/partials/filter-popup.vue'
import {HAS_TASKS} from '@/store/mutation-types' import {HAS_TASKS} from '@/store/mutation-types'
import Nothing from '@/components/misc/nothing.vue' import Nothing from '@/components/misc/nothing.vue'
import Pagination from '@/components/misc/pagination.vue' import Pagination from '@/components/misc/pagination.vue'
import Popup from '@/components/misc/popup' import {ALPHABETICAL_SORT} from '@/components/list/partials/filters.vue'
import { ALPHABETICAL_SORT } from '@/components/list/partials/filters' import TaskDetailViewModal, { useShowModal } from '@/views/tasks/TaskDetailViewModal.vue'
import draggable from 'vuedraggable' import draggable from 'vuedraggable'
import {calculateItemPosition} from '../../../helpers/calculateItemPosition' import {calculateItemPosition} from '../../../helpers/calculateItemPosition'
@ -192,7 +188,6 @@ export default {
taskList, taskList,
], ],
components: { components: {
Popup,
Nothing, Nothing,
FilterPopup, FilterPopup,
SingleTaskInList, SingleTaskInList,
@ -200,7 +195,15 @@ export default {
AddTask, AddTask,
draggable, draggable,
Pagination, Pagination,
TaskDetailViewModal,
}, },
setup() {
return {
showTaskDetail: useShowModal(),
}
},
created() { 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.

View File

@ -120,7 +120,7 @@
<tbody> <tbody>
<tr :key="t.id" v-for="t in tasks"> <tr :key="t.id" v-for="t in tasks">
<td v-if="activeColumns.id"> <td v-if="activeColumns.id">
<router-link :to="{name: 'task.detail', params: { id: t.id }}"> <router-link :to="taskDetailRoutes[t.id]">
<template v-if="t.identifier === ''"> <template v-if="t.identifier === ''">
#{{ t.index }} #{{ t.index }}
</template> </template>
@ -133,7 +133,7 @@
<Done :is-done="t.done" variant="small" /> <Done :is-done="t.done" variant="small" />
</td> </td>
<td v-if="activeColumns.title"> <td v-if="activeColumns.title">
<router-link :to="{name: 'task.detail', params: { id: t.id }}">{{ t.title }}</router-link> <router-link :to="taskDetailRoutes[t.id]">{{ t.title }}</router-link>
</td> </td>
<td v-if="activeColumns.priority"> <td v-if="activeColumns.priority">
<priority-label :priority="t.priority" :done="t.done" :show-all="true"/> <priority-label :priority="t.priority" :done="t.done" :show-all="true"/>
@ -185,6 +185,8 @@
</template> </template>
<script> <script>
import {useRoute} from 'vue-router'
import taskList from '@/components/tasks/mixins/taskList' import taskList from '@/components/tasks/mixins/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'
@ -237,6 +239,19 @@ export default {
}, },
} }
}, },
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() { created() {
const savedShowColumns = localStorage.getItem('tableViewColumns') const savedShowColumns = localStorage.getItem('tableViewColumns')
if (savedShowColumns !== null) { if (savedShowColumns !== null) {
@ -253,9 +268,13 @@ export default {
this.initTasks(1) this.initTasks(1)
},
setup() {
// 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()
console.log(route.value)
saveListView(route.value.params.listId, route.value.name)
}, },
methods: { methods: {
initTasks(page, search = '') { initTasks(page, search = '') {

View File

@ -13,37 +13,24 @@
<script> <script>
import TaskDetailView from './TaskDetailView' import TaskDetailView from './TaskDetailView'
import {computed} from 'vue'
import {useRoute} from 'vue-router'
export function useShowModal() {
const route = useRoute()
const historyState = computed(() => route.fullPath && window.history.state)
const show = computed(() => historyState.value.backgroundView)
return show
}
export default { export default {
name: 'TaskDetailViewModal', name: 'TaskDetailViewModal',
components: { components: {
TaskDetailView, TaskDetailView,
}, },
data() {
return {
lastRoute: null,
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.lastRoute = from
})
},
beforeRouteLeave(to, from, next) {
if (from.name === 'task.kanban.detail' && to.name === 'task.detail') {
this.$router.replace({name: 'task.kanban.detail', params: to.params})
return
}
next()
},
methods: { methods: {
close() { close() {
if (this.lastRoute === null) { this.$router.back()
this.$router.back()
} else {
this.$router.push(this.lastRoute)
}
}, },
}, },
} }