feat: create BaseButton component (#1123)
Co-authored-by: Dominik Pschenitschni <mail@celement.de> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/1123 Reviewed-by: konrad <k@knt.li> Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de> Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:
parent
cb37fd773d
commit
cdbd1c2ac4
39 changed files with 254 additions and 146 deletions
|
@ -101,7 +101,7 @@ describe('Lists', () => {
|
||||||
.click()
|
.click()
|
||||||
cy.url()
|
cy.url()
|
||||||
.should('contain', '/settings/delete')
|
.should('contain', '/settings/delete')
|
||||||
cy.get('.modal-mask .modal-container .modal-content .actions a.button')
|
cy.get('[data-cy="modalPrimary"]')
|
||||||
.contains('Do it')
|
.contains('Do it')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ describe('Lists', () => {
|
||||||
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input')
|
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input')
|
||||||
.first()
|
.first()
|
||||||
.type(3)
|
.type(3)
|
||||||
cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field a.button.is-primary')
|
cy.get('[data-cy="setBucketLimit"]')
|
||||||
.first()
|
.first()
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ describe('Namepaces', () => {
|
||||||
.click()
|
.click()
|
||||||
cy.url()
|
cy.url()
|
||||||
.should('contain', '/settings/delete')
|
.should('contain', '/settings/delete')
|
||||||
cy.get('.modal-mask .modal-container .modal-content .actions a.button')
|
cy.get('[data-cy="modalPrimary"]')
|
||||||
.contains('Do it')
|
.contains('Do it')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ describe('Task', () => {
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .details.content.description .editor .vue-easymde .EasyMDEContainer .CodeMirror-scroll')
|
cy.get('.task-view .details.content.description .editor .vue-easymde .EasyMDEContainer .CodeMirror-scroll')
|
||||||
.type('{selectall}New Description')
|
.type('{selectall}New Description')
|
||||||
cy.get('.task-view .details.content.description .editor a')
|
cy.get('[data-cy="saveEditor"]')
|
||||||
.contains('Save')
|
.contains('Save')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ describe('Task', () => {
|
||||||
cy.get('.datepicker .datepicker-popup a')
|
cy.get('.datepicker .datepicker-popup a')
|
||||||
.contains('Tomorrow')
|
.contains('Tomorrow')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.datepicker .datepicker-popup a.button')
|
cy.get('[data-cy="closeDatepicker"]')
|
||||||
.contains('Confirm')
|
.contains('Confirm')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ describe('User Settings', () => {
|
||||||
.trigger('mousedown', {which: 1})
|
.trigger('mousedown', {which: 1})
|
||||||
.trigger('mousemove', {clientY: 100})
|
.trigger('mousemove', {clientY: 100})
|
||||||
.trigger('mouseup')
|
.trigger('mouseup')
|
||||||
cy.get('a.button.is-primary')
|
cy.get('[data-cy="uploadAvatar"]')
|
||||||
.contains('Upload Avatar')
|
.contains('Upload Avatar')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ describe('User Settings', () => {
|
||||||
cy.get('.general-settings .control input.input')
|
cy.get('.general-settings .control input.input')
|
||||||
.first()
|
.first()
|
||||||
.type('Lorem Ipsum')
|
.type('Lorem Ipsum')
|
||||||
cy.get('.card.general-settings .button.is-primary')
|
cy.get('[data-cy="saveGeneralSettings"]')
|
||||||
.contains('Save')
|
.contains('Save')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<ready :class="{'is-touch': isTouch}">
|
<ready>
|
||||||
|
<div :class="{'is-touch': isTouch}">
|
||||||
<div :class="{'is-hidden': !online}">
|
<div :class="{'is-hidden': !online}">
|
||||||
<template v-if="authUser">
|
<template v-if="authUser">
|
||||||
<top-navigation/>
|
<top-navigation/>
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<keyboard-shortcuts v-if="keyboardShortcutsActive"/>
|
<keyboard-shortcuts v-if="keyboardShortcutsActive"/>
|
||||||
</transition>
|
</transition>
|
||||||
|
</div>
|
||||||
</ready>
|
</ready>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
118
src/components/base/BaseButton.vue
Normal file
118
src/components/base/BaseButton.vue
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
<template>
|
||||||
|
<component
|
||||||
|
:is="componentNodeName"
|
||||||
|
class="base-button"
|
||||||
|
:class="{ 'base-button--type-button': isButton }"
|
||||||
|
v-bind="elementBindings"
|
||||||
|
:disabled="disabled || undefined"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
// see https://v3.vuejs.org/api/sfc-script-setup.html#usage-alongside-normal-script
|
||||||
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
// this component removes styling differences between links / vue-router links and button elements
|
||||||
|
// by doing so we make it easy abstract the functionality from style and enable easier and semantic
|
||||||
|
// correct button and link usage. Also see: https://css-tricks.com/a-complete-guide-to-links-and-buttons/#accessibility-considerations
|
||||||
|
|
||||||
|
// the component tries to heuristically determine what it should be checking the props (see the
|
||||||
|
// componentNodeName and elementBindings ref for this).
|
||||||
|
|
||||||
|
// NOTE: Do NOT use buttons with @click to push routes. => Use router-links instead!
|
||||||
|
|
||||||
|
import { ref, watchEffect, computed, useAttrs, PropType } from 'vue'
|
||||||
|
|
||||||
|
const BASE_BUTTON_TYPES_MAP = Object.freeze({
|
||||||
|
button: 'button',
|
||||||
|
submit: 'submit',
|
||||||
|
})
|
||||||
|
|
||||||
|
type BaseButtonTypes = keyof typeof BASE_BUTTON_TYPES_MAP
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String as PropType<BaseButtonTypes>,
|
||||||
|
default: 'button',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const componentNodeName = ref<Node['nodeName']>('button')
|
||||||
|
interface ElementBindings {
|
||||||
|
type?: string;
|
||||||
|
rel?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementBindings = ref({})
|
||||||
|
|
||||||
|
const attrs = useAttrs()
|
||||||
|
watchEffect(() => {
|
||||||
|
// by default this component is a button element with the attribute of the type "button" (default prop value)
|
||||||
|
let nodeName = 'button'
|
||||||
|
let bindings: ElementBindings = {type: props.type}
|
||||||
|
|
||||||
|
// if we find a "to" prop we set it as router-link
|
||||||
|
if ('to' in attrs) {
|
||||||
|
nodeName = 'router-link'
|
||||||
|
bindings = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is a href we assume the user wants an external link via a link element
|
||||||
|
// we also set the attribute rel to "noopener" but make it possible to overwrite this by the user.
|
||||||
|
if ('href' in attrs) {
|
||||||
|
nodeName = 'a'
|
||||||
|
bindings = {rel: 'noopener'}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentNodeName.value = nodeName
|
||||||
|
elementBindings.value = {
|
||||||
|
...bindings,
|
||||||
|
...attrs,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isButton = computed(() => componentNodeName.value === 'button')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
// NOTE: we do not use scoped styles to reduce specifity and make it easy to overwrite
|
||||||
|
|
||||||
|
// We reset the default styles of a button element to enable easier styling
|
||||||
|
:where(.base-button--type-button) {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
text-align: center;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.base-button) {
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
color: inherit;
|
||||||
|
font: inherit;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: auto; // disable possible resets
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -37,7 +37,7 @@
|
||||||
<dropdown class="is-right" ref="usernameDropdown">
|
<dropdown class="is-right" ref="usernameDropdown">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<x-button
|
<x-button
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
:shadow="false">
|
:shadow="false">
|
||||||
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
<span class="username">{{ userInfo.name !== '' ? userInfo.name : userInfo.username }}</span>
|
||||||
<span class="icon is-small">
|
<span class="icon is-small">
|
||||||
|
|
|
@ -1,41 +1,45 @@
|
||||||
<template>
|
<template>
|
||||||
<a
|
<BaseButton
|
||||||
class="button"
|
class="button"
|
||||||
:class="{
|
:class="[
|
||||||
|
variantClass,
|
||||||
|
{
|
||||||
'is-loading': loading,
|
'is-loading': loading,
|
||||||
'has-no-shadow': !shadow,
|
'has-no-shadow': !shadow || variant === 'tertiary',
|
||||||
'is-primary': type === 'primary',
|
}
|
||||||
'is-outlined': type === 'secondary',
|
]"
|
||||||
'is-text is-inverted has-no-shadow underline-none':
|
|
||||||
type === 'tertary',
|
|
||||||
}"
|
|
||||||
:disabled="disabled || null"
|
|
||||||
@click="click"
|
|
||||||
:href="href !== '' ? href : null"
|
|
||||||
>
|
>
|
||||||
<icon :icon="icon" v-if="showIconOnly"/>
|
<icon :icon="icon" v-if="showIconOnly"/>
|
||||||
<span class="icon is-small" v-else-if="icon !== ''">
|
<span class="icon is-small" v-else-if="icon !== ''">
|
||||||
<icon :icon="icon"/>
|
<icon :icon="icon"/>
|
||||||
</span>
|
</span>
|
||||||
<slot></slot>
|
<slot />
|
||||||
</a>
|
</BaseButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'x-button',
|
name: 'x-button',
|
||||||
props: {
|
}
|
||||||
type: {
|
</script>
|
||||||
type: String,
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {computed, useSlots, PropType} from 'vue'
|
||||||
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
|
|
||||||
|
const BUTTON_TYPES_MAP = Object.freeze({
|
||||||
|
primary: 'is-primary',
|
||||||
|
secondary: 'is-outlined',
|
||||||
|
tertiary: 'is-text is-inverted underline-none',
|
||||||
|
})
|
||||||
|
|
||||||
|
type ButtonTypes = keyof typeof BUTTON_TYPES_MAP
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
variant: {
|
||||||
|
type: String as PropType<ButtonTypes>,
|
||||||
default: 'primary',
|
default: 'primary',
|
||||||
},
|
},
|
||||||
href: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
to: {
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
icon: {
|
icon: {
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
@ -47,31 +51,12 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
disabled: {
|
})
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['click'],
|
|
||||||
computed: {
|
|
||||||
showIconOnly() {
|
|
||||||
return this.icon !== '' && typeof this.$slots.default === 'undefined'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
click(e) {
|
|
||||||
if (this.disabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.to !== false) {
|
const variantClass = computed(() => BUTTON_TYPES_MAP[props.variant])
|
||||||
this.$router.push(this.to)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit('click', e)
|
const slots = useSlots()
|
||||||
},
|
const showIconOnly = computed(() => props.icon !== '' && typeof slots.default === 'undefined')
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -83,8 +68,8 @@ export default {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: $button-height;
|
height: $button-height;
|
||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-sm);
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
&.is-hovered,
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: var(--shadow-md);
|
box-shadow: var(--shadow-md);
|
||||||
}
|
}
|
||||||
|
@ -106,9 +91,10 @@ export default {
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-small {
|
}
|
||||||
|
|
||||||
|
.is-small {
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.underline-none {
|
.underline-none {
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
@click="reset"
|
@click="reset"
|
||||||
class="is-small ml-2"
|
class="is-small ml-2"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('input.resetColor') }}
|
{{ $t('input.resetColor') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -101,6 +101,7 @@
|
||||||
class="is-fullwidth"
|
class="is-fullwidth"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
@click="close"
|
@click="close"
|
||||||
|
v-cy="'closeDatepicker'"
|
||||||
>
|
>
|
||||||
{{ $t('misc.confirm') }}
|
{{ $t('misc.confirm') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<a @click="toggleEdit">{{ $t('input.editor.edit') }}</a>
|
<a @click="toggleEdit">{{ $t('input.editor.edit') }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<x-button v-else-if="isEditActive" @click="toggleEdit" type="secondary" :shadow="false">
|
<x-button v-else-if="isEditActive" @click="toggleEdit" variant="secondary" :shadow="false" v-cy="'saveEditor'">
|
||||||
{{ $t('misc.save') }}
|
{{ $t('misc.save') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<x-button
|
<x-button
|
||||||
v-if="hasFilters"
|
v-if="hasFilters"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
@click="clearFilters"
|
@click="clearFilters"
|
||||||
>
|
>
|
||||||
{{ $t('filters.clear') }}
|
{{ $t('filters.clear') }}
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<template #trigger="{toggle}">
|
<template #trigger="{toggle}">
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="toggle()"
|
@click.prevent.stop="toggle()"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="filter"
|
icon="filter"
|
||||||
>
|
>
|
||||||
{{ $t('filters.title') }}
|
{{ $t('filters.title') }}
|
||||||
|
|
|
@ -14,25 +14,25 @@
|
||||||
</div>
|
</div>
|
||||||
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
|
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
|
||||||
<x-button
|
<x-button
|
||||||
|
v-if="tertiary !== ''"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="tertary"
|
variant="tertiary"
|
||||||
@click.prevent.stop="$emit('tertary')"
|
@click.prevent.stop="$emit('tertiary')"
|
||||||
v-if="tertary !== ''"
|
|
||||||
>
|
>
|
||||||
{{ tertary }}
|
{{ tertiary }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
@click.prevent.stop="$router.back()"
|
@click.prevent.stop="$router.back()"
|
||||||
>
|
>
|
||||||
{{ $t('misc.cancel') }}
|
{{ $t('misc.cancel') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
type="primary"
|
v-if="primaryLabel !== ''"
|
||||||
|
variant="primary"
|
||||||
@click.prevent.stop="primary"
|
@click.prevent.stop="primary"
|
||||||
:icon="primaryIcon"
|
:icon="primaryIcon"
|
||||||
:disabled="primaryDisabled"
|
:disabled="primaryDisabled"
|
||||||
v-if="primaryLabel !== ''"
|
|
||||||
>
|
>
|
||||||
{{ primaryLabel }}
|
{{ primaryLabel }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -65,7 +65,7 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
tertary: {
|
tertiary: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
@ -78,7 +78,7 @@ export default {
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
emits: ['create', 'primary', 'tertary'],
|
emits: ['create', 'primary', 'tertiary'],
|
||||||
methods: {
|
methods: {
|
||||||
primary() {
|
primary() {
|
||||||
this.$emit('create')
|
this.$emit('create')
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
@click="action.callback"
|
@click="action.callback"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
class="is-small"
|
class="is-small"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-for="(action, i) in item.data.actions"
|
v-for="(action, i) in item.data.actions"
|
||||||
>
|
>
|
||||||
{{ action.title }}
|
{{ action.title }}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<x-button
|
<x-button
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
:icon="icon"
|
:icon="icon"
|
||||||
v-tooltip="tooltipText"
|
v-tooltip="tooltipText"
|
||||||
@click="changeSubscription"
|
@click="changeSubscription"
|
||||||
|
|
|
@ -31,14 +31,15 @@
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<x-button
|
<x-button
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
type="tertary"
|
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')"
|
||||||
type="primary"
|
variant="primary"
|
||||||
|
v-cy="'modalPrimary'"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
>
|
>
|
||||||
{{ $t('misc.doit') }}
|
{{ $t('misc.doit') }}
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
@click="$refs.files.click()"
|
@click="$refs.files.click()"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
icon="cloud-upload-alt"
|
icon="cloud-upload-alt"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
>
|
>
|
||||||
{{ $t('task.attachment.upload') }}
|
{{ $t('task.attachment.upload') }}
|
||||||
|
|
|
@ -8,21 +8,21 @@
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="() => deferDays(1)"
|
@click.prevent.stop="() => deferDays(1)"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('task.deferDueDate.1day') }}
|
{{ $t('task.deferDueDate.1day') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="() => deferDays(3)"
|
@click.prevent.stop="() => deferDays(3)"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('task.deferDueDate.3days') }}
|
{{ $t('task.deferDueDate.3days') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="() => deferDays(7)"
|
@click.prevent.stop="() => deferDays(7)"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('task.deferDueDate.1week') }}
|
{{ $t('task.deferDueDate.1week') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
class="is-pulled-right add-task-relation-button"
|
class="is-pulled-right add-task-relation-button"
|
||||||
:class="{'is-active': showNewRelationForm}"
|
:class="{'is-active': showNewRelationForm}"
|
||||||
v-tooltip="$t('task.relation.add')"
|
v-tooltip="$t('task.relation.add')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="control repeat-after-input">
|
<div class="control repeat-after-input">
|
||||||
<div class="buttons has-addons is-centered mt-2">
|
<div class="buttons has-addons is-centered mt-2">
|
||||||
<x-button type="secondary" class="is-small" @click="() => setRepeatAfter(1, 'days')">{{ $t('task.repeat.everyDay') }}</x-button>
|
<x-button variant="secondary" class="is-small" @click="() => setRepeatAfter(1, 'days')">{{ $t('task.repeat.everyDay') }}</x-button>
|
||||||
<x-button type="secondary" class="is-small" @click="() => setRepeatAfter(1, 'weeks')">{{ $t('task.repeat.everyWeek') }}</x-button>
|
<x-button variant="secondary" class="is-small" @click="() => setRepeatAfter(1, 'weeks')">{{ $t('task.repeat.everyWeek') }}</x-button>
|
||||||
<x-button type="secondary" class="is-small" @click="() => setRepeatAfter(1, 'months')">{{ $t('task.repeat.everyMonth') }}</x-button>
|
<x-button variant="secondary" class="is-small" @click="() => setRepeatAfter(1, 'months')">{{ $t('task.repeat.everyMonth') }}</x-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="is-flex is-align-items-center mb-2">
|
<div class="is-flex is-align-items-center mb-2">
|
||||||
<label for="repeatMode" class="is-fullwidth">
|
<label for="repeatMode" class="is-fullwidth">
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import {createApp, configureCompat} from 'vue'
|
import {createApp, configureCompat} from 'vue'
|
||||||
|
|
||||||
|
// default everything to Vue 3 behavior
|
||||||
configureCompat({
|
configureCompat({
|
||||||
COMPONENT_V_MODEL: false,
|
MODE: 3,
|
||||||
COMPONENT_ASYNC: false,
|
|
||||||
RENDER_FUNCTION: false,
|
|
||||||
WATCH_ARRAY: false, // TODO: check this again; this might lead to some problemes
|
|
||||||
TRANSITION_GROUP_ROOT: false,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
</div>
|
</div>
|
||||||
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
|
<footer class="modal-card-foot is-flex is-justify-content-flex-end">
|
||||||
<x-button
|
<x-button
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
@click.prevent.stop="$router.back()"
|
@click.prevent.stop="$router.back()"
|
||||||
>
|
>
|
||||||
{{ $t('misc.close') }}
|
{{ $t('misc.close') }}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
primary-icon=""
|
primary-icon=""
|
||||||
:primary-label="$t('misc.save')"
|
:primary-label="$t('misc.save')"
|
||||||
@primary="saveSavedFilter"
|
@primary="saveSavedFilter"
|
||||||
:tertary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertary="$router.push({ name: 'filter.settings.delete', params: { id: $route.params.listId } })"
|
@tertiary="$router.push({ name: 'filter.settings.delete', params: { id: $route.params.listId } })"
|
||||||
>
|
>
|
||||||
<form @submit.prevent="saveSavedFilter()">
|
<form @submit.prevent="saveSavedFilter()">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
class="list-background-setting"
|
class="list-background-setting"
|
||||||
:wide="true"
|
:wide="true"
|
||||||
v-if="uploadBackgroundEnabled || unsplashBackgroundEnabled"
|
v-if="uploadBackgroundEnabled || unsplashBackgroundEnabled"
|
||||||
:tertary="hasBackground ? $t('list.background.remove') : ''"
|
:tertiary="hasBackground ? $t('list.background.remove') : ''"
|
||||||
@tertary="removeBackground()"
|
@tertiary="removeBackground()"
|
||||||
>
|
>
|
||||||
<div class="mb-4" v-if="uploadBackgroundEnabled">
|
<div class="mb-4" v-if="uploadBackgroundEnabled">
|
||||||
<input
|
<input
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
:loading="backgroundUploadService.loading"
|
:loading="backgroundUploadService.loading"
|
||||||
@click="$refs.backgroundUploadInput.click()"
|
@click="$refs.backgroundUploadInput.click()"
|
||||||
type="primary"
|
variant="primary"
|
||||||
>
|
>
|
||||||
{{ $t('list.background.upload') }}
|
{{ $t('list.background.upload') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
@click="() => searchBackgrounds(currentPage + 1)"
|
@click="() => searchBackgrounds(currentPage + 1)"
|
||||||
class="is-load-more-button mt-4"
|
class="is-load-more-button mt-4"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-if="backgroundSearchResult.length > 0"
|
v-if="backgroundSearchResult.length > 0"
|
||||||
>
|
>
|
||||||
{{ backgroundService.loading ? $t('misc.loading') : $t('list.background.loadMore') }}
|
{{ backgroundService.loading ? $t('misc.loading') : $t('list.background.loadMore') }}
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
primary-icon=""
|
primary-icon=""
|
||||||
:primary-label="$t('misc.save')"
|
:primary-label="$t('misc.save')"
|
||||||
@primary="save"
|
@primary="save"
|
||||||
:tertary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertary="$router.push({ name: 'list.list.settings.delete', params: { id: $route.params.listId } })"
|
@tertiary="$router.push({ name: 'list.list.settings.delete', params: { id: $route.params.listId } })"
|
||||||
>
|
>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="title">{{ $t('list.title') }}</label>
|
<label class="label" for="title">{{ $t('list.title') }}</label>
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
:disabled="bucket.limit < 0"
|
:disabled="bucket.limit < 0"
|
||||||
:icon="['far', 'save']"
|
:icon="['far', 'save']"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
|
v-cy="'setBucketLimit'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -165,7 +166,7 @@
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
v-if="!showNewTaskInput[bucket.id]"
|
v-if="!showNewTaskInput[bucket.id]"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
bucket.tasks.length === 0 ? $t('list.kanban.addTask') : $t('list.kanban.addAnotherTask')
|
bucket.tasks.length === 0 ? $t('list.kanban.addTask') : $t('list.kanban.addAnotherTask')
|
||||||
|
@ -195,7 +196,7 @@
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
class="is-transparent is-fullwidth has-text-centered"
|
class="is-transparent is-fullwidth has-text-centered"
|
||||||
v-else
|
v-else
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
{{ $t('list.kanban.addBucket') }}
|
{{ $t('list.kanban.addBucket') }}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
@click="showTaskSearch = !showTaskSearch"
|
@click="showTaskSearch = !showTaskSearch"
|
||||||
icon="search"
|
icon="search"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-if="!showTaskSearch"
|
v-if="!showTaskSearch"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
@click.prevent.stop="toggle()"
|
@click.prevent.stop="toggle()"
|
||||||
icon="th"
|
icon="th"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('list.table.columns') }}
|
{{ $t('list.table.columns') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
</p>
|
</p>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<x-button @click="migrate">{{ $t('migrate.confirm') }}</x-button>
|
<x-button @click="migrate">{{ $t('migrate.confirm') }}</x-button>
|
||||||
<x-button :to="{name: 'home'}" type="tertary" class="has-text-danger">{{ $t('misc.cancel') }}</x-button>
|
<x-button :to="{name: 'home'}" variant="tertiary" class="has-text-danger">{{ $t('misc.cancel') }}</x-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
:to="{name: 'list.create', params: {id: n.id}}"
|
:to="{name: 'list.create', params: {id: n.id}}"
|
||||||
class="is-pulled-right"
|
class="is-pulled-right"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-if="n.id > 0 && n.lists.length > 0"
|
v-if="n.id > 0 && n.lists.length > 0"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
:to="{name: 'namespace.settings.archive', params: {id: n.id}}"
|
:to="{name: 'namespace.settings.archive', params: {id: n.id}}"
|
||||||
class="is-pulled-right mr-4"
|
class="is-pulled-right mr-4"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-if="n.isArchived"
|
v-if="n.isArchived"
|
||||||
icon="archive"
|
icon="archive"
|
||||||
>
|
>
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
primary-icon=""
|
primary-icon=""
|
||||||
:primary-label="$t('misc.save')"
|
:primary-label="$t('misc.save')"
|
||||||
@primary="save"
|
@primary="save"
|
||||||
:tertary="$t('misc.delete')"
|
:tertiary="$t('misc.delete')"
|
||||||
@tertary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id } })"
|
@tertiary="$router.push({ name: 'namespace.settings.delete', params: { id: $route.params.id } })"
|
||||||
>
|
>
|
||||||
<form @submit.prevent="save()">
|
<form @submit.prevent="save()">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
@ -32,9 +32,9 @@
|
||||||
/>
|
/>
|
||||||
</h3>
|
</h3>
|
||||||
<div v-if="!showAll" class="mb-4">
|
<div v-if="!showAll" class="mb-4">
|
||||||
<x-button type="secondary" @click="showTodaysTasks()" class="mr-2">{{ $t('task.show.today') }}</x-button>
|
<x-button variant="secondary" @click="showTodaysTasks()" class="mr-2">{{ $t('task.show.today') }}</x-button>
|
||||||
<x-button type="secondary" @click="setDatesToNextWeek()" class="mr-2">{{ $t('task.show.nextWeek') }}</x-button>
|
<x-button variant="secondary" @click="setDatesToNextWeek()" class="mr-2">{{ $t('task.show.nextWeek') }}</x-button>
|
||||||
<x-button type="secondary" @click="setDatesToNextMonth()">{{ $t('task.show.nextMonth') }}</x-button>
|
<x-button variant="secondary" @click="setDatesToNextMonth()">{{ $t('task.show.nextMonth') }}</x-button>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="!loading && (!tasks || tasks.length === 0) && showNothingToDo">
|
<template v-if="!loading && (!tasks || tasks.length === 0) && showNothingToDo">
|
||||||
<h3 class="nothing">{{ $t('task.show.noTasks') }}</h3>
|
<h3 class="nothing">{{ $t('task.show.noTasks') }}</h3>
|
||||||
|
|
|
@ -258,7 +258,7 @@
|
||||||
@click="toggleTaskDone()"
|
@click="toggleTaskDone()"
|
||||||
class="is-outlined has-no-border"
|
class="is-outlined has-no-border"
|
||||||
icon="check-double"
|
icon="check-double"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ task.done ? $t('task.detail.undone') : $t('task.detail.done') }}
|
{{ task.done ? $t('task.detail.undone') : $t('task.detail.done') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -270,7 +270,7 @@
|
||||||
/>
|
/>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('assignees')"
|
@click="setFieldActive('assignees')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
v-shortcut="'a'"
|
v-shortcut="'a'"
|
||||||
v-cy="'taskDetail.assign'"
|
v-cy="'taskDetail.assign'"
|
||||||
>
|
>
|
||||||
|
@ -279,7 +279,7 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('labels')"
|
@click="setFieldActive('labels')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="tags"
|
icon="tags"
|
||||||
v-shortcut="'l'"
|
v-shortcut="'l'"
|
||||||
>
|
>
|
||||||
|
@ -287,14 +287,14 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('priority')"
|
@click="setFieldActive('priority')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="exclamation"
|
icon="exclamation"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.priority') }}
|
{{ $t('task.detail.actions.priority') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('dueDate')"
|
@click="setFieldActive('dueDate')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="calendar"
|
icon="calendar"
|
||||||
v-shortcut="'d'"
|
v-shortcut="'d'"
|
||||||
>
|
>
|
||||||
|
@ -302,42 +302,42 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('startDate')"
|
@click="setFieldActive('startDate')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="play"
|
icon="play"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.startDate') }}
|
{{ $t('task.detail.actions.startDate') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('endDate')"
|
@click="setFieldActive('endDate')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="stop"
|
icon="stop"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.endDate') }}
|
{{ $t('task.detail.actions.endDate') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('reminders')"
|
@click="setFieldActive('reminders')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
:icon="['far', 'clock']"
|
:icon="['far', 'clock']"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.reminders') }}
|
{{ $t('task.detail.actions.reminders') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('repeatAfter')"
|
@click="setFieldActive('repeatAfter')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="history"
|
icon="history"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.repeatAfter') }}
|
{{ $t('task.detail.actions.repeatAfter') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('percentDone')"
|
@click="setFieldActive('percentDone')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="percent"
|
icon="percent"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.percentDone') }}
|
{{ $t('task.detail.actions.percentDone') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('attachments')"
|
@click="setFieldActive('attachments')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="paperclip"
|
icon="paperclip"
|
||||||
v-shortcut="'f'"
|
v-shortcut="'f'"
|
||||||
>
|
>
|
||||||
|
@ -345,7 +345,7 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('relatedTasks')"
|
@click="setFieldActive('relatedTasks')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="sitemap"
|
icon="sitemap"
|
||||||
v-shortcut="'r'"
|
v-shortcut="'r'"
|
||||||
>
|
>
|
||||||
|
@ -353,21 +353,21 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('moveList')"
|
@click="setFieldActive('moveList')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="list"
|
icon="list"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.moveList') }}
|
{{ $t('task.detail.actions.moveList') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="setFieldActive('color')"
|
@click="setFieldActive('color')"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
icon="fill-drip"
|
icon="fill-drip"
|
||||||
>
|
>
|
||||||
{{ $t('task.detail.actions.color') }}
|
{{ $t('task.detail.actions.color') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button
|
<x-button
|
||||||
@click="toggleFavorite"
|
@click="toggleFavorite"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
:icon="task.isFavorite ? 'star' : ['far', 'star']"
|
:icon="task.isFavorite ? 'star' : ['far', 'star']"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
:to="{ name: 'user.register' }"
|
:to="{ name: 'user.register' }"
|
||||||
v-if="registrationEnabled"
|
v-if="registrationEnabled"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
{{ $t('user.auth.register') }}
|
{{ $t('user.auth.register') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
@click="redirectToProvider(p)"
|
@click="redirectToProvider(p)"
|
||||||
v-for="(p, k) in openidConnect.providers"
|
v-for="(p, k) in openidConnect.providers"
|
||||||
:key="k"
|
:key="k"
|
||||||
type="secondary"
|
variant="secondary"
|
||||||
class="is-fullwidth mt-2"
|
class="is-fullwidth mt-2"
|
||||||
>
|
>
|
||||||
{{ $t('user.auth.loginWith', {provider: p.name}) }}
|
{{ $t('user.auth.loginWith', {provider: p.name}) }}
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
>
|
>
|
||||||
{{ $t('user.auth.register') }}
|
{{ $t('user.auth.register') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button :to="{ name: 'user.login' }" type="secondary">
|
<x-button :to="{ name: 'user.login' }" variant="secondary">
|
||||||
{{ $t('user.auth.login') }}
|
{{ $t('user.auth.login') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
>
|
>
|
||||||
{{ $t('user.auth.resetPasswordAction') }}
|
{{ $t('user.auth.resetPasswordAction') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button :to="{ name: 'user.login' }" type="secondary">
|
<x-button :to="{ name: 'user.login' }" variant="secondary">
|
||||||
{{ $t('user.auth.login') }}
|
{{ $t('user.auth.login') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
<x-button
|
<x-button
|
||||||
:loading="avatarService.loading || loading"
|
:loading="avatarService.loading || loading"
|
||||||
@click="uploadAvatar"
|
@click="uploadAvatar"
|
||||||
|
v-cy="'uploadAvatar'"
|
||||||
>
|
>
|
||||||
{{ $t('user.settings.avatar.uploadAvatar') }}
|
{{ $t('user.settings.avatar.uploadAvatar') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -110,6 +110,7 @@
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@click="updateSettings()"
|
@click="updateSettings()"
|
||||||
class="is-fullwidth mt-4"
|
class="is-fullwidth mt-4"
|
||||||
|
v-cy="'saveGeneralSettings'"
|
||||||
>
|
>
|
||||||
{{ $t('misc.save') }}
|
{{ $t('misc.save') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<x-button @click="totpDisable" class="is-danger">
|
<x-button @click="totpDisable" class="is-danger">
|
||||||
{{ $t('user.settings.totp.disable') }}
|
{{ $t('user.settings.totp.disable') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
<x-button @click="totpDisableForm = false" type="tertary" class="ml-2">
|
<x-button @click="totpDisableForm = false" variant="tertiary" class="ml-2">
|
||||||
{{ $t('misc.cancel') }}
|
{{ $t('misc.cancel') }}
|
||||||
</x-button>
|
</x-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue