feat: route modals everywhere
This commit is contained in:
parent
61cdb7a91f
commit
6fc47ee8bd
|
@ -19,7 +19,7 @@ describe('Team', () => {
|
|||
.contains('Create a new team')
|
||||
cy.get('input.input')
|
||||
.type(newTeamName)
|
||||
cy.get('.button')
|
||||
cy.get('.new-team button')
|
||||
.contains('Create')
|
||||
.click()
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<!-- https://github.com/vuejs/rfcs/pull/449 -->
|
||||
<!-- https://github.com/vuejs/rfcs/discussions/448#discussioncomment-2769396= -->
|
||||
<script lang="ts">
|
||||
export default { inheritAttrs: false }
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAttrs } from 'vue'
|
||||
|
||||
defineProps<{ is: any }>()
|
||||
|
||||
const attrs = useAttrs()
|
||||
console.log(JSON.parse(JSON.stringify(attrs)))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component v-if="is" :is="is" v-bind="$attrs">
|
||||
<slot />
|
||||
</component>
|
||||
<slot v-else />
|
||||
</template>
|
|
@ -16,7 +16,7 @@
|
|||
{{ currentList.title === '' ? $t('misc.loading') : getListTitle(currentList) }}
|
||||
</h1>
|
||||
|
||||
<BaseButton :to="{name: 'list.info', params: {listId: currentList.id}}" class="info-button">
|
||||
<BaseButton :to="{name: 'list.info', params: {listId: currentList.id}, state: {backdropView: $route.fullPath}}" class="info-button">
|
||||
<icon icon="circle-info"/>
|
||||
</BaseButton>
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
|||
{{ $t('keyboardShortcuts.title') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{name: 'about'}"
|
||||
:to="{name: 'about', state: {backdropView: $route.fullPath}}"
|
||||
>
|
||||
{{ $t('about.title') }}
|
||||
</dropdown-item>
|
||||
|
|
|
@ -38,14 +38,10 @@
|
|||
</keep-alive>
|
||||
</router-view>
|
||||
|
||||
<modal
|
||||
:enabled="Boolean(currentModal)"
|
||||
<component
|
||||
:is="currentModal"
|
||||
@close="closeModal()"
|
||||
variant="scrolling"
|
||||
class="task-detail-view-modal"
|
||||
>
|
||||
<component :is="currentModal"/>
|
||||
</modal>
|
||||
/>
|
||||
|
||||
<BaseButton
|
||||
class="keyboard-shortcuts-button d-print-none"
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
<template v-if="isSavedFilter(list)">
|
||||
<dropdown-item
|
||||
:to="{ name: 'filter.settings.edit', params: { listId: list.id } }"
|
||||
:to="{ name: 'filter.settings.edit', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="pen"
|
||||
>
|
||||
{{ $t('menu.edit') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'filter.settings.delete', params: { listId: list.id } }"
|
||||
:to="{ name: 'filter.settings.delete', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="trash-alt"
|
||||
>
|
||||
{{ $t('misc.delete') }}
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
<template v-else-if="list.isArchived">
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.archive', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="archive"
|
||||
>
|
||||
{{ $t('menu.unarchive') }}
|
||||
|
@ -33,32 +33,32 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.edit', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.edit', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="pen"
|
||||
>
|
||||
{{ $t('menu.edit') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
v-if="backgroundsEnabled"
|
||||
:to="{ name: 'list.settings.background', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.background', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="image"
|
||||
>
|
||||
{{ $t('menu.setBackground') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.share', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.share', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="share-alt"
|
||||
>
|
||||
{{ $t('menu.share') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.duplicate', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.duplicate', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="paste"
|
||||
>
|
||||
{{ $t('menu.duplicate') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.archive', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="archive"
|
||||
>
|
||||
{{ $t('menu.archive') }}
|
||||
|
@ -73,7 +73,7 @@
|
|||
type="dropdown"
|
||||
/>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.settings.delete', params: { listId: list.id } }"
|
||||
:to="{ name: 'list.settings.delete', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||
icon="trash-alt"
|
||||
class="has-text-danger"
|
||||
>
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
<template>
|
||||
<modal @close="$router.back()" :overflow="true" :wide="wide">
|
||||
<modal :overflow="true" :wide="wide" #default="{ onClose }">
|
||||
<card
|
||||
:title="title"
|
||||
:shadow="false"
|
||||
:padding="false"
|
||||
class="has-text-left"
|
||||
:has-close="true"
|
||||
@close="$router.back()"
|
||||
@close="onClose"
|
||||
:loading="loading"
|
||||
>
|
||||
<div class="p-4">
|
||||
<slot/>
|
||||
<slot :onClose="onClose" />
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<slot name="footer">
|
||||
<slot name="footer" :onClose="onClose">
|
||||
<x-button
|
||||
v-if="tertiary !== ''"
|
||||
:shadow="false"
|
||||
variant="tertiary"
|
||||
@click.prevent.stop="$emit('tertiary')"
|
||||
@click="$emit('tertiary')"
|
||||
>
|
||||
{{ tertiary }}
|
||||
</x-button>
|
||||
<x-button
|
||||
variant="secondary"
|
||||
@click.prevent.stop="$router.back()"
|
||||
@click="onClose"
|
||||
>
|
||||
{{ $t('misc.cancel') }}
|
||||
</x-button>
|
||||
<x-button
|
||||
v-if="hasPrimaryAction"
|
||||
variant="primary"
|
||||
@click.prevent.stop="primary()"
|
||||
@click="primary(onClose)"
|
||||
:icon="primaryIcon"
|
||||
:disabled="primaryDisabled || loading"
|
||||
class="ml-2"
|
||||
|
@ -83,10 +83,11 @@ defineProps({
|
|||
},
|
||||
})
|
||||
|
||||
// 'close'
|
||||
const emit = defineEmits(['create', 'primary', 'tertiary'])
|
||||
|
||||
function primary() {
|
||||
emit('create')
|
||||
emit('primary')
|
||||
function primary(onClose: () => void) {
|
||||
emit('create', onClose)
|
||||
emit('primary', onClose)
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<Teleport to="body">
|
||||
<!-- FIXME: transition should not be included in the modal -->
|
||||
<CustomTransition :name="transitionName" appear>
|
||||
<CustomTransition :name="transitionName" appear :appear-class="transitionName">
|
||||
<section
|
||||
v-if="enabled"
|
||||
class="modal-mask"
|
||||
|
@ -10,11 +10,11 @@
|
|||
variant,
|
||||
]"
|
||||
ref="modal"
|
||||
v-bind="attrs"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<div
|
||||
class="modal-container"
|
||||
@click.self.prevent.stop="$emit('close')"
|
||||
@click.self.prevent.stop="onClose"
|
||||
v-shortcut="'Escape'"
|
||||
>
|
||||
<div
|
||||
|
@ -25,13 +25,13 @@
|
|||
}"
|
||||
>
|
||||
<BaseButton
|
||||
@click="$emit('close')"
|
||||
@click="onClose"
|
||||
class="close"
|
||||
>
|
||||
<icon icon="times"/>
|
||||
</BaseButton>
|
||||
|
||||
<slot>
|
||||
<slot name="default" :onClose="onClose">
|
||||
<div class="header">
|
||||
<slot name="header"></slot>
|
||||
</div>
|
||||
|
@ -40,14 +40,14 @@
|
|||
</div>
|
||||
<div class="actions">
|
||||
<x-button
|
||||
@click="$emit('close')"
|
||||
@click="onClose"
|
||||
variant="tertiary"
|
||||
class="has-text-danger"
|
||||
>
|
||||
{{ $t('misc.cancel') }}
|
||||
</x-button>
|
||||
<x-button
|
||||
@click="$emit('submit')"
|
||||
@click="$emit('submit', onClose)"
|
||||
variant="primary"
|
||||
v-cy="'modalPrimary'"
|
||||
:shadow="false"
|
||||
|
@ -70,10 +70,11 @@ export default {
|
|||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, watchEffect} from 'vue'
|
||||
import {useScrollLock} from '@vueuse/core'
|
||||
|
||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
import {ref, useAttrs, watchEffect} from 'vue'
|
||||
import {useScrollLock} from '@vueuse/core'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
enabled?: boolean,
|
||||
|
@ -87,9 +88,7 @@ const props = withDefaults(defineProps<{
|
|||
variant: 'default',
|
||||
})
|
||||
|
||||
defineEmits(['close', 'submit'])
|
||||
|
||||
const attrs = useAttrs()
|
||||
const emit = defineEmits(['close', 'submit'])
|
||||
|
||||
const modal = ref<HTMLElement | null>(null)
|
||||
const scrollLock = useScrollLock(modal)
|
||||
|
@ -97,6 +96,10 @@ const scrollLock = useScrollLock(modal)
|
|||
watchEffect(() => {
|
||||
scrollLock.value = props.enabled
|
||||
})
|
||||
|
||||
function onClose() {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<template v-if="namespace.isArchived">
|
||||
<dropdown-item
|
||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
|
||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="archive"
|
||||
>
|
||||
{{ $t('menu.unarchive') }}
|
||||
|
@ -18,25 +18,25 @@
|
|||
</template>
|
||||
<template v-else>
|
||||
<dropdown-item
|
||||
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id } }"
|
||||
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="pen"
|
||||
>
|
||||
{{ $t('menu.edit') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id } }"
|
||||
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="share-alt"
|
||||
>
|
||||
{{ $t('menu.share') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'list.create', params: { namespaceId: namespace.id } }"
|
||||
:to="{ name: 'list.create', params: { namespaceId: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="plus"
|
||||
>
|
||||
{{ $t('menu.newList') }}
|
||||
</dropdown-item>
|
||||
<dropdown-item
|
||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id } }"
|
||||
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="archive"
|
||||
>
|
||||
{{ $t('menu.archive') }}
|
||||
|
@ -51,7 +51,7 @@
|
|||
type="dropdown"
|
||||
/>
|
||||
<dropdown-item
|
||||
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id } }"
|
||||
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||
icon="trash-alt"
|
||||
class="has-text-danger"
|
||||
>
|
||||
|
|
|
@ -44,10 +44,10 @@ export function useRouteWithModal() {
|
|||
function closeModal() {
|
||||
const historyState = computed(() => route.fullPath && window.history.state)
|
||||
|
||||
if (historyState.value) {
|
||||
if (historyState.value === undefined) {
|
||||
router.back()
|
||||
} else {
|
||||
const backdropRoute = historyState.value?.backdropView && router.resolve(historyState.value.backdropView)
|
||||
const backdropRoute = historyState.value.backdropView && router.resolve(historyState.value.backdropView)
|
||||
router.push(backdropRoute)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export function useSavedFilter(listId?: MaybeRef<IList['id']>) {
|
|||
router.push({name: 'list.index', params: {listId: getListId(filter.value)}})
|
||||
}
|
||||
|
||||
async function saveFilter() {
|
||||
async function saveFilter(callback: () => void) {
|
||||
const response = await filterService.update(filter.value)
|
||||
await namespaceStore.loadNamespaces()
|
||||
success({message: t('filters.edit.success')})
|
||||
|
@ -123,7 +123,7 @@ export function useSavedFilter(listId?: MaybeRef<IList['id']>) {
|
|||
id: getListId(filter.value),
|
||||
title: filter.value.title,
|
||||
}))
|
||||
router.back()
|
||||
callback()
|
||||
}
|
||||
|
||||
async function deleteFilter() {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
transition-name="fade"
|
||||
variant="hint-modal"
|
||||
>
|
||||
>
|
||||
<template #default="{onClose}">
|
||||
<card
|
||||
class="has-no-shadow"
|
||||
:title="$t('about.title')"
|
||||
:has-close="true"
|
||||
@close="$router.back()"
|
||||
@close="onClose"
|
||||
:padding="false"
|
||||
>
|
||||
<div class="p-4">
|
||||
|
@ -22,12 +22,13 @@
|
|||
<template #footer>
|
||||
<x-button
|
||||
variant="secondary"
|
||||
@click.prevent.stop="$router.back()"
|
||||
@click="onClose"
|
||||
>
|
||||
{{ $t('misc.close') }}
|
||||
</x-button>
|
||||
</template>
|
||||
</card>
|
||||
</template>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<template v-if="defaultNamespaceId > 0">
|
||||
<p class="mt-4">{{ $t('home.list.newText') }}</p>
|
||||
<x-button
|
||||
:to="{ name: 'list.create', params: { namespaceId: defaultNamespaceId } }"
|
||||
:to="{ name: 'list.create', params: { namespaceId: defaultNamespaceId }, state: { backdropView: $route.fullPath } }"
|
||||
:shadow="false"
|
||||
class="ml-2"
|
||||
>
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
@submit="deleteFilter()"
|
||||
>
|
||||
<modal @submit="deleteFilter()">
|
||||
<template #header>
|
||||
<span>{{ $t('filters.delete.header') }}</span>
|
||||
</template>
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
@primary="saveFilter"
|
||||
:tertiary="$t('misc.delete')"
|
||||
@tertiary="$router.push({ name: 'filter.settings.delete', params: { id: listId } })"
|
||||
#default="{onClose}"
|
||||
>
|
||||
<form @submit.prevent="saveFilter()">
|
||||
<form @submit.prevent="saveFilter(onClose)">
|
||||
<div class="field">
|
||||
<label class="label" for="title">{{ $t('filters.attributes.title') }}</label>
|
||||
<div class="control">
|
||||
<input
|
||||
:class="{ 'disabled': filterService.loading}"
|
||||
:disabled="filterService.loading || undefined"
|
||||
@keyup.enter="saveFilter"
|
||||
@keyup.enter="saveFilter(onClose)"
|
||||
class="input"
|
||||
id="title"
|
||||
:placeholder="$t('filters.attributes.titlePlaceholder')"
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
variant="hint-modal"
|
||||
>
|
||||
<modal variant="hint-modal">
|
||||
<card class="has-no-shadow" :title="$t('filters.create.title')">
|
||||
<p>
|
||||
{{ $t('filters.create.description') }}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<template>
|
||||
<div :class="{ 'is-loading': loading}" class="loader-container">
|
||||
<x-button
|
||||
:to="{name:'labels.create'}"
|
||||
:to="{
|
||||
name:'labels.create',
|
||||
state: { backdropView: $route.fullPath }
|
||||
}"
|
||||
class="is-pulled-right"
|
||||
icon="plus"
|
||||
>
|
||||
|
@ -15,7 +18,10 @@
|
|||
</p>
|
||||
<p v-else class="has-text-centered has-text-grey is-italic">
|
||||
{{ $t('label.newCTA') }}
|
||||
<router-link :to="{name:'labels.create'}">{{ $t('label.create.title') }}.</router-link>
|
||||
<router-link :to="{
|
||||
name:'labels.create',
|
||||
state: { backdropView: $route.fullPath }
|
||||
}">{{ $t('label.create.title') }}.</router-link>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
>
|
||||
<card
|
||||
:title="list.title"
|
||||
>
|
||||
<modal>
|
||||
<card :title="list.title">
|
||||
<div class="has-text-left" v-html="htmlDescription" v-if="htmlDescription !== ''"></div>
|
||||
<p v-else class="is-italic">
|
||||
{{ $t('list.noDescriptionAvailable') }}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<create-edit :title="$t('list.create.header')" @create="createNewList()" :primary-disabled="list.title === ''">
|
||||
<create-edit
|
||||
:title="$t('list.create.header')"
|
||||
@create="createNewList()"
|
||||
:primary-disabled="list.title === ''"
|
||||
#default="{onClose}"
|
||||
>
|
||||
<div class="field">
|
||||
<label class="label" for="listTitle">{{ $t('list.title') }}</label>
|
||||
<div
|
||||
|
@ -9,7 +14,7 @@
|
|||
<input
|
||||
:class="{ disabled: listService.loading }"
|
||||
@keyup.enter="createNewList()"
|
||||
@keyup.esc="$router.back()"
|
||||
@keyup.esc="onClose"
|
||||
class="input"
|
||||
:placeholder="$t('list.create.titlePlaceholder')"
|
||||
type="text"
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
@submit="archiveList()"
|
||||
>
|
||||
<modal @submit="archiveList">
|
||||
<template #header><span>{{ list.isArchived ? $t('list.archive.unarchive') : $t('list.archive.archive') }}</span></template>
|
||||
|
||||
<template #text>
|
||||
|
@ -17,7 +14,7 @@ export default {name: 'list-setting-archive'}
|
|||
|
||||
<script setup lang="ts">
|
||||
import {computed} from 'vue'
|
||||
import {useRouter, useRoute} from 'vue-router'
|
||||
import {useRoute} from 'vue-router'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import {success} from '@/message'
|
||||
|
@ -28,13 +25,12 @@ import {useListStore} from '@/stores/lists'
|
|||
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
const listStore = useListStore()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const list = computed(() => listStore.getListById(route.params.listId))
|
||||
useTitle(() => t('list.archive.title', {list: list.value.title}))
|
||||
|
||||
async function archiveList() {
|
||||
async function archiveList(onClose: () => void) {
|
||||
try {
|
||||
const newList = await listStore.updateList({
|
||||
...list.value,
|
||||
|
@ -43,7 +39,7 @@ async function archiveList() {
|
|||
useBaseStore().setCurrentList(newList)
|
||||
success({message: t('list.archive.success')})
|
||||
} finally {
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -73,19 +73,19 @@
|
|||
</x-button>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<template #footer="{onClose}">
|
||||
<x-button
|
||||
v-if="hasBackground"
|
||||
:shadow="false"
|
||||
variant="tertiary"
|
||||
class="is-danger"
|
||||
@click.prevent.stop="removeBackground"
|
||||
@click="removeBackground(onClose)"
|
||||
>
|
||||
{{ $t('list.background.remove') }}
|
||||
</x-button>
|
||||
<x-button
|
||||
variant="secondary"
|
||||
@click.prevent.stop="$router.back()"
|
||||
@click="onClose"
|
||||
>
|
||||
{{ $t('misc.close') }}
|
||||
</x-button>
|
||||
|
@ -100,7 +100,7 @@ export default { name: 'list-setting-background' }
|
|||
<script setup lang="ts">
|
||||
import {ref, computed, shallowReactive} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {useRoute} from 'vue-router'
|
||||
import debounce from 'lodash.debounce'
|
||||
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
|
@ -127,7 +127,6 @@ const SEARCH_DEBOUNCE = 300
|
|||
const {t} = useI18n({useScope: 'global'})
|
||||
const baseStore = useBaseStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
useTitle(() => t('list.background.title'))
|
||||
|
||||
|
@ -216,13 +215,13 @@ async function uploadBackground() {
|
|||
success({message: t('list.background.success')})
|
||||
}
|
||||
|
||||
async function removeBackground() {
|
||||
async function removeBackground(onClose: () => void) {
|
||||
const list = await listService.value.removeBackground(currentList.value)
|
||||
await baseStore.handleSetCurrentList({list, forceUpdate: true})
|
||||
namespaceStore.setListInNamespaceById(list)
|
||||
listStore.setList(list)
|
||||
success({message: t('list.background.removeSuccess')})
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
@submit="deleteList()"
|
||||
>
|
||||
<modal @submit="deleteList()">
|
||||
<template #header><span>{{ $t('list.delete.header') }}</span></template>
|
||||
|
||||
<template #text>
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
:primary-label="$t('misc.save')"
|
||||
@primary="save"
|
||||
:tertiary="$t('misc.delete')"
|
||||
@tertiary="$router.push({ name: 'list.settings.delete', params: { id: listId } })"
|
||||
@tertiary="$router.push({ name: 'list.settings.delete', params: { id: listId }, state: {backdropView: $route.fullPath} })"
|
||||
#default="{onClose}"
|
||||
>
|
||||
<div class="field">
|
||||
<label class="label" for="title">{{ $t('list.title') }}</label>
|
||||
|
@ -13,7 +14,7 @@
|
|||
<input
|
||||
:class="{ 'disabled': isLoading}"
|
||||
:disabled="isLoading || undefined"
|
||||
@keyup.enter="save"
|
||||
@keyup.enter="save(onClose)"
|
||||
class="input"
|
||||
id="title"
|
||||
:placeholder="$t('list.edit.titlePlaceholder')"
|
||||
|
@ -33,7 +34,7 @@
|
|||
<input
|
||||
:class="{ 'disabled': isLoading}"
|
||||
:disabled="isLoading || undefined"
|
||||
@keyup.enter="save"
|
||||
@keyup.enter="save(onClose)"
|
||||
class="input"
|
||||
id="identifier"
|
||||
:placeholder="$t('list.edit.identifierPlaceholder')"
|
||||
|
@ -71,7 +72,6 @@ export default { name: 'list-setting-edit' }
|
|||
|
||||
<script setup lang="ts">
|
||||
import type {PropType} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import Editor from '@/components/input/AsyncEditor'
|
||||
|
@ -92,17 +92,15 @@ const props = defineProps({
|
|||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
|
||||
const {list, save: saveList, isLoading} = useList(props.listId)
|
||||
|
||||
useTitle(() => list?.title ? t('list.edit.title', {list: list.title}) : '')
|
||||
|
||||
async function save() {
|
||||
async function save(onClose: () => void) {
|
||||
await saveList()
|
||||
await useBaseStore().handleSetCurrentList({list})
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
</fancycheckbox>
|
||||
|
||||
<div class="action-buttons">
|
||||
<x-button :to="{name: 'filters.create'}" icon="filter">
|
||||
<x-button :to="{name: 'filters.create', state: {backdropView: $route.fullPath}}" icon="filter">
|
||||
{{ $t('filters.create.title') }}
|
||||
</x-button>
|
||||
<x-button :to="{name: 'namespace.create'}" icon="plus" v-cy="'new-namespace'">
|
||||
<x-button :to="{name: 'namespace.create', state: {backdropView: $route.fullPath}}" icon="plus" v-cy="'new-namespace'">
|
||||
{{ $t('namespace.create.title') }}
|
||||
</x-button>
|
||||
</div>
|
||||
|
@ -17,7 +17,7 @@
|
|||
|
||||
<p v-if="namespaces.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
||||
{{ $t('namespace.noneAvailable') }}
|
||||
<BaseButton :to="{name: 'namespace.create'}">
|
||||
<BaseButton :to="{name: 'namespace.create', state: {backdropView: $route.fullPath}}">
|
||||
{{ $t('namespace.create.title') }}.
|
||||
</BaseButton>
|
||||
</p>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<section :key="`n${n.id}`" class="namespace" v-for="n in namespaces">
|
||||
<x-button
|
||||
v-if="n.id > 0 && n.lists.length > 0"
|
||||
:to="{name: 'list.create', params: {namespaceId: n.id}}"
|
||||
:to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropView: $route.fullPath }}"
|
||||
class="is-pulled-right"
|
||||
variant="secondary"
|
||||
icon="plus"
|
||||
|
@ -34,7 +34,7 @@
|
|||
</x-button>
|
||||
<x-button
|
||||
v-if="n.isArchived"
|
||||
:to="{name: 'namespace.settings.archive', params: {id: n.id}}"
|
||||
:to="{name: 'namespace.settings.archive', params: {id: n.id}, state: { backdropView: $route.fullPath } }"
|
||||
class="is-pulled-right mr-4"
|
||||
variant="secondary"
|
||||
icon="archive"
|
||||
|
@ -51,7 +51,7 @@
|
|||
|
||||
<p v-if="n.lists.length === 0" class="has-text-centered has-text-grey mt-4 is-italic">
|
||||
{{ $t('namespace.noLists') }}
|
||||
<BaseButton :to="{name: 'list.create', params: {namespaceId: n.id}}">
|
||||
<BaseButton :to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropView: $route.fullPath }}">
|
||||
{{ $t('namespace.createList') }}
|
||||
</BaseButton>
|
||||
</p>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
<template>
|
||||
<create-edit
|
||||
:title="$t('namespace.create.title')"
|
||||
@create="newNamespace()"
|
||||
@create="newNamespace"
|
||||
:primary-disabled="namespace.title === ''"
|
||||
#default="{onClose}"
|
||||
>
|
||||
<div class="field">
|
||||
<label class="label" for="namespaceTitle">{{ $t('namespace.attributes.title') }}</label>
|
||||
|
@ -14,8 +15,8 @@
|
|||
But with the input modal here since it autofocuses the input that input field catches the focus instead.
|
||||
Hence we place the listener on the input field directly. -->
|
||||
<input
|
||||
@keyup.enter="newNamespace()"
|
||||
@keyup.esc="$router.back()"
|
||||
@keyup.enter="newNamespace(onClose)"
|
||||
@keyup.esc="onClose"
|
||||
class="input"
|
||||
:placeholder="$t('namespace.attributes.titlePlaceholder')"
|
||||
type="text"
|
||||
|
@ -46,7 +47,6 @@
|
|||
<script setup lang="ts">
|
||||
import {ref, shallowReactive} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {useRouter} from 'vue-router'
|
||||
|
||||
import Message from '@/components/misc/message.vue'
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
|
@ -65,11 +65,10 @@ const namespace = ref<INamespace>(new NamespaceModel())
|
|||
const namespaceService = shallowReactive(new NamespaceService())
|
||||
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
const router = useRouter()
|
||||
|
||||
useTitle(() => t('namespace.create.title'))
|
||||
|
||||
async function newNamespace() {
|
||||
async function newNamespace(onClose: () => void) {
|
||||
if (namespace.value.title === '') {
|
||||
showError.value = true
|
||||
return
|
||||
|
@ -79,6 +78,6 @@ async function newNamespace() {
|
|||
const newNamespace = await namespaceService.create(namespace.value)
|
||||
useNamespaceStore().addNamespace(newNamespace)
|
||||
success({message: t('namespace.create.success')})
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
@submit="archiveNamespace()"
|
||||
>
|
||||
<modal @submit="archiveNamespace">
|
||||
<template #header><span>{{ title }}</span></template>
|
||||
|
||||
<template #text>
|
||||
|
@ -23,7 +20,6 @@ export default { name: 'namespace-setting-archive' }
|
|||
|
||||
<script setup lang="ts">
|
||||
import {watch, ref, computed, shallowReactive, type PropType} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import {success} from '@/message'
|
||||
|
@ -41,7 +37,6 @@ const props = defineProps({
|
|||
},
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
|
||||
const namespaceStore = useNamespaceStore()
|
||||
|
@ -69,7 +64,7 @@ const title = computed(() => {
|
|||
})
|
||||
useTitle(title)
|
||||
|
||||
async function archiveNamespace() {
|
||||
async function archiveNamespace(onClose: () => void) {
|
||||
try {
|
||||
const isArchived = !namespace.value.isArchived
|
||||
const archivedNamespace = await namespaceService.update({
|
||||
|
@ -83,7 +78,7 @@ async function archiveNamespace() {
|
|||
: t('namespace.archive.unarchiveSuccess'),
|
||||
})
|
||||
} finally {
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
<template>
|
||||
<modal
|
||||
@close="$router.back()"
|
||||
@submit="deleteNamespace()"
|
||||
>
|
||||
<modal @submit="deleteNamespace()">
|
||||
<template #header><span>{{ title }}</span></template>
|
||||
|
||||
<template #text>
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
:primary-label="$t('misc.save')"
|
||||
@primary="save"
|
||||
:tertiary="$t('misc.delete')"
|
||||
@tertiary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id } })"
|
||||
@tertiary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id }, state: { backdropView: $route.fullPath } })"
|
||||
#default="{onClose}"
|
||||
>
|
||||
<form @submit.prevent="save()">
|
||||
<form @submit.prevent="save(onClose)">
|
||||
<div class="field">
|
||||
<label class="label" for="namespacetext">{{ $t('namespace.attributes.title') }}</label>
|
||||
<div class="control">
|
||||
|
@ -58,7 +59,6 @@
|
|||
<script lang="ts" setup>
|
||||
import {nextTick, ref, watch} from 'vue'
|
||||
import {success} from '@/message'
|
||||
import router from '@/router'
|
||||
|
||||
import AsyncEditor from '@/components/input/AsyncEditor'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
|
@ -110,11 +110,11 @@ async function loadNamespace() {
|
|||
title.value = t('namespace.edit.title', {namespace: namespace.value.title})
|
||||
}
|
||||
|
||||
async function save() {
|
||||
async function save(onClose: () => void) {
|
||||
const updatedNamespace = await namespaceService.value.update(namespace.value)
|
||||
// Update the namespace in the parent
|
||||
namespaceStore.setNamespaceById(updatedNamespace)
|
||||
success({message: t('namespace.edit.success')})
|
||||
router.back()
|
||||
onClose()
|
||||
}
|
||||
</script>
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<OptionalWrapper :is="isModal && Modal" variant="scrolling">
|
||||
<div
|
||||
class="loader-container task-view-container"
|
||||
:class="{
|
||||
|
@ -442,10 +443,11 @@
|
|||
</template>
|
||||
</modal>
|
||||
</div>
|
||||
</OptionalWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, toRef, shallowReactive, computed, watch, nextTick, type PropType} from 'vue'
|
||||
import {ref, reactive, toRef, shallowReactive, computed, watch, nextTick, type PropType, useAttrs} from 'vue'
|
||||
import {useRouter, type RouteLocation} from 'vue-router'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {unrefElement} from '@vueuse/core'
|
||||
|
@ -480,7 +482,10 @@ import RelatedTasks from '@/components/tasks/partials/relatedTasks.vue'
|
|||
import Reminders from '@/components/tasks/partials/reminders.vue'
|
||||
import RepeatAfter from '@/components/tasks/partials/repeatAfter.vue'
|
||||
import TaskSubscription from '@/components/misc/subscription.vue'
|
||||
|
||||
import OptionalWrapper from '@/components/base/OptionalWrapper.vue'
|
||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||
import Modal from '@/components/misc/modal.vue'
|
||||
|
||||
import {uploadFile} from '@/helpers/attachments'
|
||||
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
|
||||
|
@ -508,7 +513,8 @@ const props = defineProps({
|
|||
})
|
||||
|
||||
defineEmits(['close'])
|
||||
|
||||
const attrs = useAttrs()
|
||||
console.log(JSON.parse(JSON.stringify(attrs)))
|
||||
const router = useRouter()
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
<template>
|
||||
<div class="content loader-container is-max-width-desktop" :class="{ 'is-loading': teamService.loading}">
|
||||
<x-button
|
||||
:to="{name:'teams.create'}"
|
||||
:to="{
|
||||
name:'teams.create',
|
||||
state: { backdropView: $route.fullPath },
|
||||
}"
|
||||
class="is-pulled-right"
|
||||
icon="plus"
|
||||
>
|
||||
|
@ -18,7 +21,10 @@
|
|||
</ul>
|
||||
<p v-else-if="!teamService.loading" class="has-text-centered has-text-grey is-italic">
|
||||
{{ $t('team.noTeams') }}
|
||||
<router-link :to="{name: 'teams.create'}">
|
||||
<router-link :to="{
|
||||
name: 'teams.create',
|
||||
state: { backdropView: $route.fullPath },
|
||||
}">
|
||||
{{ $t('team.create.title') }}.
|
||||
</router-link>
|
||||
</p>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<create-edit
|
||||
class="new-team"
|
||||
:title="title"
|
||||
@create="newTeam()"
|
||||
:primary-disabled="team.name === ''"
|
||||
|
|
Reference in New Issue