WIP: feat: route modals everywhere #2735
|
@ -19,7 +19,7 @@ describe('Team', () => {
|
||||||
.contains('Create a new team')
|
.contains('Create a new team')
|
||||||
cy.get('input.input')
|
cy.get('input.input')
|
||||||
.type(newTeamName)
|
.type(newTeamName)
|
||||||
cy.get('.button')
|
cy.get('.new-team button')
|
||||||
.contains('Create')
|
.contains('Create')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!-- https://github.com/vuejs/rfcs/pull/449 -->
|
||||||
dpschen marked this conversation as resolved
Outdated
|
|||||||
|
<!-- 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)))
|
||||||
dpschen marked this conversation as resolved
Outdated
|
|||||||
|
</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) }}
|
{{ currentList.title === '' ? $t('misc.loading') : getListTitle(currentList) }}
|
||||||
</h1>
|
</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"/>
|
<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'}"
|
:to="{name: 'about', state: {backdropView: $route.fullPath}}"
|
||||||
>
|
>
|
||||||
{{ $t('about.title') }}
|
{{ $t('about.title') }}
|
||||||
</dropdown-item>
|
</dropdown-item>
|
||||||
|
|
|
@ -38,14 +38,10 @@
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
||||||
<modal
|
<component
|
||||||
dpschen
commented
Every modal component now has to provide it's own modal. This makes it possible for us to have different modal implementations. Currently we do this by changing the Every modal component now has to provide it's own modal.
This makes it possible for us to have different modal implementations. Currently we do this by changing the `type` prop of the modal. It might be easier for us if we create something like a `BaseModal` to abstract the general modal functionality and then use that to create styled Modals with specific functionality. For example we coudl create a dedicated `Dialog` modal (this might actually be the same as the current `create-edit`, I'm not sure here if that was the intended use @konrad).
konrad
commented
That sounds like it could be a good idea. IIRC my main goal with the That sounds like it could be a good idea.
IIRC my main goal with the `create-edit` component was to be able to easily re-use a shell for creating or editing.
|
|||||||
:enabled="Boolean(currentModal)"
|
:is="currentModal"
|
||||||
@close="closeModal()"
|
@close="closeModal()"
|
||||||
variant="scrolling"
|
/>
|
||||||
class="task-detail-view-modal"
|
|
||||||
>
|
|
||||||
<component :is="currentModal"/>
|
|
||||||
</modal>
|
|
||||||
|
|
||||||
<BaseButton
|
<BaseButton
|
||||||
class="keyboard-shortcuts-button d-print-none"
|
class="keyboard-shortcuts-button d-print-none"
|
||||||
|
|
|
@ -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 } }"
|
:to="{ name: 'filter.settings.edit', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'filter.settings.delete', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.edit', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.background', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.share', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.duplicate', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.archive', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
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 } }"
|
:to="{ name: 'list.settings.delete', params: { listId: list.id }, state: {backdropView: $route.fullPath} }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
class="has-text-danger"
|
class="has-text-danger"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<modal @close="$router.back()" :overflow="true" :wide="wide">
|
<modal :overflow="true" :wide="wide" #default="{ onClose }">
|
||||||
dpschen
commented
I removed the I removed the `@close` event definitions on all internal modals because what happens when that event get's fired should instead be defined by the parent. By removing this the parents `onClose` / `@close` should automatically be passed to the `<modal>`.
By passing the `onClose` then to the slot content, the slot is still able to use the method.
|
|||||||
<card
|
<card
|
||||||
:title="title"
|
:title="title"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
:padding="false"
|
:padding="false"
|
||||||
class="has-text-left"
|
class="has-text-left"
|
||||||
:has-close="true"
|
:has-close="true"
|
||||||
@close="$router.back()"
|
@close="onClose"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<slot/>
|
<slot :onClose="onClose" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<slot name="footer">
|
<slot name="footer" :onClose="onClose">
|
||||||
<x-button
|
<x-button
|
||||||
v-if="tertiary !== ''"
|
v-if="tertiary !== ''"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
@click.prevent.stop="$emit('tertiary')"
|
@click="$emit('tertiary')"
|
||||||
>
|
>
|
||||||
{{ tertiary }}
|
{{ tertiary }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@click.prevent.stop="$router.back()"
|
@click="onClose"
|
||||||
>
|
>
|
||||||
{{ $t('misc.cancel') }}
|
{{ $t('misc.cancel') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
v-if="hasPrimaryAction"
|
v-if="hasPrimaryAction"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
@click.prevent.stop="primary()"
|
@click="primary(onClose)"
|
||||||
:icon="primaryIcon"
|
:icon="primaryIcon"
|
||||||
:disabled="primaryDisabled || loading"
|
:disabled="primaryDisabled || loading"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
|
@ -83,10 +83,11 @@ defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 'close'
|
||||||
const emit = defineEmits(['create', 'primary', 'tertiary'])
|
const emit = defineEmits(['create', 'primary', 'tertiary'])
|
||||||
|
|
||||||
function primary() {
|
function primary(onClose: () => void) {
|
||||||
dpschen
commented
We pass We pass `onClose` as a callback parameter to the `primary` emit so that it can reuse the `onClose` after the primary action finished (unsure if that makes sense).
|
|||||||
emit('create')
|
emit('create', onClose)
|
||||||
emit('primary')
|
emit('primary', onClose)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<!-- FIXME: transition should not be included in the modal -->
|
<!-- FIXME: transition should not be included in the modal -->
|
||||||
<CustomTransition :name="transitionName" appear>
|
<CustomTransition :name="transitionName" appear :appear-class="transitionName">
|
||||||
dpschen
commented
The appear transition is currently broken. Fix this. The appear transition is currently broken. Fix this.
|
|||||||
<section
|
<section
|
||||||
v-if="enabled"
|
v-if="enabled"
|
||||||
class="modal-mask"
|
class="modal-mask"
|
||||||
|
@ -10,11 +10,11 @@
|
||||||
variant,
|
variant,
|
||||||
]"
|
]"
|
||||||
ref="modal"
|
ref="modal"
|
||||||
v-bind="attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="modal-container"
|
class="modal-container"
|
||||||
@click.self.prevent.stop="$emit('close')"
|
@click.self.prevent.stop="onClose"
|
||||||
v-shortcut="'Escape'"
|
v-shortcut="'Escape'"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
@ -25,13 +25,13 @@
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
@click="$emit('close')"
|
@click="onClose"
|
||||||
class="close"
|
class="close"
|
||||||
>
|
>
|
||||||
<icon icon="times"/>
|
<icon icon="times"/>
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
|
|
||||||
<slot>
|
<slot name="default" :onClose="onClose">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -40,14 +40,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<x-button
|
<x-button
|
||||||
@click="$emit('close')"
|
@click="onClose"
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
class="has-text-danger"
|
class="has-text-danger"
|
||||||
>
|
>
|
||||||
{{ $t('misc.cancel') }}
|
{{ $t('misc.cancel') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="$emit('submit')"
|
@click="$emit('submit', onClose)"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
v-cy="'modalPrimary'"
|
v-cy="'modalPrimary'"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
|
@ -70,10 +70,11 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import {ref, watchEffect} from 'vue'
|
||||||
|
import {useScrollLock} from '@vueuse/core'
|
||||||
|
|
||||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import {ref, useAttrs, watchEffect} from 'vue'
|
|
||||||
import {useScrollLock} from '@vueuse/core'
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
enabled?: boolean,
|
enabled?: boolean,
|
||||||
|
@ -87,9 +88,7 @@ const props = withDefaults(defineProps<{
|
||||||
variant: 'default',
|
variant: 'default',
|
||||||
})
|
})
|
||||||
|
|
||||||
defineEmits(['close', 'submit'])
|
const emit = defineEmits(['close', 'submit'])
|
||||||
|
|
||||||
const attrs = useAttrs()
|
|
||||||
|
|
||||||
const modal = ref<HTMLElement | null>(null)
|
const modal = ref<HTMLElement | null>(null)
|
||||||
const scrollLock = useScrollLock(modal)
|
const scrollLock = useScrollLock(modal)
|
||||||
|
@ -97,6 +96,10 @@ const scrollLock = useScrollLock(modal)
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
scrollLock.value = props.enabled
|
scrollLock.value = props.enabled
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
dpschen
commented
FIXME: either we use an implicit FIXME: either we use an implicit `attrs.onClose` or we explicit define a `close` emit. Both should not be mixed.
|
|||||||
|
emit('close')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -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 } }"
|
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
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 } }"
|
:to="{ name: 'namespace.settings.edit', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
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 } }"
|
:to="{ name: 'namespace.settings.share', params: { namespaceId: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
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 } }"
|
:to="{ name: 'list.create', params: { namespaceId: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
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 } }"
|
:to="{ name: 'namespace.settings.archive', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
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 } }"
|
:to="{ name: 'namespace.settings.delete', params: { id: namespace.id }, state: { backdropView: $route.fullPath } }"
|
||||||
icon="trash-alt"
|
icon="trash-alt"
|
||||||
class="has-text-danger"
|
class="has-text-danger"
|
||||||
>
|
>
|
||||||
|
|
|
@ -44,10 +44,10 @@ export function useRouteWithModal() {
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
const historyState = computed(() => route.fullPath && window.history.state)
|
const historyState = computed(() => route.fullPath && window.history.state)
|
||||||
|
|
||||||
if (historyState.value) {
|
if (historyState.value === undefined) {
|
||||||
dpschen
commented
Something was broken here: since we checked for Something was broken here: since we checked for `historyState.value` in the `if` condition it could never have a value in the `else` cause.
|
|||||||
router.back()
|
router.back()
|
||||||
} else {
|
} else {
|
||||||
const backdropRoute = historyState.value?.backdropView && router.resolve(historyState.value.backdropView)
|
const backdropRoute = historyState.value.backdropView && router.resolve(historyState.value.backdropView)
|
||||||
router.push(backdropRoute)
|
router.push(backdropRoute)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ export function useSavedFilter(listId?: MaybeRef<IList['id']>) {
|
||||||
router.push({name: 'list.index', params: {listId: getListId(filter.value)}})
|
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)
|
const response = await filterService.update(filter.value)
|
||||||
await namespaceStore.loadNamespaces()
|
await namespaceStore.loadNamespaces()
|
||||||
success({message: t('filters.edit.success')})
|
success({message: t('filters.edit.success')})
|
||||||
|
@ -123,7 +123,7 @@ export function useSavedFilter(listId?: MaybeRef<IList['id']>) {
|
||||||
id: getListId(filter.value),
|
id: getListId(filter.value),
|
||||||
title: filter.value.title,
|
title: filter.value.title,
|
||||||
}))
|
}))
|
||||||
router.back()
|
callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteFilter() {
|
async function deleteFilter() {
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal
|
||||||
@close="$router.back()"
|
|
||||||
transition-name="fade"
|
transition-name="fade"
|
||||||
variant="hint-modal"
|
variant="hint-modal"
|
||||||
>
|
>
|
||||||
|
<template #default="{onClose}">
|
||||||
<card
|
<card
|
||||||
class="has-no-shadow"
|
class="has-no-shadow"
|
||||||
:title="$t('about.title')"
|
:title="$t('about.title')"
|
||||||
:has-close="true"
|
:has-close="true"
|
||||||
@close="$router.back()"
|
@close="onClose"
|
||||||
:padding="false"
|
:padding="false"
|
||||||
>
|
>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
|
@ -22,12 +22,13 @@
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@click.prevent.stop="$router.back()"
|
@click="onClose"
|
||||||
>
|
>
|
||||||
{{ $t('misc.close') }}
|
{{ $t('misc.close') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</template>
|
</template>
|
||||||
</card>
|
</card>
|
||||||
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -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 } }"
|
:to="{ name: 'list.create', params: { namespaceId: defaultNamespaceId }, state: { backdropView: $route.fullPath } }"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal @submit="deleteFilter()">
|
||||||
@close="$router.back()"
|
|
||||||
@submit="deleteFilter()"
|
|
||||||
>
|
|
||||||
<template #header>
|
<template #header>
|
||||||
<span>{{ $t('filters.delete.header') }}</span>
|
<span>{{ $t('filters.delete.header') }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
@primary="saveFilter"
|
@primary="saveFilter"
|
||||||
:tertiary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertiary="$router.push({ name: 'filter.settings.delete', params: { id: listId } })"
|
@tertiary="$router.push({ name: 'filter.settings.delete', params: { id: listId } })"
|
||||||
|
#default="{onClose}"
|
||||||
>
|
>
|
||||||
<form @submit.prevent="saveFilter()">
|
<form @submit.prevent="saveFilter(onClose)">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="title">{{ $t('filters.attributes.title') }}</label>
|
<label class="label" for="title">{{ $t('filters.attributes.title') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<input
|
<input
|
||||||
:class="{ 'disabled': filterService.loading}"
|
:class="{ 'disabled': filterService.loading}"
|
||||||
:disabled="filterService.loading || undefined"
|
:disabled="filterService.loading || undefined"
|
||||||
@keyup.enter="saveFilter"
|
@keyup.enter="saveFilter(onClose)"
|
||||||
class="input"
|
class="input"
|
||||||
id="title"
|
id="title"
|
||||||
:placeholder="$t('filters.attributes.titlePlaceholder')"
|
:placeholder="$t('filters.attributes.titlePlaceholder')"
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal variant="hint-modal">
|
||||||
@close="$router.back()"
|
|
||||||
variant="hint-modal"
|
|
||||||
>
|
|
||||||
<card class="has-no-shadow" :title="$t('filters.create.title')">
|
<card class="has-no-shadow" :title="$t('filters.create.title')">
|
||||||
<p>
|
<p>
|
||||||
{{ $t('filters.create.description') }}
|
{{ $t('filters.create.description') }}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="{ 'is-loading': loading}" class="loader-container">
|
<div :class="{ 'is-loading': loading}" class="loader-container">
|
||||||
<x-button
|
<x-button
|
||||||
:to="{name:'labels.create'}"
|
:to="{
|
||||||
|
name:'labels.create',
|
||||||
|
state: { backdropView: $route.fullPath }
|
||||||
|
}"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -15,7 +18,10 @@
|
||||||
</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="{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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal>
|
||||||
@close="$router.back()"
|
<card :title="list.title">
|
||||||
>
|
|
||||||
<card
|
|
||||||
:title="list.title"
|
|
||||||
>
|
|
||||||
<div class="has-text-left" v-html="htmlDescription" v-if="htmlDescription !== ''"></div>
|
<div class="has-text-left" v-html="htmlDescription" v-if="htmlDescription !== ''"></div>
|
||||||
<p v-else class="is-italic">
|
<p v-else class="is-italic">
|
||||||
{{ $t('list.noDescriptionAvailable') }}
|
{{ $t('list.noDescriptionAvailable') }}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<template>
|
<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">
|
<div class="field">
|
||||||
<label class="label" for="listTitle">{{ $t('list.title') }}</label>
|
<label class="label" for="listTitle">{{ $t('list.title') }}</label>
|
||||||
<div
|
<div
|
||||||
|
@ -9,7 +14,7 @@
|
||||||
<input
|
<input
|
||||||
:class="{ disabled: listService.loading }"
|
:class="{ disabled: listService.loading }"
|
||||||
@keyup.enter="createNewList()"
|
@keyup.enter="createNewList()"
|
||||||
@keyup.esc="$router.back()"
|
@keyup.esc="onClose"
|
||||||
class="input"
|
class="input"
|
||||||
:placeholder="$t('list.create.titlePlaceholder')"
|
:placeholder="$t('list.create.titlePlaceholder')"
|
||||||
type="text"
|
type="text"
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal @submit="archiveList">
|
||||||
@close="$router.back()"
|
|
||||||
@submit="archiveList()"
|
|
||||||
>
|
|
||||||
<template #header><span>{{ list.isArchived ? $t('list.archive.unarchive') : $t('list.archive.archive') }}</span></template>
|
<template #header><span>{{ list.isArchived ? $t('list.archive.unarchive') : $t('list.archive.archive') }}</span></template>
|
||||||
|
|
||||||
<template #text>
|
<template #text>
|
||||||
|
@ -17,7 +14,7 @@ export default {name: 'list-setting-archive'}
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed} from 'vue'
|
import {computed} from 'vue'
|
||||||
import {useRouter, useRoute} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
|
@ -28,13 +25,12 @@ import {useListStore} from '@/stores/lists'
|
||||||
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
const listStore = useListStore()
|
const listStore = useListStore()
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const list = computed(() => listStore.getListById(route.params.listId))
|
const list = computed(() => listStore.getListById(route.params.listId))
|
||||||
useTitle(() => t('list.archive.title', {list: list.value.title}))
|
useTitle(() => t('list.archive.title', {list: list.value.title}))
|
||||||
|
|
||||||
async function archiveList() {
|
async function archiveList(onClose: () => void) {
|
||||||
try {
|
try {
|
||||||
const newList = await listStore.updateList({
|
const newList = await listStore.updateList({
|
||||||
...list.value,
|
...list.value,
|
||||||
|
@ -43,7 +39,7 @@ async function archiveList() {
|
||||||
useBaseStore().setCurrentList(newList)
|
useBaseStore().setCurrentList(newList)
|
||||||
success({message: t('list.archive.success')})
|
success({message: t('list.archive.success')})
|
||||||
} finally {
|
} finally {
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -73,19 +73,19 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer="{onClose}">
|
||||||
<x-button
|
<x-button
|
||||||
v-if="hasBackground"
|
v-if="hasBackground"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
class="is-danger"
|
class="is-danger"
|
||||||
@click.prevent.stop="removeBackground"
|
@click="removeBackground(onClose)"
|
||||||
dpschen
commented
We should not need to use We should not need to use `.prevent` and `.stop` with the vueuse `onClickOutside`.
|
|||||||
>
|
>
|
||||||
{{ $t('list.background.remove') }}
|
{{ $t('list.background.remove') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
@click.prevent.stop="$router.back()"
|
@click="onClose"
|
||||||
>
|
>
|
||||||
{{ $t('misc.close') }}
|
{{ $t('misc.close') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -100,7 +100,7 @@ export default { name: 'list-setting-background' }
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, computed, shallowReactive} from 'vue'
|
import {ref, computed, shallowReactive} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {useRoute, useRouter} from 'vue-router'
|
import {useRoute} from 'vue-router'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
|
@ -127,7 +127,6 @@ const SEARCH_DEBOUNCE = 300
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
const baseStore = useBaseStore()
|
const baseStore = useBaseStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
useTitle(() => t('list.background.title'))
|
useTitle(() => t('list.background.title'))
|
||||||
|
|
||||||
|
@ -216,13 +215,13 @@ async function uploadBackground() {
|
||||||
success({message: t('list.background.success')})
|
success({message: t('list.background.success')})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeBackground() {
|
async function removeBackground(onClose: () => void) {
|
||||||
const list = await listService.value.removeBackground(currentList.value)
|
const list = await listService.value.removeBackground(currentList.value)
|
||||||
await baseStore.handleSetCurrentList({list, forceUpdate: true})
|
await baseStore.handleSetCurrentList({list, forceUpdate: true})
|
||||||
namespaceStore.setListInNamespaceById(list)
|
namespaceStore.setListInNamespaceById(list)
|
||||||
listStore.setList(list)
|
listStore.setList(list)
|
||||||
success({message: t('list.background.removeSuccess')})
|
success({message: t('list.background.removeSuccess')})
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal @submit="deleteList()">
|
||||||
@close="$router.back()"
|
|
||||||
@submit="deleteList()"
|
|
||||||
>
|
|
||||||
<template #header><span>{{ $t('list.delete.header') }}</span></template>
|
<template #header><span>{{ $t('list.delete.header') }}</span></template>
|
||||||
|
|
||||||
<template #text>
|
<template #text>
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
: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 } })"
|
@tertiary="$router.push({ name: 'list.settings.delete', params: { id: listId }, state: {backdropView: $route.fullPath} })"
|
||||||
|
#default="{onClose}"
|
||||||
>
|
>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="title">{{ $t('list.title') }}</label>
|
<label class="label" for="title">{{ $t('list.title') }}</label>
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
<input
|
<input
|
||||||
:class="{ 'disabled': isLoading}"
|
:class="{ 'disabled': isLoading}"
|
||||||
:disabled="isLoading || undefined"
|
:disabled="isLoading || undefined"
|
||||||
@keyup.enter="save"
|
@keyup.enter="save(onClose)"
|
||||||
class="input"
|
class="input"
|
||||||
id="title"
|
id="title"
|
||||||
:placeholder="$t('list.edit.titlePlaceholder')"
|
:placeholder="$t('list.edit.titlePlaceholder')"
|
||||||
|
@ -33,7 +34,7 @@
|
||||||
<input
|
<input
|
||||||
:class="{ 'disabled': isLoading}"
|
:class="{ 'disabled': isLoading}"
|
||||||
:disabled="isLoading || undefined"
|
:disabled="isLoading || undefined"
|
||||||
@keyup.enter="save"
|
@keyup.enter="save(onClose)"
|
||||||
class="input"
|
class="input"
|
||||||
id="identifier"
|
id="identifier"
|
||||||
:placeholder="$t('list.edit.identifierPlaceholder')"
|
:placeholder="$t('list.edit.identifierPlaceholder')"
|
||||||
|
@ -71,7 +72,6 @@ export default { name: 'list-setting-edit' }
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type {PropType} from 'vue'
|
import type {PropType} from 'vue'
|
||||||
import {useRouter} from 'vue-router'
|
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import Editor from '@/components/input/AsyncEditor'
|
import Editor from '@/components/input/AsyncEditor'
|
||||||
|
@ -92,17 +92,15 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
const {list, save: saveList, isLoading} = useList(props.listId)
|
const {list, save: saveList, isLoading} = useList(props.listId)
|
||||||
|
|
||||||
useTitle(() => list?.title ? t('list.edit.title', {list: list.title}) : '')
|
useTitle(() => list?.title ? t('list.edit.title', {list: list.title}) : '')
|
||||||
|
|
||||||
async function save() {
|
async function save(onClose: () => void) {
|
||||||
await saveList()
|
await saveList()
|
||||||
await useBaseStore().handleSetCurrentList({list})
|
await useBaseStore().handleSetCurrentList({list})
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
</fancycheckbox>
|
</fancycheckbox>
|
||||||
|
|
||||||
<div class="action-buttons">
|
<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') }}
|
{{ $t('filters.create.title') }}
|
||||||
</x-button>
|
</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') }}
|
{{ $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'}">
|
<BaseButton :to="{name: 'namespace.create', state: {backdropView: $route.fullPath}}">
|
||||||
{{ $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}}"
|
:to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropView: $route.fullPath }}"
|
||||||
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}}"
|
:to="{name: 'namespace.settings.archive', params: {id: n.id}, state: { backdropView: $route.fullPath } }"
|
||||||
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}}">
|
<BaseButton :to="{name: 'list.create', params: {namespaceId: n.id}, state: { backdropView: $route.fullPath }}">
|
||||||
{{ $t('namespace.createList') }}
|
{{ $t('namespace.createList') }}
|
||||||
</BaseButton>
|
</BaseButton>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<create-edit
|
<create-edit
|
||||||
:title="$t('namespace.create.title')"
|
:title="$t('namespace.create.title')"
|
||||||
@create="newNamespace()"
|
@create="newNamespace"
|
||||||
:primary-disabled="namespace.title === ''"
|
:primary-disabled="namespace.title === ''"
|
||||||
|
#default="{onClose}"
|
||||||
>
|
>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="namespaceTitle">{{ $t('namespace.attributes.title') }}</label>
|
<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.
|
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. -->
|
Hence we place the listener on the input field directly. -->
|
||||||
<input
|
<input
|
||||||
@keyup.enter="newNamespace()"
|
@keyup.enter="newNamespace(onClose)"
|
||||||
@keyup.esc="$router.back()"
|
@keyup.esc="onClose"
|
||||||
class="input"
|
class="input"
|
||||||
:placeholder="$t('namespace.attributes.titlePlaceholder')"
|
:placeholder="$t('namespace.attributes.titlePlaceholder')"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -46,7 +47,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, shallowReactive} from 'vue'
|
import {ref, shallowReactive} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {useRouter} from 'vue-router'
|
|
||||||
|
|
||||||
import Message from '@/components/misc/message.vue'
|
import Message from '@/components/misc/message.vue'
|
||||||
import CreateEdit from '@/components/misc/create-edit.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 namespaceService = shallowReactive(new NamespaceService())
|
||||||
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
useTitle(() => t('namespace.create.title'))
|
useTitle(() => t('namespace.create.title'))
|
||||||
|
|
||||||
async function newNamespace() {
|
async function newNamespace(onClose: () => void) {
|
||||||
if (namespace.value.title === '') {
|
if (namespace.value.title === '') {
|
||||||
showError.value = true
|
showError.value = true
|
||||||
return
|
return
|
||||||
|
@ -79,6 +78,6 @@ async function newNamespace() {
|
||||||
const newNamespace = await namespaceService.create(namespace.value)
|
const newNamespace = await namespaceService.create(namespace.value)
|
||||||
useNamespaceStore().addNamespace(newNamespace)
|
useNamespaceStore().addNamespace(newNamespace)
|
||||||
success({message: t('namespace.create.success')})
|
success({message: t('namespace.create.success')})
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal @submit="archiveNamespace">
|
||||||
@close="$router.back()"
|
|
||||||
@submit="archiveNamespace()"
|
|
||||||
>
|
|
||||||
<template #header><span>{{ title }}</span></template>
|
<template #header><span>{{ title }}</span></template>
|
||||||
|
|
||||||
<template #text>
|
<template #text>
|
||||||
|
@ -23,7 +20,6 @@ export default { name: 'namespace-setting-archive' }
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {watch, ref, computed, shallowReactive, type PropType} from 'vue'
|
import {watch, ref, computed, shallowReactive, type PropType} from 'vue'
|
||||||
import {useRouter} from 'vue-router'
|
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
|
@ -41,7 +37,6 @@ const props = defineProps({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
const namespaceStore = useNamespaceStore()
|
const namespaceStore = useNamespaceStore()
|
||||||
|
@ -69,7 +64,7 @@ const title = computed(() => {
|
||||||
})
|
})
|
||||||
useTitle(title)
|
useTitle(title)
|
||||||
|
|
||||||
async function archiveNamespace() {
|
async function archiveNamespace(onClose: () => void) {
|
||||||
try {
|
try {
|
||||||
const isArchived = !namespace.value.isArchived
|
const isArchived = !namespace.value.isArchived
|
||||||
const archivedNamespace = await namespaceService.update({
|
const archivedNamespace = await namespaceService.update({
|
||||||
|
@ -83,7 +78,7 @@ async function archiveNamespace() {
|
||||||
: t('namespace.archive.unarchiveSuccess'),
|
: t('namespace.archive.unarchiveSuccess'),
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<modal
|
<modal @submit="deleteNamespace()">
|
||||||
@close="$router.back()"
|
|
||||||
@submit="deleteNamespace()"
|
|
||||||
>
|
|
||||||
<template #header><span>{{ title }}</span></template>
|
<template #header><span>{{ title }}</span></template>
|
||||||
|
|
||||||
<template #text>
|
<template #text>
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
: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 } })"
|
@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">
|
<div class="field">
|
||||||
<label class="label" for="namespacetext">{{ $t('namespace.attributes.title') }}</label>
|
<label class="label" for="namespacetext">{{ $t('namespace.attributes.title') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
@ -58,7 +59,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {nextTick, ref, watch} from 'vue'
|
import {nextTick, ref, watch} from 'vue'
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
import router from '@/router'
|
|
||||||
|
|
||||||
import AsyncEditor from '@/components/input/AsyncEditor'
|
import AsyncEditor from '@/components/input/AsyncEditor'
|
||||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||||
|
@ -110,11 +110,11 @@ async function loadNamespace() {
|
||||||
title.value = t('namespace.edit.title', {namespace: namespace.value.title})
|
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)
|
const updatedNamespace = await namespaceService.value.update(namespace.value)
|
||||||
// Update the namespace in the parent
|
// Update the namespace in the parent
|
||||||
namespaceStore.setNamespaceById(updatedNamespace)
|
namespaceStore.setNamespaceById(updatedNamespace)
|
||||||
success({message: t('namespace.edit.success')})
|
success({message: t('namespace.edit.success')})
|
||||||
router.back()
|
onClose()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
|
@ -1,4 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
|
<OptionalWrapper :is="isModal && Modal" variant="scrolling">
|
||||||
dpschen
commented
By using the OptionalWrapper we can use components that can be used with or without Modal By using the OptionalWrapper we can use components that can be used with or without Modal
|
|||||||
<div
|
<div
|
||||||
class="loader-container task-view-container"
|
class="loader-container task-view-container"
|
||||||
:class="{
|
:class="{
|
||||||
|
@ -442,10 +443,11 @@
|
||||||
</template>
|
</template>
|
||||||
</modal>
|
</modal>
|
||||||
</div>
|
</div>
|
||||||
|
</OptionalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<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 {useRouter, type RouteLocation} from 'vue-router'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {unrefElement} from '@vueuse/core'
|
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 Reminders from '@/components/tasks/partials/reminders.vue'
|
||||||
import RepeatAfter from '@/components/tasks/partials/repeatAfter.vue'
|
import RepeatAfter from '@/components/tasks/partials/repeatAfter.vue'
|
||||||
import TaskSubscription from '@/components/misc/subscription.vue'
|
import TaskSubscription from '@/components/misc/subscription.vue'
|
||||||
|
|
||||||
|
import OptionalWrapper from '@/components/base/OptionalWrapper.vue'
|
||||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||||
|
import Modal from '@/components/misc/modal.vue'
|
||||||
|
|
||||||
import {uploadFile} from '@/helpers/attachments'
|
import {uploadFile} from '@/helpers/attachments'
|
||||||
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
|
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
|
||||||
|
@ -508,7 +513,8 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
|
|
||||||
defineEmits(['close'])
|
defineEmits(['close'])
|
||||||
|
const attrs = useAttrs()
|
||||||
|
console.log(JSON.parse(JSON.stringify(attrs)))
|
||||||
dpschen
commented
Remove log Remove log
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const {t} = useI18n({useScope: 'global'})
|
const {t} = useI18n({useScope: 'global'})
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<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="{name:'teams.create'}"
|
:to="{
|
||||||
|
name:'teams.create',
|
||||||
|
state: { backdropView: $route.fullPath },
|
||||||
|
}"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -18,7 +21,10 @@
|
||||||
</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="{name: 'teams.create'}">
|
<router-link :to="{
|
||||||
|
name: 'teams.create',
|
||||||
|
state: { backdropView: $route.fullPath },
|
||||||
|
}">
|
||||||
{{ $t('team.create.title') }}.
|
{{ $t('team.create.title') }}.
|
||||||
</router-link>
|
</router-link>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<create-edit
|
<create-edit
|
||||||
|
class="new-team"
|
||||||
:title="title"
|
:title="title"
|
||||||
@create="newTeam()"
|
@create="newTeam()"
|
||||||
:primary-disabled="team.name === ''"
|
:primary-disabled="team.name === ''"
|
||||||
|
|
This component makes it possible to optionally wrap around another component. If the
is
prop defines a component it will be rendered as a wrapper around the slot content. If theis
prop is undefined there won't be any wrapper.