WIP: feat: route modals everywhere #2735
|
@ -16,7 +16,7 @@
|
||||||
{{ currentList.title === '' ? $t('misc.loading') : getListTitle(currentList) }}
|
{{ currentList.title === '' ? $t('misc.loading') : getListTitle(currentList) }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<BaseButton :to="{name: 'list.info', params: {listId: currentList.id}, state: {backdropRoutePath: $route.fullPath}}" class="info-button">
|
<BaseButton :to="{name: 'list.info', params: {listId: currentList.id},}" class="info-button">
|
||||||
<icon icon="circle-info"/>
|
<icon icon="circle-info"/>
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
{{ $t('keyboardShortcuts.title') }}
|
{{ $t('keyboardShortcuts.title') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{name: 'about', state: {backdropRoutePath: $route.fullPath}}"
|
:to="{name: 'about',}"
|
||||||
>
|
>
|
||||||
{{ $t('about.title') }}
|
{{ $t('about.title') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
<template v-if="isSavedFilter(list)">
|
<template v-if="isSavedFilter(list)">
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'filter.settings.edit', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'filter.settings.edit', params: { listId: list.id } }"
|
||||||
icon="pen"
|
icon="pen"
|
||||||
>
|
>
|
||||||
{{ $t('menu.edit') }}
|
{{ $t('menu.edit') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'filter.settings.delete', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'filter.settings.delete', params: { listId: list.id } }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
>
|
>
|
||||||
{{ $t('misc.delete') }}
|
{{ $t('misc.delete') }}
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
<template v-else-if="list.isArchived">
|
<template v-else-if="list.isArchived">
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.archive', params: { listId: list.id } }"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
>
|
>
|
||||||
{{ $t('menu.unarchive') }}
|
{{ $t('menu.unarchive') }}
|
||||||
|
@ -33,32 +33,32 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.edit', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.edit', params: { listId: list.id } }"
|
||||||
icon="pen"
|
icon="pen"
|
||||||
>
|
>
|
||||||
{{ $t('menu.edit') }}
|
{{ $t('menu.edit') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
v-if="backgroundsEnabled"
|
v-if="backgroundsEnabled"
|
||||||
:to="{ name: 'list.settings.background', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.background', params: { listId: list.id } }"
|
||||||
icon="image"
|
icon="image"
|
||||||
>
|
>
|
||||||
{{ $t('menu.setBackground') }}
|
{{ $t('menu.setBackground') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.share', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.share', params: { listId: list.id } }"
|
||||||
icon="share-alt"
|
icon="share-alt"
|
||||||
>
|
>
|
||||||
{{ $t('menu.share') }}
|
{{ $t('menu.share') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.duplicate', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.duplicate', params: { listId: list.id } }"
|
||||||
icon="paste"
|
icon="paste"
|
||||||
>
|
>
|
||||||
{{ $t('menu.duplicate') }}
|
{{ $t('menu.duplicate') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.archive', params: { listId: list.id } }"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
>
|
>
|
||||||
{{ $t('menu.archive') }}
|
{{ $t('menu.archive') }}
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
/>
|
/>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.settings.delete', params: { listId: list.id }, state: {backdropRoutePath: $route.fullPath} }"
|
:to="{ name: 'list.settings.delete', params: { listId: list.id } }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
class="has-text-danger"
|
class="has-text-danger"
|
||||||
>
|
>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<template v-if="namespace.isArchived">
|
<template v-if="namespace.isArchived">
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
>
|
>
|
||||||
{{ $t('menu.unarchive') }}
|
{{ $t('menu.unarchive') }}
|
||||||
|
@ -18,25 +18,25 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id } }"
|
||||||
icon="pen"
|
icon="pen"
|
||||||
>
|
>
|
||||||
{{ $t('menu.edit') }}
|
{{ $t('menu.edit') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id } }"
|
||||||
icon="share-alt"
|
icon="share-alt"
|
||||||
>
|
>
|
||||||
{{ $t('menu.share') }}
|
{{ $t('menu.share') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'list.create', params: { namespaceId: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'list.create', params: { namespaceId: namespace.id } }"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
{{ $t('menu.newList') }}
|
{{ $t('menu.newList') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
>
|
>
|
||||||
{{ $t('menu.archive') }}
|
{{ $t('menu.archive') }}
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
type="dropdown"
|
type="dropdown"
|
||||||
/>
|
/>
|
||||||
<dropdown-item
|
<dropdown-item
|
||||||
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id } }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
class="has-text-danger"
|
class="has-text-danger"
|
||||||
>
|
>
|
||||||
|
|
|
@ -153,7 +153,6 @@ function openTask(e: {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'task.detail',
|
name: 'task.detail',
|
||||||
params: {id: e.bar.ganttBarConfig.id},
|
params: {id: e.bar.ganttBarConfig.id},
|
||||||
state: {backdropRoutePath: router.currentRoute.value.fullPath},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,6 @@ function openTaskDetail() {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'task.detail',
|
name: 'task.detail',
|
||||||
params: {id: props.task.id},
|
params: {id: props.task.id},
|
||||||
state: {backdropRoutePath: router.currentRoute.value.fullPath},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<router-link
|
<router-link
|
||||||
:to="{
|
:to="{name: 'task.detail', params: {id: task.id}}"
|
||||||
name: 'task.detail',
|
|
||||||
params: {id: task.id},
|
|
||||||
state: { backdropRoutePath: $route.fullPath },
|
|
||||||
}"
|
|
||||||
:class="{ 'done': task.done}"
|
:class="{ 'done': task.done}"
|
||||||
class="tasktext"
|
class="tasktext"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {computed, shallowRef, watch, h, type VNode, ref} from 'vue'
|
import {computed, shallowRef, watch, h, type VNode, ref} from 'vue'
|
||||||
import {useRoute, useRouter, loadRouteLocation, type RouteLocationNormalizedLoaded, type RouteLocationRaw, START_LOCATION, type RouteLocationNormalized} from 'vue-router'
|
import {useRoute, useRouter, loadRouteLocation, type RouteLocationNormalizedLoaded, type RouteLocationRaw, START_LOCATION} from 'vue-router'
|
||||||
import router from '@/router'
|
import router, { handleRedirectRecord } from '@/router'
|
||||||
|
|
||||||
// this is adapted from vue-router
|
// this is adapted from vue-router
|
||||||
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
|
// https://github.com/vuejs/vue-router-next/blob/798cab0d1e21f9b4d45a2bd12b840d2c7415f38a/src/RouterView.ts#L125
|
||||||
|
@ -16,7 +16,14 @@ function getRouteProps(route: RouteLocationNormalizedLoaded) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveAndLoadRoute(route: RouteLocationRaw, currentLocation?: RouteLocationNormalizedLoaded) {
|
function resolveAndLoadRoute(route: RouteLocationRaw, currentLocation?: RouteLocationNormalizedLoaded) {
|
||||||
return loadRouteLocation(router.resolve(route, currentLocation))
|
const resolvedRoute = router.resolve(route, currentLocation)
|
||||||
|
|
||||||
|
// resolvedRoute.matched.forEach((record) => console.log(record.redirect))
|
||||||
|
|
||||||
|
// e.g. 'list.index' will always redirect, so we need to resolve the redirected route record
|
||||||
|
const redirectedRoute = handleRedirectRecord(resolvedRoute) || resolvedRoute
|
||||||
|
|
||||||
|
return loadRouteLocation(router.resolve(redirectedRoute, currentLocation))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useRouteWithModal() {
|
export function useRouteWithModal() {
|
||||||
|
@ -31,33 +38,64 @@ export function useRouteWithModal() {
|
||||||
: undefined
|
: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isInitialNavigation = ref(true)
|
||||||
|
|
||||||
|
router.beforeEach((to, from) => {
|
||||||
|
isInitialNavigation.value = from === START_LOCATION
|
||||||
|
})
|
||||||
|
|
||||||
|
const lastBackdropRoutePath = ref<string>()
|
||||||
|
|||||||
router.afterEach((to, from) => {
|
router.afterEach((to, from) => {
|
||||||
const resolvedRoute = router.resolve(to)
|
const resolvedRoute = router.resolve(to)
|
||||||
// if (!resolvedRoute.meta.forceModal) {
|
|
||||||
if (!resolvedRoute.meta.modal) {
|
if (!resolvedRoute.meta.modal) {
|
||||||
|
// this route doesn't define that it can be a modal
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let routeNormalized: RouteLocationNormalized
|
let backdropRoutePath
|
||||||
if (typeof resolvedRoute.meta?.modal === 'boolean' || resolvedRoute.meta.modal?.force !== true) {
|
if (resolvedRoute.meta?.modal === true || resolvedRoute.meta.modal?.force !== true) {
|
||||||
// TODO: also check route history here
|
// this route can be shown as modal or as normal view
|
||||||
routeNormalized = from
|
|
||||||
|
// TODO: add new state or prop instead of checking backdropRoutePath here
|
||||||
|
// e.g. `modal` with `'normal' | 'sidebar' | 'modal' | 'sheet'`
|
||||||
|
if (!history.state.backdropRoutePath) {
|
||||||
|
// since this modal is optional and we don't have a backdropRoutePath we don't do anything
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (lastBackdropRoutePath.value) {
|
||||||
|
// there was already a modal in the last route
|
||||||
|
// we have to save this in the lastBackdropRoutePath ref because
|
||||||
|
// the state gets overwritten
|
||||||
|
|
||||||
|
// let's show that backdropRoute again
|
||||||
|
// TODO: add support for multiple modal layers here
|
||||||
|
// FIXME: use `history.state.backdropRoutePath` from last route
|
||||||
|
// FIXME: this might be wrong, because we redirect to our current path forever??
|
||||||
|
backdropRoutePath = lastBackdropRoutePath.value
|
||||||
|
} else if (isInitialNavigation.value === false) {
|
||||||
|
backdropRoutePath = from.fullPath
|
||||||
} else if (resolvedRoute.meta.modal?.defaultBackdropRoute) {
|
} else if (resolvedRoute.meta.modal?.defaultBackdropRoute) {
|
||||||
const {defaultBackdropRoute} = resolvedRoute.meta.modal
|
const {defaultBackdropRoute} = resolvedRoute.meta.modal
|
||||||
const routeRaw = typeof defaultBackdropRoute === 'function'
|
const routeRaw = typeof defaultBackdropRoute === 'function'
|
||||||
? defaultBackdropRoute(resolvedRoute)
|
? defaultBackdropRoute(resolvedRoute)
|
||||||
: defaultBackdropRoute
|
: defaultBackdropRoute
|
||||||
routeNormalized = router.resolve(routeRaw)
|
backdropRoutePath = router.resolve(routeRaw).fullPath
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (backdropRoutePath === undefined) {
|
||||||
|
console.log('No defaultBackdropRoute defined for this route')
|
||||||
|
|
||||||
// TODO: maybe load parent route here in the future,
|
// TODO: maybe load parent route here in the future,
|
||||||
// via: route.matched[route.matched.length - 2]
|
// via: route.matched[route.matched.length - 2]
|
||||||
// see: https://router.vuejs.org/guide/migration/#removal-of-parent-from-route-locations
|
// see: https://router.vuejs.org/guide/migration/#removal-of-parent-from-route-locations
|
||||||
routeNormalized = router.resolve({ name: 'home' })
|
backdropRoutePath = router.resolve({ name: 'home' }).fullPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastBackdropRoutePath.value = backdropRoutePath
|
||||||
|
|
||||||
history.replaceState({
|
history.replaceState({
|
||||||
...history.state,
|
...history.state,
|
||||||
foobar: routeNormalized.fullPath,
|
backdropRoutePath,
|
||||||
}, '')
|
}, '')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -140,7 +178,9 @@ export function useRouteWithModal() {
|
||||||
|
|
||||||
async function closeModal() {
|
async function closeModal() {
|
||||||
await router.isReady()
|
await router.isReady()
|
||||||
if (backdropRoute.value !== undefined) {
|
if (isInitialNavigation.value === false) {
|
||||||
|
return router.back()
|
||||||
|
} else if (backdropRoute.value !== undefined) {
|
||||||
// TODO: Dialog modals might want to replace the route here via router.replace()
|
// TODO: Dialog modals might want to replace the route here via router.replace()
|
||||||
return router.push(backdropRoute.value)
|
return router.push(backdropRoute.value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ declare module 'vue-router' {
|
||||||
/** Forces the view to be always shown as modal */
|
/** Forces the view to be always shown as modal */
|
||||||
force?: boolean,
|
force?: boolean,
|
||||||
/** Show this route as backdrop if there is no route history */
|
/** Show this route as backdrop if there is no route history */
|
||||||
defaultBackdropRoute?: RouteLocationRaw | ((currentRoute: RouteLocation) => RouteLocationRaw),
|
defaultBackdropRoute?: RouteLocationRaw | ((to: RouteLocationNormalized) => RouteLocationRaw),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,10 @@ const router = createRouter({
|
||||||
name: 'namespace.settings.edit',
|
name: 'namespace.settings.edit',
|
||||||
component: NamespaceSettingEdit,
|
component: NamespaceSettingEdit,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
||||||
},
|
},
|
||||||
|
@ -245,7 +248,10 @@ const router = createRouter({
|
||||||
name: 'namespace.settings.share',
|
name: 'namespace.settings.share',
|
||||||
component: NamespaceSettingShare,
|
component: NamespaceSettingShare,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -253,7 +259,10 @@ const router = createRouter({
|
||||||
name: 'namespace.settings.archive',
|
name: 'namespace.settings.archive',
|
||||||
component: NamespaceSettingArchive,
|
component: NamespaceSettingArchive,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
||||||
},
|
},
|
||||||
|
@ -262,7 +271,10 @@ const router = createRouter({
|
||||||
name: 'namespace.settings.delete',
|
name: 'namespace.settings.delete',
|
||||||
component: NamespaceSettingDelete,
|
component: NamespaceSettingDelete,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
props: route => ({ namespaceId: Number(route.params.id as string) }),
|
||||||
},
|
},
|
||||||
|
@ -274,7 +286,9 @@ const router = createRouter({
|
||||||
meta: {
|
meta: {
|
||||||
modal: {
|
modal: {
|
||||||
force: true,
|
force: true,
|
||||||
defaultBackdropRoute: {name: 'home'},
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -294,7 +308,10 @@ const router = createRouter({
|
||||||
name: 'list.create',
|
name: 'list.create',
|
||||||
component: NewListComponent,
|
component: NewListComponent,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -303,7 +320,12 @@ const router = createRouter({
|
||||||
component: ListSettingEdit,
|
component: ListSettingEdit,
|
||||||
props: route => ({ listId: Number(route.params.listId as string) }),
|
props: route => ({ listId: Number(route.params.listId as string) }),
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -311,7 +333,12 @@ const router = createRouter({
|
||||||
name: 'list.settings.background',
|
name: 'list.settings.background',
|
||||||
component: ListSettingBackground,
|
component: ListSettingBackground,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -319,7 +346,12 @@ const router = createRouter({
|
||||||
name: 'list.settings.duplicate',
|
name: 'list.settings.duplicate',
|
||||||
component: ListSettingDuplicate,
|
component: ListSettingDuplicate,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -327,7 +359,12 @@ const router = createRouter({
|
||||||
name: 'list.settings.share',
|
name: 'list.settings.share',
|
||||||
component: ListSettingShare,
|
component: ListSettingShare,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -335,7 +372,12 @@ const router = createRouter({
|
||||||
name: 'list.settings.delete',
|
name: 'list.settings.delete',
|
||||||
component: ListSettingDelete,
|
component: ListSettingDelete,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -343,7 +385,12 @@ const router = createRouter({
|
||||||
name: 'list.settings.archive',
|
name: 'list.settings.archive',
|
||||||
component: ListSettingArchive,
|
component: ListSettingArchive,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -351,7 +398,12 @@ const router = createRouter({
|
||||||
name: 'filter.settings.edit',
|
name: 'filter.settings.edit',
|
||||||
component: FilterEdit,
|
component: FilterEdit,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ listId: Number(route.params.listId as string) }),
|
props: route => ({ listId: Number(route.params.listId as string) }),
|
||||||
},
|
},
|
||||||
|
@ -360,7 +412,12 @@ const router = createRouter({
|
||||||
name: 'filter.settings.delete',
|
name: 'filter.settings.delete',
|
||||||
component: FilterDelete,
|
component: FilterDelete,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ listId: Number(route.params.listId as string) }),
|
props: route => ({ listId: Number(route.params.listId as string) }),
|
||||||
},
|
},
|
||||||
|
@ -369,7 +426,12 @@ const router = createRouter({
|
||||||
name: 'list.info',
|
name: 'list.info',
|
||||||
component: ListInfo,
|
component: ListInfo,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute(route) {
|
||||||
|
return { name: 'list.index', props: { listId: route.params.listId}}
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
props: route => ({ listId: Number(route.params.listId as string) }),
|
props: route => ({ listId: Number(route.params.listId as string) }),
|
||||||
},
|
},
|
||||||
|
@ -436,9 +498,13 @@ const router = createRouter({
|
||||||
name: 'teams.create',
|
name: 'teams.create',
|
||||||
component: NewTeamComponent,
|
component: NewTeamComponent,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'teams.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// TODO: make modal
|
||||||
{
|
{
|
||||||
path: '/teams/:id/edit',
|
path: '/teams/:id/edit',
|
||||||
name: 'teams.edit',
|
name: 'teams.edit',
|
||||||
|
@ -454,7 +520,10 @@ const router = createRouter({
|
||||||
name: 'labels.create',
|
name: 'labels.create',
|
||||||
component: NewLabelComponent,
|
component: NewLabelComponent,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'labels.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -476,7 +545,10 @@ const router = createRouter({
|
||||||
name: 'filters.create',
|
name: 'filters.create',
|
||||||
component: FilterNew,
|
component: FilterNew,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
defaultBackdropRoute: {name: 'namespaces.index'},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -489,7 +561,9 @@ const router = createRouter({
|
||||||
name: 'about',
|
name: 'about',
|
||||||
component: About,
|
component: About,
|
||||||
meta: {
|
meta: {
|
||||||
modal: true,
|
modal: {
|
||||||
|
force: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<template v-if="defaultNamespaceId > 0">
|
<template v-if="defaultNamespaceId > 0">
|
||||||
<p class="mt-4">{{ $t('home.list.newText') }}</p>
|
<p class="mt-4">{{ $t('home.list.newText') }}</p>
|
||||||
<x-button
|
<x-button
|
||||||
:to="{ name: 'list.create', params: { namespaceId: defaultNamespaceId }, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{ name: 'list.create', params: { namespaceId: defaultNamespaceId } }"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{ 'is-loading': loading}" class="loader-container">
|
<div :class="{ 'is-loading': loading}" class="loader-container">
|
||||||
<x-button
|
<x-button
|
||||||
:to="{
|
:to="{ name:'labels.create' }"
|
||||||
name:'labels.create',
|
|
||||||
state: { backdropRoutePath: $route.fullPath }
|
|
||||||
}"
|
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -18,10 +15,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p v-else class="has-text-centered has-text-grey is-italic">
|
<p v-else class="has-text-centered has-text-grey is-italic">
|
||||||
{{ $t('label.newCTA') }}
|
{{ $t('label.newCTA') }}
|
||||||
<router-link :to="{
|
<router-link :to="{name:'labels.create'}">{{ $t('label.create.title') }}.</router-link>
|
||||||
name:'labels.create',
|
|
||||||
state: { backdropRoutePath: $route.fullPath }
|
|
||||||
}">{{ $t('label.create.title') }}.</router-link>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,6 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {toRef, computed, type Ref} from 'vue'
|
import {toRef, computed, type Ref} from 'vue'
|
||||||
import {useRoute} from 'vue-router'
|
|
||||||
import {useStorage} from '@vueuse/core'
|
import {useStorage} from '@vueuse/core'
|
||||||
|
|
||||||
import ListWrapper from '@/components/list/ListWrapper.vue'
|
import ListWrapper from '@/components/list/ListWrapper.vue'
|
||||||
|
@ -274,14 +273,12 @@ function sort(property: keyof SortBy) {
|
||||||
sortByParam.value = sortBy.value
|
sortByParam.value = sortBy.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = useRoute()
|
|
||||||
const taskDetailRoutes = computed(() => Object.fromEntries(
|
const taskDetailRoutes = computed(() => Object.fromEntries(
|
||||||
tasks.value.map(({id}) => ([
|
tasks.value.map(({id}) => ([
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
name: 'task.detail',
|
name: 'task.detail',
|
||||||
params: {id},
|
params: {id},
|
||||||
state: { backdropRoutePath: route.fullPath },
|
|
||||||
},
|
},
|
||||||
])),
|
])),
|
||||||
))
|
))
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
:primary-label="$t('misc.save')"
|
:primary-label="$t('misc.save')"
|
||||||
@primary="save"
|
@primary="save"
|
||||||
:tertiary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertiary="$router.push({ name: 'list.settings.delete', params: { id: listId }, state: {backdropRoutePath: $route.fullPath} })"
|
@tertiary="$router.push({ name: 'list.settings.delete', params: { id: listId } })"
|
||||||
#default="{onClose}"
|
#default="{onClose}"
|
||||||
>
|
>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
</fancycheckbox>
|
</fancycheckbox>
|
||||||
|
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<x-button :to="{name: 'filters.create', state: {backdropRoutePath: $route.fullPath}}" icon="filter">
|
<x-button :to="{name: 'filters.create'}" icon="filter">
|
||||||
{{ $t('filters.create.title') }}
|
{{ $t('filters.create.title') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button :to="{name: 'namespace.create', state: {backdropRoutePath: $route.fullPath}}" icon="plus" v-cy="'new-namespace'">
|
<x-button :to="{name: 'namespace.create'}" icon="plus" v-cy="'new-namespace'">
|
||||||
{{ $t('namespace.create.title') }}
|
{{ $t('namespace.create.title') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<p v-if="namespaces.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
<p v-if="namespaces.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
||||||
{{ $t('namespace.noneAvailable') }}
|
{{ $t('namespace.noneAvailable') }}
|
||||||
<BaseButton :to="{name: 'namespace.create', state: {backdropRoutePath: $route.fullPath}}">
|
<BaseButton :to="{name: 'namespace.create'}">
|
||||||
{{ $t('namespace.create.title') }}.
|
{{ $t('namespace.create.title') }}.
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</p>
|
</p>
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
<section :key="`n${n.id}`" class="namespace" v-for="n in namespaces">
|
<section :key="`n${n.id}`" class="namespace" v-for="n in namespaces">
|
||||||
<x-button
|
<x-button
|
||||||
v-if="n.id > 0 && n.lists.length > 0"
|
v-if="n.id > 0 && n.lists.length > 0"
|
||||||
:to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropRoutePath: $route.fullPath }}"
|
:to="{name: 'list.create', params: {namespaceId: n.id}}"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
v-if="n.isArchived"
|
v-if="n.isArchived"
|
||||||
:to="{name: 'namespace.settings.archive', params: {id: n.id}, state: { backdropRoutePath: $route.fullPath } }"
|
:to="{name: 'namespace.settings.archive', params: {id: n.id} }"
|
||||||
class="is-pulled-right mr-4"
|
class="is-pulled-right mr-4"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
|
|
||||||
<p v-if="n.lists.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
<p v-if="n.lists.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
||||||
{{ $t('namespace.noLists') }}
|
{{ $t('namespace.noLists') }}
|
||||||
<BaseButton :to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropRoutePath: $route.fullPath }}">
|
<BaseButton :to="{name: 'list.create', params: {namespaceId: n.id}}">
|
||||||
{{ $t('namespace.createList') }}
|
{{ $t('namespace.createList') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
:primary-label="$t('misc.save')"
|
:primary-label="$t('misc.save')"
|
||||||
@primary="save"
|
@primary="save"
|
||||||
:tertiary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertiary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id }, state: { backdropRoutePath: $route.fullPath } })"
|
@tertiary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id } })"
|
||||||
#default="{onClose}"
|
#default="{onClose}"
|
||||||
>
|
>
|
||||||
<form @submit.prevent="save(onClose)">
|
<form @submit.prevent="save(onClose)">
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="content loader-container is-max-width-desktop" :class="{ 'is-loading': teamService.loading}">
|
<div class="content loader-container is-max-width-desktop" :class="{ 'is-loading': teamService.loading}">
|
||||||
<x-button
|
<x-button
|
||||||
:to="{
|
:to="{name:'teams.create'}"
|
||||||
name:'teams.create',
|
|
||||||
state: { backdropRoutePath: $route.fullPath },
|
|
||||||
}"
|
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -21,10 +18,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
<p v-else-if="!teamService.loading" class="has-text-centered has-text-grey is-italic">
|
<p v-else-if="!teamService.loading" class="has-text-centered has-text-grey is-italic">
|
||||||
{{ $t('team.noTeams') }}
|
{{ $t('team.noTeams') }}
|
||||||
<router-link :to="{
|
<router-link :to="{name: 'teams.create'}">
|
||||||
name: 'teams.create',
|
|
||||||
state: { backdropRoutePath: $route.fullPath },
|
|
||||||
}">
|
|
||||||
{{ $t('team.create.title') }}.
|
{{ $t('team.create.title') }}.
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
|
|
Reference in New Issue
Something was broken here: since we checked for
historyState.value
in theif
condition it could never have a value in theelse
cause.