Merge branch 'main' into feature/date-math
This commit is contained in:
commit
0b6a74d11e
52 changed files with 3664 additions and 3317 deletions
|
@ -120,7 +120,7 @@ steps:
|
||||||
from_secret: cypress_project_key
|
from_secret: cypress_project_key
|
||||||
commands:
|
commands:
|
||||||
- sed -i 's/localhost/api/g' dist/index.html
|
- sed -i 's/localhost/api/g' dist/index.html
|
||||||
- yarn serve:dist & npx wait-on http://localhost:5000
|
- yarn serve:dist & npx wait-on http://localhost:4173
|
||||||
- yarn test:frontend --browser chrome --record
|
- yarn test:frontend --browser chrome --record
|
||||||
depends_on:
|
depends_on:
|
||||||
- dependencies
|
- dependencies
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"baseUrl": "http://localhost:5000",
|
"baseUrl": "http://localhost:4173",
|
||||||
"env": {
|
"env": {
|
||||||
"API_URL": "http://localhost:3456/api/v1",
|
"API_URL": "http://localhost:3456/api/v1",
|
||||||
"TEST_SECRET": "averyLongSecretToSe33dtheDB"
|
"TEST_SECRET": "averyLongSecretToSe33dtheDB"
|
||||||
|
|
|
@ -132,7 +132,7 @@ describe('List View Kanban', () => {
|
||||||
cy.getSettled('.kanban .bucket .tasks .task')
|
cy.getSettled('.kanban .bucket .tasks .task')
|
||||||
.contains(tasks[0].title)
|
.contains(tasks[0].title)
|
||||||
.first()
|
.first()
|
||||||
.drag('.kanban .bucket:nth-child(2) .tasks .dropper')
|
.drag('.kanban .bucket:nth-child(2) .tasks')
|
||||||
|
|
||||||
cy.get('.kanban .bucket:nth-child(2) .tasks')
|
cy.get('.kanban .bucket:nth-child(2) .tasks')
|
||||||
.should('contain', tasks[0].title)
|
.should('contain', tasks[0].title)
|
||||||
|
@ -176,7 +176,7 @@ describe('List View Kanban', () => {
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button', { timeout: 3000 })
|
cy.get('.task-view .action-buttons .button', { timeout: 3000 })
|
||||||
.contains('Move task')
|
.contains('Move')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input')
|
cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input')
|
||||||
.type(`${lists[1].title}{enter}`)
|
.type(`${lists[1].title}{enter}`)
|
||||||
|
|
|
@ -210,7 +210,7 @@ describe('Task', () => {
|
||||||
cy.visit(`/tasks/${tasks[0].id}`)
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button')
|
cy.get('.task-view .action-buttons .button')
|
||||||
.contains('Move task')
|
.contains('Move')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input')
|
cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input')
|
||||||
.type(`${lists[1].title}{enter}`)
|
.type(`${lists[1].title}{enter}`)
|
||||||
|
@ -237,7 +237,7 @@ describe('Task', () => {
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button')
|
cy.get('.task-view .action-buttons .button')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.contains('Delete task')
|
.contains('Delete')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.modal-mask .modal-container .modal-content .header')
|
cy.get('.modal-mask .modal-container .modal-content .header')
|
||||||
.should('contain', 'Delete this task')
|
.should('contain', 'Delete this task')
|
||||||
|
@ -317,7 +317,7 @@ describe('Task', () => {
|
||||||
cy.visit(`/tasks/${tasks[0].id}`)
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button')
|
cy.get('.task-view .action-buttons .button')
|
||||||
.contains('Add labels')
|
.contains('Add Labels')
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .details.labels-list .multiselect input')
|
cy.get('.task-view .details.labels-list .multiselect input')
|
||||||
|
@ -344,7 +344,7 @@ describe('Task', () => {
|
||||||
cy.visit(`/tasks/${tasks[0].id}`)
|
cy.visit(`/tasks/${tasks[0].id}`)
|
||||||
|
|
||||||
cy.get('.task-view .action-buttons .button')
|
cy.get('.task-view .action-buttons .button')
|
||||||
.contains('Add labels')
|
.contains('Add Labels')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.task-view .details.labels-list .multiselect input')
|
cy.get('.task-view .details.labels-list .multiselect input')
|
||||||
.type(labels[0].title)
|
.type(labels[0].title)
|
||||||
|
|
|
@ -6,7 +6,7 @@ describe('Log out', () => {
|
||||||
|
|
||||||
cy.get('.navbar .user .username')
|
cy.get('.navbar .user .username')
|
||||||
.click()
|
.click()
|
||||||
cy.get('.navbar .user .dropdown-menu a.dropdown-item')
|
cy.get('.navbar .user .dropdown-menu .dropdown-item')
|
||||||
.contains('Logout')
|
.contains('Logout')
|
||||||
.click()
|
.click()
|
||||||
|
|
||||||
|
|
63
package.json
63
package.json
|
@ -5,7 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vite",
|
"serve": "vite",
|
||||||
"serve:dist-dev": "node scripts/serve-dist.js",
|
"serve:dist-dev": "node scripts/serve-dist.js",
|
||||||
"serve:dist": "vite preview",
|
"serve:dist": "vite preview --port 4173",
|
||||||
"build": "vite build && workbox copyLibraries dist/",
|
"build": "vite build && workbox copyLibraries dist/",
|
||||||
"build:modern-only": "BUILD_MODERN_ONLY=true vite build && workbox copyLibraries dist/",
|
"build:modern-only": "BUILD_MODERN_ONLY=true vite build && workbox copyLibraries dist/",
|
||||||
"build:dev": "vite build -m development --outDir dist-dev/",
|
"build:dev": "vite build -m development --outDir dist-dev/",
|
||||||
|
@ -20,18 +20,18 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@github/hotkey": "2.0.0",
|
"@github/hotkey": "2.0.0",
|
||||||
"@kyvg/vue3-notification": "2.3.4",
|
"@kyvg/vue3-notification": "2.3.4",
|
||||||
"@sentry/tracing": "6.17.4",
|
"@sentry/tracing": "6.17.9",
|
||||||
"@sentry/vue": "6.17.4",
|
"@sentry/vue": "6.17.9",
|
||||||
"@types/is-touch-device": "1.0.0",
|
"@types/is-touch-device": "1.0.0",
|
||||||
"@vue/compat": "3.2.29",
|
"@vue/compat": "3.2.31",
|
||||||
"@vueuse/core": "7.5.5",
|
"@vueuse/core": "7.6.2",
|
||||||
"@vueuse/router": "7.5.5",
|
"@vueuse/router": "7.6.2",
|
||||||
"bulma-css-variables": "0.9.33",
|
"bulma-css-variables": "0.9.33",
|
||||||
"camel-case": "4.1.2",
|
"camel-case": "4.1.2",
|
||||||
"codemirror": "5.65.1",
|
"codemirror": "5.65.1",
|
||||||
"copy-to-clipboard": "3.3.1",
|
"copy-to-clipboard": "3.3.1",
|
||||||
"date-fns": "2.28.0",
|
"date-fns": "2.28.0",
|
||||||
"dompurify": "2.3.5",
|
"dompurify": "2.3.6",
|
||||||
"easymde": "2.16.1",
|
"easymde": "2.16.1",
|
||||||
"flatpickr": "4.6.9",
|
"flatpickr": "4.6.9",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "0.7.21",
|
||||||
|
@ -44,8 +44,8 @@
|
||||||
"snake-case": "3.0.4",
|
"snake-case": "3.0.4",
|
||||||
"ufo": "0.7.10",
|
"ufo": "0.7.10",
|
||||||
"v-tooltip": "4.0.0-beta.17",
|
"v-tooltip": "4.0.0-beta.17",
|
||||||
"vue": "3.2.29",
|
"vue": "3.2.31",
|
||||||
"vue-advanced-cropper": "2.8.0",
|
"vue-advanced-cropper": "2.8.1",
|
||||||
"vue-drag-resize": "2.0.3",
|
"vue-drag-resize": "2.0.3",
|
||||||
"vue-flatpickr-component": "9.0.5",
|
"vue-flatpickr-component": "9.0.5",
|
||||||
"vue-i18n": "9.2.0-beta.30",
|
"vue-i18n": "9.2.0-beta.30",
|
||||||
|
@ -56,41 +56,40 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@4tw/cypress-drag-drop": "2.1.0",
|
"@4tw/cypress-drag-drop": "2.1.0",
|
||||||
"@faker-js/faker": "6.0.0-alpha.5",
|
"@faker-js/faker": "6.0.0-alpha.7",
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
"@fortawesome/fontawesome-svg-core": "1.3.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
"@fortawesome/free-regular-svg-icons": "5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
"@fortawesome/free-solid-svg-icons": "5.15.4",
|
||||||
"@fortawesome/vue-fontawesome": "3.0.0-5",
|
"@fortawesome/vue-fontawesome": "3.0.0-5",
|
||||||
"@types/flexsearch": "0.7.2",
|
"@types/flexsearch": "0.7.2",
|
||||||
"@typescript-eslint/eslint-plugin": "5.10.2",
|
"@typescript-eslint/eslint-plugin": "5.12.0",
|
||||||
"@typescript-eslint/parser": "5.10.2",
|
"@typescript-eslint/parser": "5.12.0",
|
||||||
"@vitejs/plugin-legacy": "1.6.4",
|
"@vitejs/plugin-legacy": "1.7.1",
|
||||||
"@vitejs/plugin-vue": "2.1.0",
|
"@vitejs/plugin-vue": "2.2.2",
|
||||||
"@vue/eslint-config-typescript": "10.0.0",
|
"@vue/eslint-config-typescript": "10.0.0",
|
||||||
"autoprefixer": "10.4.2",
|
"autoprefixer": "10.4.2",
|
||||||
"axios": "0.25.0",
|
"axios": "0.26.0",
|
||||||
"browserslist": "4.19.1",
|
"browserslist": "4.19.3",
|
||||||
"caniuse-lite": "1.0.30001307",
|
"caniuse-lite": "1.0.30001312",
|
||||||
"cypress": "9.4.1",
|
"cypress": "9.5.0",
|
||||||
"esbuild": "0.14.18",
|
"esbuild": "0.14.23",
|
||||||
"eslint": "8.8.0",
|
"eslint": "8.9.0",
|
||||||
"eslint-plugin-vue": "8.4.1",
|
"eslint-plugin-vue": "8.4.1",
|
||||||
"express": "4.17.2",
|
"express": "4.17.3",
|
||||||
"happy-dom": "2.31.1",
|
"happy-dom": "2.39.1",
|
||||||
"netlify-cli": "8.15.0",
|
"netlify-cli": "8.16.1",
|
||||||
"postcss": "8.4.6",
|
"postcss": "8.4.6",
|
||||||
"postcss-preset-env": "7.3.1",
|
"postcss-preset-env": "7.4.1",
|
||||||
"rollup": "2.67.0",
|
"rollup": "2.67.3",
|
||||||
"rollup-plugin-visualizer": "5.5.4",
|
"rollup-plugin-visualizer": "5.5.4",
|
||||||
"sass": "1.49.7",
|
"sass": "1.49.8",
|
||||||
"slugify": "1.6.5",
|
|
||||||
"typescript": "4.5.5",
|
"typescript": "4.5.5",
|
||||||
"vite": "2.7.13",
|
"vite": "2.8.4",
|
||||||
"vite-plugin-pwa": "0.11.13",
|
"vite-plugin-pwa": "0.11.13",
|
||||||
"vite-svg-loader": "3.1.2",
|
"vite-svg-loader": "3.1.2",
|
||||||
"vitest": "0.2.7",
|
"vitest": "0.4.2",
|
||||||
"vue-tsc": "0.31.1",
|
"vue-tsc": "0.31.4",
|
||||||
"wait-on": "6.0.0",
|
"wait-on": "6.0.1",
|
||||||
"workbox-cli": "6.4.2"
|
"workbox-cli": "6.4.2"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
const slugify = require('slugify')
|
|
||||||
const {exec} = require('child_process')
|
const {exec} = require('child_process')
|
||||||
const axios = require('axios')
|
const axios = require('axios')
|
||||||
|
|
||||||
const BOT_USER_ID = 513
|
const BOT_USER_ID = 513
|
||||||
const giteaToken = process.env.GITEA_TOKEN
|
const giteaToken = process.env.GITEA_TOKEN
|
||||||
const siteId = process.env.NETLIFY_SITE_ID
|
const siteId = process.env.NETLIFY_SITE_ID
|
||||||
const branchSlug = slugify(process.env.DRONE_SOURCE_BRANCH)
|
const branchSlug = String(process.env.DRONE_SOURCE_BRANCH)
|
||||||
|
.trim()
|
||||||
|
.normalize('NFKD')
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[.\s/]/g, '-')
|
||||||
|
.replace(/[^A-Za-z\d-]/g, '')
|
||||||
const prNumber = process.env.DRONE_PULL_REQUEST
|
const prNumber = process.env.DRONE_PULL_REQUEST
|
||||||
|
|
||||||
const prIssueCommentsUrl = `https://kolaente.dev/api/v1/repos/vikunja/frontend/issues/${prNumber}/comments`
|
const prIssueCommentsUrl = `https://kolaente.dev/api/v1/repos/vikunja/frontend/issues/${prNumber}/comments`
|
||||||
const alias = `${prNumber}-${branchSlug}`
|
const alias = `${prNumber}-${branchSlug}`.substring(0,37)
|
||||||
const fullPreviewUrl = `https://${alias}--vikunja-frontend-preview.netlify.app`
|
const fullPreviewUrl = `https://${alias}--vikunja-frontend-preview.netlify.app`
|
||||||
|
|
||||||
const promiseExec = cmd => {
|
const promiseExec = cmd => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(cmd, (error, stdout, stderr) => {
|
exec(cmd, (error, stdout) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error)
|
reject(error)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
55ce0faaa2c1919341617ccfaeccbb6029ac12107964ff488985cff13dd952f1a991df3ab0d4b0705deb761e508e6434 ./scripts/deploy-preview-netlify.js
|
bb46342a0a08105b340ba7976cff9d80ef89901120ec0639669caa70bb7d2dbc43e78b1f635a7654ab2456e8358c98a4 ./scripts/deploy-preview-netlify.js
|
||||||
|
|
|
@ -3,7 +3,7 @@ const express = require('express')
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
const p = path.join(__dirname, '..', 'dist-dev')
|
const p = path.join(__dirname, '..', 'dist-dev')
|
||||||
const port = 5000
|
const port = 4173
|
||||||
|
|
||||||
app.use(express.static(p))
|
app.use(express.static(p))
|
||||||
// Handle urls set by the frontend
|
// Handle urls set by the frontend
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<ready>
|
<ready>
|
||||||
<template v-if="authUser">
|
<template v-if="authUser">
|
||||||
<top-navigation/>
|
<TheNavigation/>
|
||||||
<content-auth/>
|
<content-auth/>
|
||||||
</template>
|
</template>
|
||||||
<content-link-share v-else-if="authLinkShare"/>
|
<content-link-share v-else-if="authLinkShare"/>
|
||||||
|
@ -27,7 +27,7 @@ import {success} from '@/message'
|
||||||
|
|
||||||
import Notification from '@/components/misc/notification.vue'
|
import Notification from '@/components/misc/notification.vue'
|
||||||
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue'
|
import KeyboardShortcuts from './components/misc/keyboard-shortcuts/index.vue'
|
||||||
import TopNavigation from './components/home/topNavigation.vue'
|
import TheNavigation from '@/components/home/TheNavigation.vue'
|
||||||
import ContentAuth from './components/home/contentAuth.vue'
|
import ContentAuth from './components/home/contentAuth.vue'
|
||||||
import ContentLinkShare from './components/home/contentLinkShare.vue'
|
import ContentLinkShare from './components/home/contentLinkShare.vue'
|
||||||
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
|
import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
|
||||||
|
|
|
@ -69,10 +69,10 @@ watchEffect(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is a href we assume the user wants an external link via a link element
|
// 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.
|
// we also set a predefined value for the attribute rel, but make it possible to overwrite this by the user.
|
||||||
if ('href' in attrs) {
|
if ('href' in attrs) {
|
||||||
nodeName = 'a'
|
nodeName = 'a'
|
||||||
bindings = {rel: 'noopener'}
|
bindings = {rel: 'noreferrer noopener nofollow'}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentNodeName.value = nodeName
|
componentNodeName.value = nodeName
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
import { useNow } from '@vueuse/core'
|
||||||
|
|
||||||
import LogoFull from '@/assets/logo-full.svg?component'
|
import LogoFull from '@/assets/logo-full.svg?component'
|
||||||
import LogoFullPride from '@/assets/logo-full-pride.svg?component'
|
import LogoFullPride from '@/assets/logo-full-pride.svg?component'
|
||||||
|
|
||||||
const Logo = computed(() => new Date().getMonth() === 5 ? LogoFullPride : LogoFull)
|
const now = useNow()
|
||||||
|
const Logo = computed(() => now.value.getMonth() === 5 ? LogoFullPride : LogoFull)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<BaseButton
|
||||||
type="button"
|
|
||||||
@click="$store.commit('toggleMenu')"
|
|
||||||
class="menu-show-button"
|
class="menu-show-button"
|
||||||
|
@click="$store.commit('toggleMenu')"
|
||||||
@shortkey="() => $store.commit('toggleMenu')"
|
@shortkey="() => $store.commit('toggleMenu')"
|
||||||
v-shortcut="'Control+e'"
|
v-shortcut="'Control+e'"
|
||||||
:title="$t('keyboardShortcuts.toggleMenu')"
|
:title="$t('keyboardShortcuts.toggleMenu')"
|
||||||
|
@ -10,11 +9,14 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import {computed} from 'vue'
|
import {computed} from 'vue'
|
||||||
import {store} from '@/store'
|
import {useStore} from 'vuex'
|
||||||
|
|
||||||
const menuActive = computed(() => store.menuActive)
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const menuActive = computed(() => store.state.menuActive)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -22,11 +24,6 @@ $lineWidth: 2rem;
|
||||||
$size: $lineWidth + 1rem;
|
$size: $lineWidth + 1rem;
|
||||||
|
|
||||||
.menu-show-button {
|
.menu-show-button {
|
||||||
// FIXME: create general button component
|
|
||||||
appearance: none;
|
|
||||||
background-color: transparent;
|
|
||||||
border: 0;
|
|
||||||
|
|
||||||
min-height: $size;
|
min-height: $size;
|
||||||
width: $size;
|
width: $size;
|
||||||
|
|
||||||
|
|
|
@ -32,12 +32,13 @@
|
||||||
</a>
|
</a>
|
||||||
<notifications/>
|
<notifications/>
|
||||||
<div class="user">
|
<div class="user">
|
||||||
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
|
||||||
<dropdown class="is-right" ref="usernameDropdown">
|
<dropdown class="is-right" ref="usernameDropdown">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<x-button
|
<x-button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
:shadow="false">
|
:shadow="false"
|
||||||
|
>
|
||||||
|
<img :src="userAvatar" alt="" class="avatar" width="40" height="40"/>
|
||||||
<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">
|
||||||
<icon icon="chevron-down"/>
|
<icon icon="chevron-down"/>
|
||||||
|
@ -45,92 +46,96 @@
|
||||||
</x-button>
|
</x-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<router-link :to="{name: 'user.settings'}" class="dropdown-item">
|
<BaseButton
|
||||||
|
:to="{name: 'user.settings'}"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('user.settings.title') }}
|
{{ $t('user.settings.title') }}
|
||||||
</router-link>
|
</BaseButton>
|
||||||
<a
|
<BaseButton
|
||||||
|
v-if="imprintUrl"
|
||||||
:href="imprintUrl"
|
:href="imprintUrl"
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
target="_blank"
|
>
|
||||||
rel="noreferrer noopener nofollow"
|
|
||||||
v-if="imprintUrl">
|
|
||||||
{{ $t('navigation.imprint') }}
|
{{ $t('navigation.imprint') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<a
|
<BaseButton
|
||||||
|
v-if="privacyPolicyUrl"
|
||||||
:href="privacyPolicyUrl"
|
:href="privacyPolicyUrl"
|
||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
target="_blank"
|
>
|
||||||
rel="noreferrer noopener nofollow"
|
|
||||||
v-if="privacyPolicyUrl">
|
|
||||||
{{ $t('navigation.privacy') }}
|
{{ $t('navigation.privacy') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<a @click="$store.commit('keyboardShortcutsActive', true)" class="dropdown-item">
|
<BaseButton
|
||||||
|
@click="$store.commit('keyboardShortcutsActive', true)"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('keyboardShortcuts.title') }}
|
{{ $t('keyboardShortcuts.title') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<router-link :to="{name: 'about'}" class="dropdown-item">
|
<BaseButton
|
||||||
|
:to="{name: 'about'}"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('about.title') }}
|
{{ $t('about.title') }}
|
||||||
</router-link>
|
</BaseButton>
|
||||||
<a @click="logout()" class="dropdown-item">
|
<BaseButton
|
||||||
|
@click="logout()"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
{{ $t('user.auth.logout') }}
|
{{ $t('user.auth.logout') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup langs="ts">
|
||||||
import {mapState} from 'vuex'
|
import {ref, computed, onMounted, nextTick} from 'vue'
|
||||||
import {CURRENT_LIST, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
import {useStore} from 'vuex'
|
||||||
|
import {useRouter} from 'vue-router'
|
||||||
|
|
||||||
|
import {QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
||||||
import Rights from '@/models/constants/rights.json'
|
import Rights from '@/models/constants/rights.json'
|
||||||
|
|
||||||
import Update from '@/components/home/update.vue'
|
import Update from '@/components/home/update.vue'
|
||||||
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
import ListSettingsDropdown from '@/components/list/list-settings-dropdown.vue'
|
||||||
import Dropdown from '@/components/misc/dropdown.vue'
|
import Dropdown from '@/components/misc/dropdown.vue'
|
||||||
import Notifications from '@/components/notifications/notifications.vue'
|
import Notifications from '@/components/notifications/notifications.vue'
|
||||||
import Logo from '@/components/home/Logo.vue'
|
import Logo from '@/components/home/Logo.vue'
|
||||||
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import MenuButton from '@/components/home/MenuButton.vue'
|
import MenuButton from '@/components/home/MenuButton.vue'
|
||||||
|
|
||||||
export default {
|
const store = useStore()
|
||||||
name: 'topNavigation',
|
|
||||||
components: {
|
|
||||||
Notifications,
|
|
||||||
Dropdown,
|
|
||||||
ListSettingsDropdown,
|
|
||||||
Update,
|
|
||||||
Logo,
|
|
||||||
MenuButton,
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState({
|
|
||||||
userInfo: state => state.auth.info,
|
|
||||||
userAvatar: state => state.auth.avatarUrl,
|
|
||||||
userAuthenticated: state => state.auth.authenticated,
|
|
||||||
currentList: CURRENT_LIST,
|
|
||||||
background: 'background',
|
|
||||||
imprintUrl: state => state.config.legal.imprintUrl,
|
|
||||||
privacyPolicyUrl: state => state.config.legal.privacyPolicyUrl,
|
|
||||||
canWriteCurrentList: state => state.currentList.maxRight > Rights.READ,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (typeof this.$refs.usernameDropdown === 'undefined' || typeof this.$refs.listTitle === 'undefined') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const usernameWidth = this.$refs.usernameDropdown.$el.clientWidth
|
const userInfo = computed(() => store.state.auth.info)
|
||||||
this.$refs.listTitle.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
const userAvatar = computed(() => store.state.auth.avatarUrl)
|
||||||
})
|
const currentList = computed(() => store.state.currentList)
|
||||||
},
|
const background = computed(() => store.state.background)
|
||||||
methods: {
|
const imprintUrl = computed(() => store.state.config.legal.imprintUrl)
|
||||||
logout() {
|
const privacyPolicyUrl = computed(() => store.state.config.legal.privacyPolicyUrl)
|
||||||
this.$store.dispatch('auth/logout')
|
const canWriteCurrentList = computed(() => store.state.currentList.maxRight > Rights.READ)
|
||||||
this.$router.push({name: 'user.login'})
|
|
||||||
},
|
const usernameDropdown = ref()
|
||||||
openQuickActions() {
|
const listTitle = ref()
|
||||||
this.$store.commit(QUICK_ACTIONS_ACTIVE, true)
|
onMounted(async () => {
|
||||||
},
|
await nextTick()
|
||||||
},
|
if (typeof usernameDropdown.value === 'undefined' || typeof listTitle.value === 'undefined') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const usernameWidth = usernameDropdown.value.$el.clientWidth
|
||||||
|
listTitle.value.style.setProperty('--nav-username-width', `${usernameWidth}px`)
|
||||||
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
function logout() {
|
||||||
|
store.dispatch('auth/logout')
|
||||||
|
router.push({name: 'user.login'})
|
||||||
|
}
|
||||||
|
|
||||||
|
function openQuickActions() {
|
||||||
|
store.commit(QUICK_ACTIONS_ACTIVE, true)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -246,6 +251,7 @@ $hamburger-menu-icon-width: 28px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
margin-right: var(--button-padding-horizontal);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.dropdown-trigger .button) {
|
:deep(.dropdown-trigger .button) {
|
|
@ -66,7 +66,7 @@ const showIconOnly = computed(() => props.icon !== '' && typeof slots.default ==
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: $button-height;
|
min-height: $button-height;
|
||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-sm);
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
||||||
|
|
|
@ -39,79 +39,66 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import Message from '@/components/misc/message'
|
import {ref, computed, watch} from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import {parseURL} from 'ufo'
|
import {parseURL} from 'ufo'
|
||||||
|
|
||||||
import {checkAndSetApiUrl} from '@/helpers/checkAndSetApiUrl'
|
import {checkAndSetApiUrl} from '@/helpers/checkAndSetApiUrl'
|
||||||
|
import {success} from '@/message'
|
||||||
|
|
||||||
export default {
|
import Message from '@/components/misc/message.vue'
|
||||||
name: 'apiConfig',
|
|
||||||
components: {
|
const props = defineProps({
|
||||||
Message,
|
configureOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
},
|
},
|
||||||
data() {
|
})
|
||||||
return {
|
const emit = defineEmits(['foundApi'])
|
||||||
configureApi: false,
|
|
||||||
apiUrl: window.API_URL,
|
const apiUrl = ref(window.API_URL)
|
||||||
errorMsg: '',
|
const configureApi = ref(apiUrl.value === '')
|
||||||
successMsg: '',
|
|
||||||
|
const apiDomain = computed(() => parseURL(apiUrl.value).host || parseURL(window.location.href).host)
|
||||||
|
|
||||||
|
|
||||||
|
watch(() => props.configureOpen, (value) => {
|
||||||
|
configureApi.value = value
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
|
||||||
|
const {t} = useI18n()
|
||||||
|
|
||||||
|
const errorMsg = ref('')
|
||||||
|
const successMsg = ref('')
|
||||||
|
async function setApiUrl() {
|
||||||
|
if (apiUrl.value === '') {
|
||||||
|
// Don't try to check and set an empty url
|
||||||
|
errorMsg.value = t('apiConfig.urlRequired')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = await checkAndSetApiUrl(apiUrl.value)
|
||||||
|
|
||||||
|
if (url === '') {
|
||||||
|
// If the config setter function could not figure out a url
|
||||||
|
throw new Error('URL cannot be empty.')
|
||||||
}
|
}
|
||||||
},
|
|
||||||
emits: ['foundApi'],
|
|
||||||
created() {
|
|
||||||
if (this.apiUrl === '') {
|
|
||||||
this.configureApi = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
apiDomain() {
|
|
||||||
return parseURL(this.apiUrl).host || parseURL(window.location.href).host
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
configureOpen: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
configureOpen: {
|
|
||||||
handler(value) {
|
|
||||||
this.configureApi = value
|
|
||||||
},
|
|
||||||
immediate: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async setApiUrl() {
|
|
||||||
if (this.apiUrl === '') {
|
|
||||||
// Don't try to check and set an empty url
|
|
||||||
this.errorMsg = this.$t('apiConfig.urlRequired')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
// Set it + save it to local storage to save us the hoops
|
||||||
const url = await checkAndSetApiUrl(this.apiUrl)
|
errorMsg.value = ''
|
||||||
|
apiUrl.value = url
|
||||||
if (url === '') {
|
success({message: t('apiConfig.success', {domain: apiDomain.value})})
|
||||||
// If the config setter function could not figure out a url
|
configureApi.value = false
|
||||||
throw new Error('URL cannot be empty.')
|
emit('foundApi', apiUrl.value)
|
||||||
}
|
} catch (e) {
|
||||||
|
// Still not found, url is still invalid
|
||||||
// Set it + save it to local storage to save us the hoops
|
successMsg.value = ''
|
||||||
this.errorMsg = ''
|
errorMsg.value = t('apiConfig.error', {domain: apiDomain.value})
|
||||||
this.$message.success({message: this.$t('apiConfig.success', {domain: this.apiDomain})})
|
}
|
||||||
this.configureApi = false
|
|
||||||
this.apiUrl = url
|
|
||||||
this.$emit('foundApi', this.apiUrl)
|
|
||||||
} catch (e) {
|
|
||||||
// Still not found, url is still invalid
|
|
||||||
this.successMsg = ''
|
|
||||||
this.errorMsg = this.$t('apiConfig.error', {domain: this.apiDomain})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
@click="emit('close')"
|
@click="$emit('close')"
|
||||||
class="close"
|
class="close"
|
||||||
>
|
>
|
||||||
<icon icon="times"/>
|
<icon icon="times"/>
|
||||||
|
|
47
src/components/tasks/partials/createdUpdated.vue
Normal file
47
src/components/tasks/partials/createdUpdated.vue
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<p class="created">
|
||||||
|
<time :datetime="formatISO(task.created)" v-tooltip="formatDate(task.created)">
|
||||||
|
<i18n-t keypath="task.detail.created">
|
||||||
|
<span>{{ formatDateSince(task.created) }}</span>
|
||||||
|
{{ task.createdBy.getDisplayName() }}
|
||||||
|
</i18n-t>
|
||||||
|
</time>
|
||||||
|
<template v-if="+new Date(task.created) !== +new Date(task.updated)">
|
||||||
|
<br/>
|
||||||
|
<!-- Computed properties to show the actual date every time it gets updated -->
|
||||||
|
<time :datetime="formatISO(task.updated)" v-tooltip="updatedFormatted">
|
||||||
|
<i18n-t keypath="task.detail.updated">
|
||||||
|
<span>{{ updatedSince }}</span>
|
||||||
|
</i18n-t>
|
||||||
|
</time>
|
||||||
|
</template>
|
||||||
|
<template v-if="task.done">
|
||||||
|
<br/>
|
||||||
|
<time :datetime="formatISO(task.doneAt)" v-tooltip="doneFormatted">
|
||||||
|
<i18n-t keypath="task.detail.doneAt">
|
||||||
|
<span>{{ doneSince }}</span>
|
||||||
|
</i18n-t>
|
||||||
|
</time>
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import {computed, toRefs} from 'vue'
|
||||||
|
import TaskModel from '@/models/task'
|
||||||
|
import {formatDateLong, formatDateSince} from '@/helpers/time/formatDate'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
task: {
|
||||||
|
type: TaskModel,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const {task} = toRefs(props)
|
||||||
|
|
||||||
|
const updatedSince = computed(() => formatDateSince(task.value.updated))
|
||||||
|
const updatedFormatted = computed(() => formatDateLong(task.value.updated))
|
||||||
|
const doneSince = computed(() => formatDateSince(task.value.doneAt))
|
||||||
|
const doneFormatted = computed(() => formatDateLong(task.value.doneAt))
|
||||||
|
</script>
|
|
@ -138,7 +138,6 @@ $task-background: var(--white);
|
||||||
border: 3px solid transparent;
|
border: 3px solid transparent;
|
||||||
|
|
||||||
font-size: .9rem;
|
font-size: .9rem;
|
||||||
margin: .5rem;
|
|
||||||
padding: .4rem;
|
padding: .4rem;
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
background: $task-background;
|
background: $task-background;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="task-relations">
|
<div class="task-relations">
|
||||||
<x-button
|
<x-button
|
||||||
v-if="Object.keys(relatedTasks).length > 0"
|
v-if="editEnabled && Object.keys(relatedTasks).length > 0"
|
||||||
@click="showNewRelationForm = !showNewRelationForm"
|
@click="showNewRelationForm = !showNewRelationForm"
|
||||||
class="is-pulled-right add-task-relation-button"
|
class="is-pulled-right add-task-relation-button"
|
||||||
:class="{'is-active': showNewRelationForm}"
|
:class="{'is-active': showNewRelationForm}"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {HTTPFactory} from '@/http-common'
|
import {AuthenticatedHTTPFactory} from '@/http-common'
|
||||||
import {AxiosResponse} from 'axios'
|
import {AxiosResponse} from 'axios'
|
||||||
|
|
||||||
let savedToken: string | null = null
|
let savedToken: string | null = null
|
||||||
|
@ -6,8 +6,6 @@ let savedToken: string | null = null
|
||||||
/**
|
/**
|
||||||
* Saves a token while optionally saving it to lacal storage. This is used when viewing a link share:
|
* Saves a token while optionally saving it to lacal storage. This is used when viewing a link share:
|
||||||
* It enables viewing multiple link shares indipendently from each in multiple tabs other without overriding any other open ones.
|
* It enables viewing multiple link shares indipendently from each in multiple tabs other without overriding any other open ones.
|
||||||
* @param token
|
|
||||||
* @param persist
|
|
||||||
*/
|
*/
|
||||||
export const saveToken = (token: string, persist: boolean) => {
|
export const saveToken = (token: string, persist: boolean) => {
|
||||||
savedToken = token
|
savedToken = token
|
||||||
|
@ -18,7 +16,6 @@ export const saveToken = (token: string, persist: boolean) => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a saved token. If there is one saved in memory it will use that before anything else.
|
* Returns a saved token. If there is one saved in memory it will use that before anything else.
|
||||||
* @returns {string|null}
|
|
||||||
*/
|
*/
|
||||||
export const getToken = (): string | null => {
|
export const getToken = (): string | null => {
|
||||||
if (savedToken !== null) {
|
if (savedToken !== null) {
|
||||||
|
@ -39,16 +36,11 @@ export const removeToken = () => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes an auth token while ensuring it is updated everywhere.
|
* Refreshes an auth token while ensuring it is updated everywhere.
|
||||||
* @returns {Promise<AxiosResponse<any>>}
|
|
||||||
*/
|
*/
|
||||||
export async function refreshToken(persist: boolean): Promise<AxiosResponse> {
|
export async function refreshToken(persist: boolean): Promise<AxiosResponse> {
|
||||||
const HTTP = HTTPFactory()
|
const HTTP = AuthenticatedHTTPFactory()
|
||||||
try {
|
try {
|
||||||
const response = await HTTP.post('user/token', null, {
|
const response = await HTTP.post('user/token')
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${getToken()}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
saveToken(response.data.token, persist)
|
saveToken(response.data.token, persist)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import {getToken} from '@/helpers/auth'
|
||||||
|
|
||||||
export const HTTPFactory = () => {
|
export function HTTPFactory() {
|
||||||
return axios.create({
|
return axios.create({
|
||||||
baseURL: window.API_URL,
|
baseURL: window.API_URL,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function AuthenticatedHTTPFactory(token = getToken()) {
|
||||||
|
return axios.create({
|
||||||
|
baseURL: window.API_URL,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { createI18n } from 'vue-i18n'
|
import {createI18n} from 'vue-i18n'
|
||||||
import langEN from './lang/en.json'
|
import langEN from './lang/en.json'
|
||||||
|
|
||||||
export const i18n = createI18n({
|
export const i18n = createI18n({
|
||||||
|
@ -19,6 +19,9 @@ export const availableLanguages = {
|
||||||
'vi-VN': 'Tiếng Việt',
|
'vi-VN': 'Tiếng Việt',
|
||||||
'it-IT': 'Italiano',
|
'it-IT': 'Italiano',
|
||||||
'cs-CZ': 'Čeština',
|
'cs-CZ': 'Čeština',
|
||||||
|
'pl-PL': 'Polski',
|
||||||
|
'nl-NL': 'Nederlands',
|
||||||
|
'pt-PT': 'Português',
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadedLanguages = ['en'] // our default language that is preloaded
|
const loadedLanguages = ['en'] // our default language that is preloaded
|
||||||
|
@ -30,10 +33,10 @@ const setI18nLanguage = lang => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadLanguageAsync = lang => {
|
export const loadLanguageAsync = lang => {
|
||||||
if(!lang) {
|
if (!lang) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// If the same language
|
// If the same language
|
||||||
i18n.global.locale === lang ||
|
i18n.global.locale === lang ||
|
||||||
|
|
|
@ -31,10 +31,9 @@
|
||||||
"username": "Uživatelské jméno",
|
"username": "Uživatelské jméno",
|
||||||
"usernameEmail": "Uživatelské jméno nebo e-mail",
|
"usernameEmail": "Uživatelské jméno nebo e-mail",
|
||||||
"usernamePlaceholder": "např. Jarmil",
|
"usernamePlaceholder": "např. Jarmil",
|
||||||
"email": "E-mailová adresa",
|
"email": "Email address",
|
||||||
"emailPlaceholder": "např. jarmil{'@'}vikunja.io",
|
"emailPlaceholder": "např. jarmil{'@'}vikunja.io",
|
||||||
"password": "Heslo",
|
"password": "Heslo",
|
||||||
"passwordRepeat": "Zopakovat heslo",
|
|
||||||
"passwordPlaceholder": "např. • • • • • • • •",
|
"passwordPlaceholder": "např. • • • • • • • •",
|
||||||
"forgotPassword": "Zapomenuté heslo?",
|
"forgotPassword": "Zapomenuté heslo?",
|
||||||
"resetPassword": "Obnovit heslo",
|
"resetPassword": "Obnovit heslo",
|
||||||
|
@ -45,12 +44,20 @@
|
||||||
"totpTitle": "Kód dvoufaktorového ověření",
|
"totpTitle": "Kód dvoufaktorového ověření",
|
||||||
"totpPlaceholder": "např. 123456",
|
"totpPlaceholder": "např. 123456",
|
||||||
"login": "Přihlásit se",
|
"login": "Přihlásit se",
|
||||||
"register": "Registrovat",
|
"createAccount": "Create account",
|
||||||
"loginWith": "Přihlásit se pomocí {provider}",
|
"loginWith": "Přihlásit se pomocí {provider}",
|
||||||
"authenticating": "Ověřování…",
|
"authenticating": "Ověřování…",
|
||||||
"openIdStateError": "Stav neodpovídá, odmítám pokračovat!",
|
"openIdStateError": "Stav neodpovídá, odmítám pokračovat!",
|
||||||
"openIdGeneralError": "Došlo k chybě při ověřování proti třetí straně.",
|
"openIdGeneralError": "Došlo k chybě při ověřování proti třetí straně.",
|
||||||
"logout": "Odhlásit se"
|
"logout": "Odhlásit se",
|
||||||
|
"emailInvalid": "Please enter a valid email address.",
|
||||||
|
"usernameRequired": "Please provide a username.",
|
||||||
|
"passwordRequired": "Please provide a password.",
|
||||||
|
"showPassword": "Show the password",
|
||||||
|
"hidePassword": "Hide the password",
|
||||||
|
"noAccountYet": "Don't have an account yet?",
|
||||||
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Nastavení",
|
"title": "Nastavení",
|
||||||
|
@ -61,7 +68,7 @@
|
||||||
"currentPasswordPlaceholder": "Vaše současné heslo",
|
"currentPasswordPlaceholder": "Vaše současné heslo",
|
||||||
"passwordsDontMatch": "Nové heslo se neshoduje s potvrzením hesla.",
|
"passwordsDontMatch": "Nové heslo se neshoduje s potvrzením hesla.",
|
||||||
"passwordUpdateSuccess": "Heslo bylo úspěšně změněno.",
|
"passwordUpdateSuccess": "Heslo bylo úspěšně změněno.",
|
||||||
"updateEmailTitle": "Aktualizovat Vaši e-mailovou adresu",
|
"updateEmailTitle": "Update Your Email Address",
|
||||||
"updateEmailNew": "Nová e-mailová adresa",
|
"updateEmailNew": "Nová e-mailová adresa",
|
||||||
"updateEmailSuccess": "Vaše e-mailová adresa byla úspěšně aktualizována. Poslali jsme vám odkaz pro její potvrzení.",
|
"updateEmailSuccess": "Vaše e-mailová adresa byla úspěšně aktualizována. Poslali jsme vám odkaz pro její potvrzení.",
|
||||||
"general": {
|
"general": {
|
||||||
|
@ -78,7 +85,8 @@
|
||||||
"weekStartSunday": "Neděle",
|
"weekStartSunday": "Neděle",
|
||||||
"weekStartMonday": "Pondělí",
|
"weekStartMonday": "Pondělí",
|
||||||
"language": "Jazyk",
|
"language": "Jazyk",
|
||||||
"defaultList": "Výchozí seznam"
|
"defaultList": "Výchozí seznam",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Dvoufaktorové ověření",
|
"title": "Dvoufaktorové ověření",
|
||||||
|
@ -327,6 +335,7 @@
|
||||||
"archiveText": "Nebudete moci upravovat tento jmenný prostor ani vytvářet nové seznamy, dokud jej neodarchivujete. Všechny seznamy v tomto prostoru budou také archivovány.",
|
"archiveText": "Nebudete moci upravovat tento jmenný prostor ani vytvářet nové seznamy, dokud jej neodarchivujete. Všechny seznamy v tomto prostoru budou také archivovány.",
|
||||||
"unarchiveText": "Budete moci vytvářet nové úkoly nebo je upravovat.",
|
"unarchiveText": "Budete moci vytvářet nové úkoly nebo je upravovat.",
|
||||||
"success": "Prostor byl úspěšně archivován.",
|
"success": "Prostor byl úspěšně archivován.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "Pokud je prostor archivován, nelze vytvořit nové seznamy nebo je upravit."
|
"description": "Pokud je prostor archivován, nelze vytvořit nové seznamy nebo je upravit."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
"showDoneTasks": "Zobrazit dokončené úkoly",
|
"showDoneTasks": "Zobrazit dokončené úkoly",
|
||||||
"sortAlphabetically": "Řadit podle abecedy",
|
"sortAlphabetically": "Řadit podle abecedy",
|
||||||
"enablePriority": "Povolit filtrování podle priority",
|
"enablePriority": "Povolit filtrování podle priority",
|
||||||
"enablePercentDone": "Povolit filtrování dle dokončenosti",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Rozsah termínu",
|
"dueDateRange": "Rozsah termínu",
|
||||||
"startDateRange": "Začátek období",
|
"startDateRange": "Začátek období",
|
||||||
"endDateRange": "Konec období",
|
"endDateRange": "Konec období",
|
||||||
|
@ -569,7 +578,7 @@
|
||||||
"endDate": "Nastavit koncové datum",
|
"endDate": "Nastavit koncové datum",
|
||||||
"reminders": "Nastavit připomenutí",
|
"reminders": "Nastavit připomenutí",
|
||||||
"repeatAfter": "Nastavit interval opakování",
|
"repeatAfter": "Nastavit interval opakování",
|
||||||
"percentDone": "Nastavit procenta dokončeno",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Přidat přílohy",
|
"attachments": "Přidat přílohy",
|
||||||
"relatedTasks": "Přidat vztahy úkolu",
|
"relatedTasks": "Přidat vztahy úkolu",
|
||||||
"moveList": "Přesunout úkol",
|
"moveList": "Přesunout úkol",
|
||||||
|
@ -589,7 +598,7 @@
|
||||||
"dueDate": "Termín",
|
"dueDate": "Termín",
|
||||||
"endDate": "Datum ukončení",
|
"endDate": "Datum ukončení",
|
||||||
"labels": "Štítky",
|
"labels": "Štítky",
|
||||||
"percentDone": "% Hotovo",
|
"percentDone": "Progress",
|
||||||
"priority": "Priorita",
|
"priority": "Priorita",
|
||||||
"relatedTasks": "Související úkoly",
|
"relatedTasks": "Související úkoly",
|
||||||
"reminders": "Připomínky",
|
"reminders": "Připomínky",
|
||||||
|
|
|
@ -31,10 +31,9 @@
|
||||||
"username": "Anmeldename",
|
"username": "Anmeldename",
|
||||||
"usernameEmail": "Anmeldename oder E-Mail-Adresse",
|
"usernameEmail": "Anmeldename oder E-Mail-Adresse",
|
||||||
"usernamePlaceholder": "z.B. frederick",
|
"usernamePlaceholder": "z.B. frederick",
|
||||||
"email": "Email address",
|
"email": "E-Mail-Adresse",
|
||||||
"emailPlaceholder": "z.B. frederic{'@'}vikunja.io",
|
"emailPlaceholder": "z.B. frederic{'@'}vikunja.io",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"passwordRepeat": "Gib dein Passwort erneut ein",
|
|
||||||
"passwordPlaceholder": "z.B. •••••••••••",
|
"passwordPlaceholder": "z.B. •••••••••••",
|
||||||
"forgotPassword": "Passwort vergessen?",
|
"forgotPassword": "Passwort vergessen?",
|
||||||
"resetPassword": "Setze dein Passwort zurück",
|
"resetPassword": "Setze dein Passwort zurück",
|
||||||
|
@ -45,12 +44,20 @@
|
||||||
"totpTitle": "Zwei-Faktor-Authentifizierungscode",
|
"totpTitle": "Zwei-Faktor-Authentifizierungscode",
|
||||||
"totpPlaceholder": "z.B. 123456",
|
"totpPlaceholder": "z.B. 123456",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"register": "Registrieren",
|
"createAccount": "Account erstellen",
|
||||||
"loginWith": "Mit {provider} anmelden",
|
"loginWith": "Mit {provider} anmelden",
|
||||||
"authenticating": "Authentifizierung…",
|
"authenticating": "Authentifizierung…",
|
||||||
"openIdStateError": "Zustand stimmt nicht überein, fahre nicht fort!",
|
"openIdStateError": "Zustand stimmt nicht überein, fahre nicht fort!",
|
||||||
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
|
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
|
||||||
"logout": "Abmelden"
|
"logout": "Abmelden",
|
||||||
|
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
|
||||||
|
"usernameRequired": "Bitte gib einen Anmeldenamen ein.",
|
||||||
|
"passwordRequired": "Bitte gib ein Passwort ein.",
|
||||||
|
"showPassword": "Passwort anzeigen",
|
||||||
|
"hidePassword": "Passwort verbergen",
|
||||||
|
"noAccountYet": "Noch kein Account?",
|
||||||
|
"alreadyHaveAnAccount": "Hast du bereits einen Account?",
|
||||||
|
"remember": "Angemeldet bleiben"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Einstellungen",
|
"title": "Einstellungen",
|
||||||
|
@ -78,7 +85,8 @@
|
||||||
"weekStartSunday": "Sonntag",
|
"weekStartSunday": "Sonntag",
|
||||||
"weekStartMonday": "Montag",
|
"weekStartMonday": "Montag",
|
||||||
"language": "Sprache",
|
"language": "Sprache",
|
||||||
"defaultList": "Standard-Liste"
|
"defaultList": "Standard-Liste",
|
||||||
|
"timezone": "Zeitzone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Zwei-Faktor-Authentifizierung",
|
"title": "Zwei-Faktor-Authentifizierung",
|
||||||
|
@ -327,6 +335,7 @@
|
||||||
"archiveText": "Du kannst diesen Namespace nicht mehr bearbeiten oder neue Listen erstellen, bis du die Archivierung rückgängig machst. Das gilt auch für alle Listen in diesem Namespace.",
|
"archiveText": "Du kannst diesen Namespace nicht mehr bearbeiten oder neue Listen erstellen, bis du die Archivierung rückgängig machst. Das gilt auch für alle Listen in diesem Namespace.",
|
||||||
"unarchiveText": "Du kannst neue Aufgaben erstellen oder diese bearbeiten.",
|
"unarchiveText": "Du kannst neue Aufgaben erstellen oder diese bearbeiten.",
|
||||||
"success": "Der Namespace wurde erfolgreich archiviert.",
|
"success": "Der Namespace wurde erfolgreich archiviert.",
|
||||||
|
"unarchiveSuccess": "Der Namespace wurde erfolgreich wiederhergestellt.",
|
||||||
"description": "In einem archivierten Namespace können Listen weder angelegt noch editiert werden."
|
"description": "In einem archivierten Namespace können Listen weder angelegt noch editiert werden."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
"showDoneTasks": "Erledigte Aufgaben anzeigen",
|
"showDoneTasks": "Erledigte Aufgaben anzeigen",
|
||||||
"sortAlphabetically": "Alphabetisch sortieren",
|
"sortAlphabetically": "Alphabetisch sortieren",
|
||||||
"enablePriority": "Filter nach Priorität aktivieren",
|
"enablePriority": "Filter nach Priorität aktivieren",
|
||||||
"enablePercentDone": "Filter nach % Erledigt aktivieren",
|
"enablePercentDone": "Filter nach Fortschritt aktivieren",
|
||||||
"dueDateRange": "Fälligkeitsbereich",
|
"dueDateRange": "Fälligkeitsbereich",
|
||||||
"startDateRange": "Startdatumsbereich",
|
"startDateRange": "Startdatumsbereich",
|
||||||
"endDateRange": "Enddatumsbereich",
|
"endDateRange": "Enddatumsbereich",
|
||||||
|
@ -569,7 +578,7 @@
|
||||||
"endDate": "Enddatum setzen",
|
"endDate": "Enddatum setzen",
|
||||||
"reminders": "Erinnerungen setzen",
|
"reminders": "Erinnerungen setzen",
|
||||||
"repeatAfter": "Wiederholung setzen",
|
"repeatAfter": "Wiederholung setzen",
|
||||||
"percentDone": "Prozent erledigt setzen",
|
"percentDone": "Fortschritt einstellen",
|
||||||
"attachments": "Anhänge hinzufügen",
|
"attachments": "Anhänge hinzufügen",
|
||||||
"relatedTasks": "Aufgabenbeziehungen hinzufügen",
|
"relatedTasks": "Aufgabenbeziehungen hinzufügen",
|
||||||
"moveList": "Aufgabe verschieben",
|
"moveList": "Aufgabe verschieben",
|
||||||
|
@ -589,7 +598,7 @@
|
||||||
"dueDate": "Fälligkeitsdatum",
|
"dueDate": "Fälligkeitsdatum",
|
||||||
"endDate": "Enddatum",
|
"endDate": "Enddatum",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% erledigt",
|
"percentDone": "Fortschritt",
|
||||||
"priority": "Priorität",
|
"priority": "Priorität",
|
||||||
"relatedTasks": "Verwandte Aufgaben",
|
"relatedTasks": "Verwandte Aufgaben",
|
||||||
"reminders": "Erinnerungen",
|
"reminders": "Erinnerungen",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"username": "Benutzernamä",
|
"username": "Benutzernamä",
|
||||||
"usernameEmail": "Benutzernamä oder E-Mail Adrässe",
|
"usernameEmail": "Benutzernamä oder E-Mail Adrässe",
|
||||||
"usernamePlaceholder": "z.B. Hansruedi",
|
"usernamePlaceholder": "z.B. Hansruedi",
|
||||||
"email": "Email address",
|
"email": "E-Mail-Adresse",
|
||||||
"emailPlaceholder": "z.B. frederic{'@'}vikunja.io",
|
"emailPlaceholder": "z.B. frederic{'@'}vikunja.io",
|
||||||
"password": "Passwort",
|
"password": "Passwort",
|
||||||
"passwordPlaceholder": "z.B. •••••••••••",
|
"passwordPlaceholder": "z.B. •••••••••••",
|
||||||
|
@ -44,19 +44,20 @@
|
||||||
"totpTitle": "Zweifaktor Authentifizierigs Ziffere",
|
"totpTitle": "Zweifaktor Authentifizierigs Ziffere",
|
||||||
"totpPlaceholder": "z.B. 123456",
|
"totpPlaceholder": "z.B. 123456",
|
||||||
"login": "Iihlogge",
|
"login": "Iihlogge",
|
||||||
"createAccount": "Create account",
|
"createAccount": "Account erstellen",
|
||||||
"loginWith": "Iihlogge mit {provider}",
|
"loginWith": "Iihlogge mit {provider}",
|
||||||
"authenticating": "Authentifiziere…",
|
"authenticating": "Authentifiziere…",
|
||||||
"openIdStateError": "Status stimmt nid überiih, ich verweigerä wiiter zmache!",
|
"openIdStateError": "Status stimmt nid überiih, ich verweigerä wiiter zmache!",
|
||||||
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
|
"openIdGeneralError": "Es ist ein Fehler bei der externen Authentisierung aufgetreten.",
|
||||||
"logout": "Uuslogge",
|
"logout": "Uuslogge",
|
||||||
"emailInvalid": "Please enter a valid email address.",
|
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein.",
|
||||||
"usernameRequired": "Please provide a username.",
|
"usernameRequired": "Bitte gib einen Anmeldenamen ein.",
|
||||||
"passwordRequired": "Please provide a password.",
|
"passwordRequired": "Bitte gib ein Passwort ein.",
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Passwort anzeigen",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Passwort verbergen",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Noch kein Account?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Hast du bereits einen Account?",
|
||||||
|
"remember": "Angemeldet bleiben"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Iihstellige",
|
"title": "Iihstellige",
|
||||||
|
@ -67,7 +68,7 @@
|
||||||
"currentPasswordPlaceholder": "Diis jetzige Passwort",
|
"currentPasswordPlaceholder": "Diis jetzige Passwort",
|
||||||
"passwordsDontMatch": "Dis neue Passwort und siini Bestätigung stimmed nid überiih.",
|
"passwordsDontMatch": "Dis neue Passwort und siini Bestätigung stimmed nid überiih.",
|
||||||
"passwordUpdateSuccess": "Dis Passwort isch erfolgriich aktualisiert wordä.",
|
"passwordUpdateSuccess": "Dis Passwort isch erfolgriich aktualisiert wordä.",
|
||||||
"updateEmailTitle": "Update Your Email Address",
|
"updateEmailTitle": "Aktualisiere deine E-Mail-Adresse",
|
||||||
"updateEmailNew": "Neui E-Mail Adrässä",
|
"updateEmailNew": "Neui E-Mail Adrässä",
|
||||||
"updateEmailSuccess": "Dini E-Mail Adrässä isch erfolgriich gänderet worde. Mir hend dir en Link gschickt, um si zu bestätigä.",
|
"updateEmailSuccess": "Dini E-Mail Adrässä isch erfolgriich gänderet worde. Mir hend dir en Link gschickt, um si zu bestätigä.",
|
||||||
"general": {
|
"general": {
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunntig",
|
"weekStartSunday": "Sunntig",
|
||||||
"weekStartMonday": "Määntig",
|
"weekStartMonday": "Määntig",
|
||||||
"language": "Sproch",
|
"language": "Sproch",
|
||||||
"defaultList": "Standard Liste"
|
"defaultList": "Standard Liste",
|
||||||
|
"timezone": "Zeitzone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Zweifaktor Authentifizierig",
|
"title": "Zweifaktor Authentifizierig",
|
||||||
|
@ -101,9 +103,9 @@
|
||||||
"disableSuccess": "Zweifaktor Authentifizierig isch erfolgriich uusgschalte wore."
|
"disableSuccess": "Zweifaktor Authentifizierig isch erfolgriich uusgschalte wore."
|
||||||
},
|
},
|
||||||
"caldav": {
|
"caldav": {
|
||||||
"title": "Caldav",
|
"title": "CalDAV",
|
||||||
"howTo": "Du chasch Vikunja zu Caldav Applikatione verbinde, um dini Uufgabe vo verschidene Gräät zgseh. Gib die Url i dim Client iih:",
|
"howTo": "Du chasch Vikunja zu CalDAV Applikatione verbinde, um dini Uufgabe vo verschidene Gräät zgseh. Gib die Url i dim Client iih:",
|
||||||
"more": "Meh Informatione über Caldav in Vikunja"
|
"more": "Meh Informatione über CalDAV in Vikunja"
|
||||||
},
|
},
|
||||||
"avatar": {
|
"avatar": {
|
||||||
"title": "Herr Der Elemente",
|
"title": "Herr Der Elemente",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "Du hesch kei möglichkeit meh de Namensruum z'bearbeite oder neui Listene drin z'erstelle, bis du si wider ent-archiviert hesch. Das archiviert au grad alli Liste im Namensruum.",
|
"archiveText": "Du hesch kei möglichkeit meh de Namensruum z'bearbeite oder neui Listene drin z'erstelle, bis du si wider ent-archiviert hesch. Das archiviert au grad alli Liste im Namensruum.",
|
||||||
"unarchiveText": "Du chasch neui Liste erstelle oder bearbeite.",
|
"unarchiveText": "Du chasch neui Liste erstelle oder bearbeite.",
|
||||||
"success": "De Namensruum isch erfolgriich archiviert worde.",
|
"success": "De Namensruum isch erfolgriich archiviert worde.",
|
||||||
|
"unarchiveSuccess": "Der Namespace wurde erfolgreich wiederhergestellt.",
|
||||||
"description": "Wenn en Namensruum archiviert isch, chasch du kei neui Liste erstelle oder die bearbeite."
|
"description": "Wenn en Namensruum archiviert isch, chasch du kei neui Liste erstelle oder die bearbeite."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Zeig die fertige Uufgabe",
|
"showDoneTasks": "Zeig die fertige Uufgabe",
|
||||||
"sortAlphabetically": "Alphabetisch sortieren",
|
"sortAlphabetically": "Alphabetisch sortieren",
|
||||||
"enablePriority": "Filter nach Priorität aktiviere",
|
"enablePriority": "Filter nach Priorität aktiviere",
|
||||||
"enablePercentDone": "Filter nach Prozent iihschalte",
|
"enablePercentDone": "Filter nach Fortschritt aktivieren",
|
||||||
"dueDateRange": "Fälligkeitsberiich",
|
"dueDateRange": "Fälligkeitsberiich",
|
||||||
"startDateRange": "Startdatumsbreiich",
|
"startDateRange": "Startdatumsbreiich",
|
||||||
"endDateRange": "Enddatumsberiich",
|
"endDateRange": "Enddatumsberiich",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Enddatum setze",
|
"endDate": "Enddatum setze",
|
||||||
"reminders": "Errinnerig iihstelle",
|
"reminders": "Errinnerig iihstelle",
|
||||||
"repeatAfter": "En wiederholende Intervall setze",
|
"repeatAfter": "En wiederholende Intervall setze",
|
||||||
"percentDone": "Prozentuelli Erledigung setze",
|
"percentDone": "Fortschritt einstellen",
|
||||||
"attachments": "Aahang hinzuefüege",
|
"attachments": "Aahang hinzuefüege",
|
||||||
"relatedTasks": "Uufgabsbeziehig hinzufüege",
|
"relatedTasks": "Uufgabsbeziehig hinzufüege",
|
||||||
"moveList": "Uufgab verschiebe",
|
"moveList": "Uufgab verschiebe",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Fälligkeitsdatum",
|
"dueDate": "Fälligkeitsdatum",
|
||||||
"endDate": "Enddatum",
|
"endDate": "Enddatum",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% fertig",
|
"percentDone": "Fortschritt",
|
||||||
"priority": "Priorität",
|
"priority": "Priorität",
|
||||||
"relatedTasks": "Verwandti Uufgabe",
|
"relatedTasks": "Verwandti Uufgabe",
|
||||||
"reminders": "Errinnerige",
|
"reminders": "Errinnerige",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -619,22 +622,22 @@
|
||||||
"text2": "This will also remove all attachments, reminders and relations associated with this task and cannot be undone!"
|
"text2": "This will also remove all attachments, reminders and relations associated with this task and cannot be undone!"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"assign": "Assign to a user",
|
"assign": "Assign to User",
|
||||||
"label": "Add labels",
|
"label": "Add Labels",
|
||||||
"priority": "Set Priority",
|
"priority": "Set Priority",
|
||||||
"dueDate": "Set Due Date",
|
"dueDate": "Set Due Date",
|
||||||
"startDate": "Set a Start Date",
|
"startDate": "Set Start Date",
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set Repeating Interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add Attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add Relation",
|
||||||
"moveList": "Move task",
|
"moveList": "Move",
|
||||||
"color": "Set task color",
|
"color": "Set Color",
|
||||||
"delete": "Delete task",
|
"delete": "Delete",
|
||||||
"favorite": "Save as favorite",
|
"favorite": "Add to Favorites",
|
||||||
"unfavorite": "Remove from favorites"
|
"unfavorite": "Remove from Favorites"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
|
@ -647,7 +650,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set an End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set a repeating interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add task relations",
|
||||||
"moveList": "Move task",
|
"moveList": "Move task",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
"email": "Email address",
|
"email": "Email address",
|
||||||
"emailPlaceholder": "p. ex. frederic{'@'}vikunja.io",
|
"emailPlaceholder": "p. ex. frederic{'@'}vikunja.io",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"passwordRepeat": "Retape ton mot de passe",
|
|
||||||
"passwordPlaceholder": "p. ex. •••••••••••",
|
"passwordPlaceholder": "p. ex. •••••••••••",
|
||||||
"forgotPassword": "Forgot your password?",
|
"forgotPassword": "Forgot your password?",
|
||||||
"resetPassword": "Réinitialiser ton mot de passe",
|
"resetPassword": "Réinitialiser ton mot de passe",
|
||||||
|
@ -45,12 +44,20 @@
|
||||||
"totpTitle": "Code d’authentification à deux facteurs",
|
"totpTitle": "Code d’authentification à deux facteurs",
|
||||||
"totpPlaceholder": "p. ex. 123456",
|
"totpPlaceholder": "p. ex. 123456",
|
||||||
"login": "Se connecter",
|
"login": "Se connecter",
|
||||||
"register": "S’inscrire",
|
"createAccount": "Create account",
|
||||||
"loginWith": "Se connecter avec {provider}",
|
"loginWith": "Se connecter avec {provider}",
|
||||||
"authenticating": "Authentification…",
|
"authenticating": "Authentification…",
|
||||||
"openIdStateError": "L’état ne correspond pas, impossible de continuer !",
|
"openIdStateError": "L’état ne correspond pas, impossible de continuer !",
|
||||||
"openIdGeneralError": "Une erreur s'est produite lors de l'authentification contre un tiers.",
|
"openIdGeneralError": "Une erreur s'est produite lors de l'authentification contre un tiers.",
|
||||||
"logout": "Se déconnecter"
|
"logout": "Se déconnecter",
|
||||||
|
"emailInvalid": "Please enter a valid email address.",
|
||||||
|
"usernameRequired": "Please provide a username.",
|
||||||
|
"passwordRequired": "Please provide a password.",
|
||||||
|
"showPassword": "Show the password",
|
||||||
|
"hidePassword": "Hide the password",
|
||||||
|
"noAccountYet": "Don't have an account yet?",
|
||||||
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Paramètres",
|
"title": "Paramètres",
|
||||||
|
@ -61,7 +68,7 @@
|
||||||
"currentPasswordPlaceholder": "Ton mot de passe actuel",
|
"currentPasswordPlaceholder": "Ton mot de passe actuel",
|
||||||
"passwordsDontMatch": "Le nouveau mot de passe et sa confirmation ne correspondent pas.",
|
"passwordsDontMatch": "Le nouveau mot de passe et sa confirmation ne correspondent pas.",
|
||||||
"passwordUpdateSuccess": "Mot de passe mis à jour.",
|
"passwordUpdateSuccess": "Mot de passe mis à jour.",
|
||||||
"updateEmailTitle": "Mets à jour ton adresse électronique",
|
"updateEmailTitle": "Update Your Email Address",
|
||||||
"updateEmailNew": "Nouvelle adresse courriel",
|
"updateEmailNew": "Nouvelle adresse courriel",
|
||||||
"updateEmailSuccess": "Mise à jour de l’adresse électronique. Clique sur le lien dans le courriel qui t’a été envoyé pour le confirmer.",
|
"updateEmailSuccess": "Mise à jour de l’adresse électronique. Clique sur le lien dans le courriel qui t’a été envoyé pour le confirmer.",
|
||||||
"general": {
|
"general": {
|
||||||
|
@ -78,7 +85,8 @@
|
||||||
"weekStartSunday": "dimanche",
|
"weekStartSunday": "dimanche",
|
||||||
"weekStartMonday": "lundi",
|
"weekStartMonday": "lundi",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"defaultList": "Liste par défaut"
|
"defaultList": "Liste par défaut",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Authentification à deux facteurs",
|
"title": "Authentification à deux facteurs",
|
||||||
|
@ -327,6 +335,7 @@
|
||||||
"archiveText": "Tu ne pourras pas modifier cet espace de noms ou créer de nouvelles listes tant que tu ne l’auras pas désarchivé. Ceci archivera également toutes les listes de cet espace de noms.",
|
"archiveText": "Tu ne pourras pas modifier cet espace de noms ou créer de nouvelles listes tant que tu ne l’auras pas désarchivé. Ceci archivera également toutes les listes de cet espace de noms.",
|
||||||
"unarchiveText": "Tu pourras créer de nouvelles listes ou les modifier.",
|
"unarchiveText": "Tu pourras créer de nouvelles listes ou les modifier.",
|
||||||
"success": "Espace de noms archivé.",
|
"success": "Espace de noms archivé.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "L’archivage d’un espace de noms signifie qu’on ne peut pas créer de nouvelles listes dans cet espace, ni le modifier."
|
"description": "L’archivage d’un espace de noms signifie qu’on ne peut pas créer de nouvelles listes dans cet espace, ni le modifier."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
"showDoneTasks": "Afficher les tâches terminées",
|
"showDoneTasks": "Afficher les tâches terminées",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Activer le filtre par priorité",
|
"enablePriority": "Activer le filtre par priorité",
|
||||||
"enablePercentDone": "Par % d’achèvement",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Plage de dates d’échéance",
|
"dueDateRange": "Plage de dates d’échéance",
|
||||||
"startDateRange": "Plage de dates de début",
|
"startDateRange": "Plage de dates de début",
|
||||||
"endDateRange": "Plage de dates de fin",
|
"endDateRange": "Plage de dates de fin",
|
||||||
|
@ -569,7 +578,7 @@
|
||||||
"endDate": "Fixer une date de fin",
|
"endDate": "Fixer une date de fin",
|
||||||
"reminders": "Définir des rappels",
|
"reminders": "Définir des rappels",
|
||||||
"repeatAfter": "Définir un intervalle de répétition",
|
"repeatAfter": "Définir un intervalle de répétition",
|
||||||
"percentDone": "Définir le pourcentage d’achèvement",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Ajouter des pièces jointes",
|
"attachments": "Ajouter des pièces jointes",
|
||||||
"relatedTasks": "Ajouter des relations de tâches",
|
"relatedTasks": "Ajouter des relations de tâches",
|
||||||
"moveList": "Déplacer la tâche",
|
"moveList": "Déplacer la tâche",
|
||||||
|
@ -589,7 +598,7 @@
|
||||||
"dueDate": "Date d’échéance",
|
"dueDate": "Date d’échéance",
|
||||||
"endDate": "Date de fin",
|
"endDate": "Date de fin",
|
||||||
"labels": "Étiquettes",
|
"labels": "Étiquettes",
|
||||||
"percentDone": "% terminé",
|
"percentDone": "Progress",
|
||||||
"priority": "Priorité",
|
"priority": "Priorité",
|
||||||
"relatedTasks": "Tâches connexes",
|
"relatedTasks": "Tâches connexes",
|
||||||
"reminders": "Rappels",
|
"reminders": "Rappels",
|
||||||
|
|
|
@ -31,10 +31,9 @@
|
||||||
"username": "Nome utente",
|
"username": "Nome utente",
|
||||||
"usernameEmail": "Nome utente o indirizzo e-mail",
|
"usernameEmail": "Nome utente o indirizzo e-mail",
|
||||||
"usernamePlaceholder": "es. frederick",
|
"usernamePlaceholder": "es. frederick",
|
||||||
"email": "Email address",
|
"email": "Indirizzo e-mail",
|
||||||
"emailPlaceholder": "per es. frederic{'@'}vikunja.io",
|
"emailPlaceholder": "per es. frederic{'@'}vikunja.io",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"passwordRepeat": "Digita di nuovo la tua password",
|
|
||||||
"passwordPlaceholder": "es. ••••••••••••",
|
"passwordPlaceholder": "es. ••••••••••••",
|
||||||
"forgotPassword": "Password dimenticata?",
|
"forgotPassword": "Password dimenticata?",
|
||||||
"resetPassword": "Reimposta la tua password",
|
"resetPassword": "Reimposta la tua password",
|
||||||
|
@ -45,12 +44,20 @@
|
||||||
"totpTitle": "Codice di autenticazione a due fattori",
|
"totpTitle": "Codice di autenticazione a due fattori",
|
||||||
"totpPlaceholder": "es. 123456",
|
"totpPlaceholder": "es. 123456",
|
||||||
"login": "Accedi",
|
"login": "Accedi",
|
||||||
"register": "Registrati",
|
"createAccount": "Crea account",
|
||||||
"loginWith": "Accedi con {provider}",
|
"loginWith": "Accedi con {provider}",
|
||||||
"authenticating": "Autenticazione…",
|
"authenticating": "Autenticazione…",
|
||||||
"openIdStateError": "Stato non corrispondente, impossibile continuare!",
|
"openIdStateError": "Stato non corrispondente, impossibile continuare!",
|
||||||
"openIdGeneralError": "Si è verificato un errore durante l'autenticazione con terze parti.",
|
"openIdGeneralError": "Si è verificato un errore durante l'autenticazione con terze parti.",
|
||||||
"logout": "Esci"
|
"logout": "Esci",
|
||||||
|
"emailInvalid": "Inserisci un indirizzo e-mail valido.",
|
||||||
|
"usernameRequired": "Inserisci un nome utente.",
|
||||||
|
"passwordRequired": "Inserisci una password.",
|
||||||
|
"showPassword": "Mostra la password",
|
||||||
|
"hidePassword": "Nascondi la password",
|
||||||
|
"noAccountYet": "Non hai un account?",
|
||||||
|
"alreadyHaveAnAccount": "Hai già un account?",
|
||||||
|
"remember": "Resta connesso"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Impostazioni",
|
"title": "Impostazioni",
|
||||||
|
@ -61,7 +68,7 @@
|
||||||
"currentPasswordPlaceholder": "La tua password attuale",
|
"currentPasswordPlaceholder": "La tua password attuale",
|
||||||
"passwordsDontMatch": "La nuova password e la conferma non coincidono.",
|
"passwordsDontMatch": "La nuova password e la conferma non coincidono.",
|
||||||
"passwordUpdateSuccess": "Password aggiornata con successo.",
|
"passwordUpdateSuccess": "Password aggiornata con successo.",
|
||||||
"updateEmailTitle": "Inserisci il tuo indirizzo e-mail",
|
"updateEmailTitle": "Aggiorna l'indirizzo e-mail",
|
||||||
"updateEmailNew": "Nuovo indirizzo e-mail",
|
"updateEmailNew": "Nuovo indirizzo e-mail",
|
||||||
"updateEmailSuccess": "Il tuo indirizzo e-mail è stato aggiornato correttamente. Ti abbiamo inviato un collegamento per confermarlo.",
|
"updateEmailSuccess": "Il tuo indirizzo e-mail è stato aggiornato correttamente. Ti abbiamo inviato un collegamento per confermarlo.",
|
||||||
"general": {
|
"general": {
|
||||||
|
@ -78,7 +85,8 @@
|
||||||
"weekStartSunday": "Domenica",
|
"weekStartSunday": "Domenica",
|
||||||
"weekStartMonday": "Lunedì",
|
"weekStartMonday": "Lunedì",
|
||||||
"language": "Lingua",
|
"language": "Lingua",
|
||||||
"defaultList": "Lista predefinita"
|
"defaultList": "Lista predefinita",
|
||||||
|
"timezone": "Fuso Orario"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Autenticazione a due fattori",
|
"title": "Autenticazione a due fattori",
|
||||||
|
@ -95,9 +103,9 @@
|
||||||
"disableSuccess": "L'autenticazione a due fattori è stata disattivata."
|
"disableSuccess": "L'autenticazione a due fattori è stata disattivata."
|
||||||
},
|
},
|
||||||
"caldav": {
|
"caldav": {
|
||||||
"title": "CalDav",
|
"title": "CalDAV",
|
||||||
"howTo": "Puoi connettere Vikunja ai client caldav per visualizzare e gestire tutte le attività da diversi client. Inserisci questo URL nel tuo client:",
|
"howTo": "Puoi connettere Vikunja ai client CalDAV per visualizzare e gestire tutte le attività da diversi client. Inserisci questo URL nel tuo client:",
|
||||||
"more": "Ulteriori informazioni su caldav in Vikunja"
|
"more": "Ulteriori informazioni su CalDAV in Vikunja"
|
||||||
},
|
},
|
||||||
"avatar": {
|
"avatar": {
|
||||||
"title": "Avatar",
|
"title": "Avatar",
|
||||||
|
@ -327,6 +335,7 @@
|
||||||
"archiveText": "Non sarà possibile modificare questo namespace o creare nuove liste fino a quando non verrà disarchiviato. Questo archivierà anche tutte le liste in questo namespace.",
|
"archiveText": "Non sarà possibile modificare questo namespace o creare nuove liste fino a quando non verrà disarchiviato. Questo archivierà anche tutte le liste in questo namespace.",
|
||||||
"unarchiveText": "Potrai creare nuove liste o modificarle.",
|
"unarchiveText": "Potrai creare nuove liste o modificarle.",
|
||||||
"success": "Namespace creato.",
|
"success": "Namespace creato.",
|
||||||
|
"unarchiveSuccess": "Namespace estratto dall'archivio.",
|
||||||
"description": "Se un namespace è archiviato, non è possibile creare nuove liste o modificarlo."
|
"description": "Se un namespace è archiviato, non è possibile creare nuove liste o modificarlo."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -376,7 +385,7 @@
|
||||||
"showDoneTasks": "Mostra Attività Fatte",
|
"showDoneTasks": "Mostra Attività Fatte",
|
||||||
"sortAlphabetically": "Ordine alfabetico",
|
"sortAlphabetically": "Ordine alfabetico",
|
||||||
"enablePriority": "Abilita Filtro Per Priorità",
|
"enablePriority": "Abilita Filtro Per Priorità",
|
||||||
"enablePercentDone": "Abilitare Filtro Per Percentuale Fatta",
|
"enablePercentDone": "Abilita Filtro Per Progresso",
|
||||||
"dueDateRange": "Intervallo Data Di Scadenza",
|
"dueDateRange": "Intervallo Data Di Scadenza",
|
||||||
"startDateRange": "Intervallo Data Iniziale",
|
"startDateRange": "Intervallo Data Iniziale",
|
||||||
"endDateRange": "Intervallo Data Finale",
|
"endDateRange": "Intervallo Data Finale",
|
||||||
|
@ -569,7 +578,7 @@
|
||||||
"endDate": "Imposta una data di fine",
|
"endDate": "Imposta una data di fine",
|
||||||
"reminders": "Imposta promemoria",
|
"reminders": "Imposta promemoria",
|
||||||
"repeatAfter": "Imposta ricorrenza",
|
"repeatAfter": "Imposta ricorrenza",
|
||||||
"percentDone": "Imposta Percentuale Completata",
|
"percentDone": "Imposta Progresso",
|
||||||
"attachments": "Aggiungi allegati",
|
"attachments": "Aggiungi allegati",
|
||||||
"relatedTasks": "Aggiungi attività collegate",
|
"relatedTasks": "Aggiungi attività collegate",
|
||||||
"moveList": "Sposta attività",
|
"moveList": "Sposta attività",
|
||||||
|
@ -589,7 +598,7 @@
|
||||||
"dueDate": "Data di scadenza",
|
"dueDate": "Data di scadenza",
|
||||||
"endDate": "Data di fine",
|
"endDate": "Data di fine",
|
||||||
"labels": "Etichette",
|
"labels": "Etichette",
|
||||||
"percentDone": "% Completata",
|
"percentDone": "Progresso",
|
||||||
"priority": "Priorità",
|
"priority": "Priorità",
|
||||||
"relatedTasks": "Attività Collegate",
|
"relatedTasks": "Attività Collegate",
|
||||||
"reminders": "Promemoria",
|
"reminders": "Promemoria",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set an End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set a repeating interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add task relations",
|
||||||
"moveList": "Move task",
|
"moveList": "Move task",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set an End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set a repeating interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add task relations",
|
||||||
"moveList": "Move task",
|
"moveList": "Move task",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Настройки",
|
"title": "Настройки",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Воскресенье",
|
"weekStartSunday": "Воскресенье",
|
||||||
"weekStartMonday": "Понедельник",
|
"weekStartMonday": "Понедельник",
|
||||||
"language": "Язык",
|
"language": "Язык",
|
||||||
"defaultList": "Список по умолчанию"
|
"defaultList": "Список по умолчанию",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Двухфакторная аутентификация",
|
"title": "Двухфакторная аутентификация",
|
||||||
|
@ -103,7 +105,7 @@
|
||||||
"caldav": {
|
"caldav": {
|
||||||
"title": "CalDAV",
|
"title": "CalDAV",
|
||||||
"howTo": "Ты можешь подключить Vikunja к клиентам CalDAV, чтобы просматривать и управлять всеми задачами из разных клиентов. Введи этот URL в свой клиент:",
|
"howTo": "Ты можешь подключить Vikunja к клиентам CalDAV, чтобы просматривать и управлять всеми задачами из разных клиентов. Введи этот URL в свой клиент:",
|
||||||
"more": "Подробнее о caldav в Vikunja"
|
"more": "Подробнее о CalDAV в Vikunja"
|
||||||
},
|
},
|
||||||
"avatar": {
|
"avatar": {
|
||||||
"title": "Аватар",
|
"title": "Аватар",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "Ты не сможешь изменять это пространство имён, пока не вернёшь его из архива. Это также касается всех списков в этом пространстве имён.",
|
"archiveText": "Ты не сможешь изменять это пространство имён, пока не вернёшь его из архива. Это также касается всех списков в этом пространстве имён.",
|
||||||
"unarchiveText": "Ты сможешь создавать новые списки или изменять их.",
|
"unarchiveText": "Ты сможешь создавать новые списки или изменять их.",
|
||||||
"success": "Пространство имён архивировано.",
|
"success": "Пространство имён архивировано.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "Архивирование пространства имён означает, что ты не сможешь создавать в нём новые списки или изменять их."
|
"description": "Архивирование пространства имён означает, что ты не сможешь создавать в нём новые списки или изменять их."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Показывать завершённые задачи",
|
"showDoneTasks": "Показывать завершённые задачи",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Вкл. фильтр по приоритету",
|
"enablePriority": "Вкл. фильтр по приоритету",
|
||||||
"enablePercentDone": "По % завершения",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Диапазон срока",
|
"dueDateRange": "Диапазон срока",
|
||||||
"startDateRange": "Диапазон даты начала",
|
"startDateRange": "Диапазон даты начала",
|
||||||
"endDateRange": "Диапазон даты завершения",
|
"endDateRange": "Диапазон даты завершения",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Установить дату завершения",
|
"endDate": "Установить дату завершения",
|
||||||
"reminders": "Установить напоминания",
|
"reminders": "Установить напоминания",
|
||||||
"repeatAfter": "Установить интервал повтора",
|
"repeatAfter": "Установить интервал повтора",
|
||||||
"percentDone": "Установить процент завершения",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Добавить вложения",
|
"attachments": "Добавить вложения",
|
||||||
"relatedTasks": "Добавить связанные задачи",
|
"relatedTasks": "Добавить связанные задачи",
|
||||||
"moveList": "Переместить задачу",
|
"moveList": "Переместить задачу",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Срок",
|
"dueDate": "Срок",
|
||||||
"endDate": "Дата завершения",
|
"endDate": "Дата завершения",
|
||||||
"labels": "Метки",
|
"labels": "Метки",
|
||||||
"percentDone": "% Завершено",
|
"percentDone": "Progress",
|
||||||
"priority": "Приоритет",
|
"priority": "Приоритет",
|
||||||
"relatedTasks": "Связанные задачи",
|
"relatedTasks": "Связанные задачи",
|
||||||
"reminders": "Напоминания",
|
"reminders": "Напоминания",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set an End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set a repeating interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add task relations",
|
||||||
"moveList": "Move task",
|
"moveList": "Move task",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Sunday",
|
"weekStartSunday": "Sunday",
|
||||||
"weekStartMonday": "Monday",
|
"weekStartMonday": "Monday",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultList": "Default List"
|
"defaultList": "Default List",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Two Factor Authentication",
|
"title": "Two Factor Authentication",
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
"archiveText": "You won't be able to edit this namespace or create new lists until you un-archive it. This will also archive all lists in this namespace.",
|
||||||
"unarchiveText": "You will be able to create new lists or edit it.",
|
"unarchiveText": "You will be able to create new lists or edit it.",
|
||||||
"success": "The namespace was successfully archived.",
|
"success": "The namespace was successfully archived.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
"description": "If a namespace is archived, you cannot create new lists or edit it."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Show Done Tasks",
|
"showDoneTasks": "Show Done Tasks",
|
||||||
"sortAlphabetically": "Sort Alphabetically",
|
"sortAlphabetically": "Sort Alphabetically",
|
||||||
"enablePriority": "Enable Filter By Priority",
|
"enablePriority": "Enable Filter By Priority",
|
||||||
"enablePercentDone": "Enable Filter By Percent Done",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Due Date Range",
|
"dueDateRange": "Due Date Range",
|
||||||
"startDateRange": "Start Date Range",
|
"startDateRange": "Start Date Range",
|
||||||
"endDateRange": "End Date Range",
|
"endDateRange": "End Date Range",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Set an End Date",
|
"endDate": "Set an End Date",
|
||||||
"reminders": "Set Reminders",
|
"reminders": "Set Reminders",
|
||||||
"repeatAfter": "Set a repeating interval",
|
"repeatAfter": "Set a repeating interval",
|
||||||
"percentDone": "Set Percent Done",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Add attachments",
|
"attachments": "Add attachments",
|
||||||
"relatedTasks": "Add task relations",
|
"relatedTasks": "Add task relations",
|
||||||
"moveList": "Move task",
|
"moveList": "Move task",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Due Date",
|
"dueDate": "Due Date",
|
||||||
"endDate": "End Date",
|
"endDate": "End Date",
|
||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"percentDone": "% Done",
|
"percentDone": "Progress",
|
||||||
"priority": "Priority",
|
"priority": "Priority",
|
||||||
"relatedTasks": "Related Tasks",
|
"relatedTasks": "Related Tasks",
|
||||||
"reminders": "Reminders",
|
"reminders": "Reminders",
|
||||||
|
|
|
@ -56,7 +56,8 @@
|
||||||
"showPassword": "Show the password",
|
"showPassword": "Show the password",
|
||||||
"hidePassword": "Hide the password",
|
"hidePassword": "Hide the password",
|
||||||
"noAccountYet": "Don't have an account yet?",
|
"noAccountYet": "Don't have an account yet?",
|
||||||
"alreadyHaveAnAccount": "Already have an account?"
|
"alreadyHaveAnAccount": "Already have an account?",
|
||||||
|
"remember": "Stay logged in"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Cài đặt",
|
"title": "Cài đặt",
|
||||||
|
@ -84,7 +85,8 @@
|
||||||
"weekStartSunday": "Chủ nhật",
|
"weekStartSunday": "Chủ nhật",
|
||||||
"weekStartMonday": "Thứ hai",
|
"weekStartMonday": "Thứ hai",
|
||||||
"language": "Ngôn ngữ",
|
"language": "Ngôn ngữ",
|
||||||
"defaultList": "Danh sách mặc định"
|
"defaultList": "Danh sách mặc định",
|
||||||
|
"timezone": "Time Zone"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"title": "Xác thực hai lớp",
|
"title": "Xác thực hai lớp",
|
||||||
|
@ -101,7 +103,7 @@
|
||||||
"disableSuccess": "Xác thực hai lớp đã bị vô hiệu hóa thành công."
|
"disableSuccess": "Xác thực hai lớp đã bị vô hiệu hóa thành công."
|
||||||
},
|
},
|
||||||
"caldav": {
|
"caldav": {
|
||||||
"title": "Giao thức Caldav",
|
"title": "Giao thức CalDAV",
|
||||||
"howTo": "Bạn có thể kết nối Vikunja tới các máy khách CalDAV để xem và quản lý tất cả các công việc từ nhiều máy khách khác nhau. Nhập URL này vào ứng dụng khách của bạn:",
|
"howTo": "Bạn có thể kết nối Vikunja tới các máy khách CalDAV để xem và quản lý tất cả các công việc từ nhiều máy khách khác nhau. Nhập URL này vào ứng dụng khách của bạn:",
|
||||||
"more": "Tìm hiểu thêm về CalDAV"
|
"more": "Tìm hiểu thêm về CalDAV"
|
||||||
},
|
},
|
||||||
|
@ -333,6 +335,7 @@
|
||||||
"archiveText": "Bạn sẽ không thể chỉnh sửa góc làm việc này hoặc tạo danh sách mới cho đến khi bạn bỏ lưu trữ nó. Điều này cũng sẽ lưu trữ tất cả các danh sách trong góc làm việc này.",
|
"archiveText": "Bạn sẽ không thể chỉnh sửa góc làm việc này hoặc tạo danh sách mới cho đến khi bạn bỏ lưu trữ nó. Điều này cũng sẽ lưu trữ tất cả các danh sách trong góc làm việc này.",
|
||||||
"unarchiveText": "Bạn có thể tạo danh sách mới hoặc chỉnh sửa nó.",
|
"unarchiveText": "Bạn có thể tạo danh sách mới hoặc chỉnh sửa nó.",
|
||||||
"success": "Góc làm việc đã lưu trữ thành công.",
|
"success": "Góc làm việc đã lưu trữ thành công.",
|
||||||
|
"unarchiveSuccess": "The namespace was successfully un-archived.",
|
||||||
"description": "Nếu một góc làm việc được lưu trữ, bạn không thể tạo thêm danh sách hoặc chỉnh sửa nó."
|
"description": "Nếu một góc làm việc được lưu trữ, bạn không thể tạo thêm danh sách hoặc chỉnh sửa nó."
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
|
@ -382,7 +385,7 @@
|
||||||
"showDoneTasks": "Hiển thị các công việc đã hoàn thành",
|
"showDoneTasks": "Hiển thị các công việc đã hoàn thành",
|
||||||
"sortAlphabetically": "Xếp theo bảng chữ cái",
|
"sortAlphabetically": "Xếp theo bảng chữ cái",
|
||||||
"enablePriority": "Bật Bộ lọc theo mức độ ưu tiên",
|
"enablePriority": "Bật Bộ lọc theo mức độ ưu tiên",
|
||||||
"enablePercentDone": "Bật Bộ lọc theo tỉ lệ % hoàn thành",
|
"enablePercentDone": "Enable Filter By Progress",
|
||||||
"dueDateRange": "Phạm vi ngày đến hạn",
|
"dueDateRange": "Phạm vi ngày đến hạn",
|
||||||
"startDateRange": "Phạm vi Ngày bắt đầu",
|
"startDateRange": "Phạm vi Ngày bắt đầu",
|
||||||
"endDateRange": "Phạm vi Ngày Kết thúc",
|
"endDateRange": "Phạm vi Ngày Kết thúc",
|
||||||
|
@ -575,7 +578,7 @@
|
||||||
"endDate": "Chọn ngày kết thúc",
|
"endDate": "Chọn ngày kết thúc",
|
||||||
"reminders": "Thiết lập nhắc nhở",
|
"reminders": "Thiết lập nhắc nhở",
|
||||||
"repeatAfter": "Đặt khoảng lặp lại",
|
"repeatAfter": "Đặt khoảng lặp lại",
|
||||||
"percentDone": "Chọn tỉ lệ hoàn thành",
|
"percentDone": "Set Progress",
|
||||||
"attachments": "Đính kèm tệp",
|
"attachments": "Đính kèm tệp",
|
||||||
"relatedTasks": "Thêm liên kết công việc",
|
"relatedTasks": "Thêm liên kết công việc",
|
||||||
"moveList": "Di chuyển công việc",
|
"moveList": "Di chuyển công việc",
|
||||||
|
@ -595,7 +598,7 @@
|
||||||
"dueDate": "Ngày hết hạn",
|
"dueDate": "Ngày hết hạn",
|
||||||
"endDate": "Ngày kết thúc",
|
"endDate": "Ngày kết thúc",
|
||||||
"labels": "Nhãn",
|
"labels": "Nhãn",
|
||||||
"percentDone": "Tiến độ hoàn thành",
|
"percentDone": "Progress",
|
||||||
"priority": "Mức độ ưu tiên",
|
"priority": "Mức độ ưu tiên",
|
||||||
"relatedTasks": "Công việc liên quan",
|
"relatedTasks": "Công việc liên quan",
|
||||||
"reminders": "Nhắc nhở",
|
"reminders": "Nhắc nhở",
|
||||||
|
|
|
@ -4,7 +4,7 @@ export default class EmailUpdateModel extends AbstractModel {
|
||||||
defaults() {
|
defaults() {
|
||||||
return {
|
return {
|
||||||
newEmail: '',
|
newEmail: '',
|
||||||
passwort: '',
|
password: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@ export default class UserSettingsModel extends AbstractModel {
|
||||||
overdueTasksRemindersEnabled: true,
|
overdueTasksRemindersEnabled: true,
|
||||||
defaultListId: undefined,
|
defaultListId: undefined,
|
||||||
weekStart: 0,
|
weekStart: 0,
|
||||||
|
timezone: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import {HTTPFactory} from '@/http-common'
|
import {HTTPFactory, AuthenticatedHTTPFactory} from '@/http-common'
|
||||||
import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n'
|
import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n'
|
||||||
|
import {objectToSnakeCase} from '@/helpers/case'
|
||||||
import {LOADING} from '../mutation-types'
|
import {LOADING} from '../mutation-types'
|
||||||
import UserModel from '@/models/user'
|
import UserModel from '@/models/user'
|
||||||
import UserSettingsService from '@/services/userSettings'
|
import UserSettingsService from '@/services/userSettings'
|
||||||
|
@ -90,17 +91,8 @@ export default {
|
||||||
// Delete an eventually preexisting old token
|
// Delete an eventually preexisting old token
|
||||||
removeToken()
|
removeToken()
|
||||||
|
|
||||||
const data = {
|
|
||||||
username: credentials.username,
|
|
||||||
password: credentials.password,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (credentials.totpPasscode) {
|
|
||||||
data.totp_passcode = credentials.totpPasscode
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await HTTP.post('login', data)
|
const response = await HTTP.post('login', objectToSnakeCase(credentials))
|
||||||
// Save the token to local storage for later use
|
// Save the token to local storage for later use
|
||||||
saveToken(response.data.token, true)
|
saveToken(response.data.token, true)
|
||||||
|
|
||||||
|
@ -223,13 +215,9 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const HTTP = HTTPFactory()
|
const HTTP = AuthenticatedHTTPFactory(jwt)
|
||||||
try {
|
try {
|
||||||
const response = await HTTP.get('user', {
|
const response = await HTTP.get('user')
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${jwt}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const info = new UserModel(response.data)
|
const info = new UserModel(response.data)
|
||||||
info.type = state.info.type
|
info.type = state.info.type
|
||||||
info.email = state.info.email
|
info.email = state.info.email
|
||||||
|
|
|
@ -44,35 +44,15 @@ export default {
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
[CONFIG](state, config) {
|
[CONFIG](state, config) {
|
||||||
state.version = config.version
|
Object.assign(state, config)
|
||||||
state.frontendUrl = config.frontend_url
|
|
||||||
state.motd = config.motd
|
|
||||||
state.linkSharingEnabled = config.link_sharing_enabled
|
|
||||||
state.maxFileSize = config.max_file_size
|
|
||||||
state.registrationEnabled = config.registration_enabled
|
|
||||||
state.availableMigrators = config.available_migrators
|
|
||||||
state.taskAttachmentsEnabled = config.task_attachments_enabled
|
|
||||||
state.totpEnabled = config.totp_enabled
|
|
||||||
state.enabledBackgroundProviders = config.enabled_background_providers
|
|
||||||
state.legal.imprintUrl = config.legal.imprint_url
|
|
||||||
state.legal.privacyPolicyUrl = config.legal.privacy_policy_url
|
|
||||||
state.caldavEnabled = config.caldav_enabled
|
|
||||||
state.userDeletionEnabled = config.user_deletion_enabled
|
|
||||||
state.taskCommentsEnabled = config.task_comments_enabled
|
|
||||||
const auth = objectToCamelCase(config.auth)
|
|
||||||
state.auth.local.enabled = auth.local.enabled
|
|
||||||
state.auth.openidConnect.enabled = auth.openidConnect.enabled
|
|
||||||
state.auth.openidConnect.redirectUrl = auth.openidConnect.redirectUrl
|
|
||||||
state.auth.openidConnect.providers = auth.openidConnect.providers
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async update(ctx) {
|
async update(ctx) {
|
||||||
const HTTP = HTTPFactory()
|
const HTTP = HTTPFactory()
|
||||||
|
const {data: config} = await HTTP.get('info')
|
||||||
const {data: info} = await HTTP.get('info')
|
ctx.commit(CONFIG, objectToCamelCase(config))
|
||||||
ctx.commit(CONFIG, info)
|
return config
|
||||||
return info
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
|
@ -133,9 +133,19 @@ export default {
|
||||||
console.debug('Could not add assignee to task in kanban, task not found', t)
|
console.debug('Could not add assignee to task in kanban, task not found', t)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
// FIXME: direct store manipulation (task)
|
|
||||||
t.task.assignees.push(user)
|
const assignees = [
|
||||||
ctx.commit('kanban/setTaskInBucketByIndex', t, { root: true })
|
...t.task.assignees,
|
||||||
|
user,
|
||||||
|
]
|
||||||
|
|
||||||
|
ctx.commit('kanban/setTaskInBucketByIndex', {
|
||||||
|
...t,
|
||||||
|
task: {
|
||||||
|
...t.task,
|
||||||
|
assignees,
|
||||||
|
},
|
||||||
|
}, {root: true})
|
||||||
return r
|
return r
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -153,15 +163,15 @@ export default {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const a in t.task.assignees) {
|
const assignees = t.task.assignees.filter(({ id }) => id !== user.id)
|
||||||
if (t.task.assignees[a].id === user.id) {
|
|
||||||
// FIXME: direct store manipulation (task)
|
|
||||||
t.task.assignees.splice(a, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.commit('kanban/setTaskInBucketByIndex', t, {root: true})
|
ctx.commit('kanban/setTaskInBucketByIndex', {
|
||||||
|
...t,
|
||||||
|
task: {
|
||||||
|
...t.task,
|
||||||
|
assignees,
|
||||||
|
},
|
||||||
|
}, {root: true})
|
||||||
return response
|
return response
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -179,17 +189,19 @@ export default {
|
||||||
console.debug('Could not add label to task in kanban, task not found', t)
|
console.debug('Could not add label to task in kanban, task not found', t)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
const labels = [...t.task.labels]
|
const labels = [
|
||||||
labels.push(label)
|
...t.task.labels,
|
||||||
|
label,
|
||||||
|
]
|
||||||
|
|
||||||
ctx.commit('kanban/setTaskInBucketByIndex', {
|
ctx.commit('kanban/setTaskInBucketByIndex', {
|
||||||
task: {
|
|
||||||
labels,
|
|
||||||
...t.task,
|
|
||||||
},
|
|
||||||
...t,
|
...t,
|
||||||
}, { root: true })
|
task: {
|
||||||
|
...t.task,
|
||||||
|
labels,
|
||||||
|
},
|
||||||
|
}, {root: true})
|
||||||
|
|
||||||
return r
|
return r
|
||||||
},
|
},
|
||||||
|
@ -209,20 +221,14 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the label from the list
|
// Remove the label from the list
|
||||||
const labels = [...t.task.labels]
|
const labels = t.task.labels.filter(({ id }) => id !== label.id)
|
||||||
for (const l in labels) {
|
|
||||||
if (labels[l].id === label.id) {
|
|
||||||
labels.splice(l, 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.commit('kanban/setTaskInBucketByIndex', {
|
ctx.commit('kanban/setTaskInBucketByIndex', {
|
||||||
task: {
|
|
||||||
labels,
|
|
||||||
...t.task,
|
|
||||||
},
|
|
||||||
...t,
|
...t,
|
||||||
|
task: {
|
||||||
|
...t.task,
|
||||||
|
labels,
|
||||||
|
},
|
||||||
}, {root: true})
|
}, {root: true})
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
<ListWrapper class="list-kanban" :list-id="listId" viewName="kanban">
|
<ListWrapper class="list-kanban" :list-id="listId" viewName="kanban">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="filter-container" v-if="isSavedFilter">
|
<div class="filter-container" v-if="isSavedFilter">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<filter-popup
|
<filter-popup
|
||||||
v-model="params"
|
v-model="params"
|
||||||
@update:modelValue="loadBuckets"
|
@update:modelValue="loadBuckets"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -123,61 +123,59 @@
|
||||||
</a>
|
</a>
|
||||||
</dropdown>
|
</dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
:ref="(el) => setTaskContainerRef(bucket.id, el)"
|
<draggable
|
||||||
@scroll="($event) => handleTaskContainerScroll(bucket.id, bucket.listId, $event.target)"
|
v-bind="dragOptions"
|
||||||
class="tasks"
|
:modelValue="bucket.tasks"
|
||||||
|
@update:modelValue="(tasks) => updateTasks(bucket.id, tasks)"
|
||||||
|
@start="() => dragstart(bucket)"
|
||||||
|
@end="updateTaskPosition"
|
||||||
|
:group="{name: 'tasks', put: shouldAcceptDrop(bucket) && !dragBucket}"
|
||||||
|
:disabled="!canWrite"
|
||||||
|
:data-bucket-index="bucketIndex"
|
||||||
|
tag="transition-group"
|
||||||
|
:item-key="(task) => `bucket${bucket.id}-task${task.id}`"
|
||||||
|
:component-data="getTaskDraggableTaskComponentData(bucket)"
|
||||||
>
|
>
|
||||||
<draggable
|
<template #footer>
|
||||||
v-bind="dragOptions"
|
<div class="bucket-footer" v-if="canWrite">
|
||||||
:modelValue="bucket.tasks"
|
<div class="field" v-if="showNewTaskInput[bucket.id]">
|
||||||
@update:modelValue="(tasks) => updateTasks(bucket.id, tasks)"
|
<div class="control" :class="{'is-loading': loading}">
|
||||||
@start="() => dragstart(bucket)"
|
<input
|
||||||
@end="updateTaskPosition"
|
class="input"
|
||||||
:group="{name: 'tasks', put: shouldAcceptDrop(bucket) && !dragBucket}"
|
:disabled="loading || undefined"
|
||||||
:disabled="!canWrite"
|
@focusout="toggleShowNewTaskInput(bucket.id)"
|
||||||
:data-bucket-index="bucketIndex"
|
@keyup.enter="addTaskToBucket(bucket.id)"
|
||||||
tag="transition-group"
|
@keyup.esc="toggleShowNewTaskInput(bucket.id)"
|
||||||
:item-key="(task) => `bucket${bucket.id}-task${task.id}`"
|
:placeholder="$t('list.kanban.addTaskPlaceholder')"
|
||||||
:component-data="taskDraggableTaskComponentData"
|
type="text"
|
||||||
>
|
v-focus.always
|
||||||
<template #item="{element: task}">
|
v-model="newTaskText"
|
||||||
<kanban-card :task="task"/>
|
/>
|
||||||
</template>
|
</div>
|
||||||
</draggable>
|
<p class="help is-danger" v-if="newTaskError[bucket.id] && newTaskText === ''">
|
||||||
</div>
|
{{ $t('list.create.addTitleRequired') }}
|
||||||
<div class="bucket-footer" v-if="canWrite">
|
</p>
|
||||||
<div class="field" v-if="showNewTaskInput[bucket.id]">
|
</div>
|
||||||
<div class="control" :class="{'is-loading': loading}">
|
<x-button
|
||||||
<input
|
@click="toggleShowNewTaskInput(bucket.id)"
|
||||||
class="input"
|
class="is-fullwidth has-text-centered"
|
||||||
:disabled="loading || null"
|
:shadow="false"
|
||||||
@focusout="toggleShowNewTaskInput(bucket.id)"
|
v-else
|
||||||
@keyup.enter="addTaskToBucket(bucket.id)"
|
icon="plus"
|
||||||
@keyup.esc="toggleShowNewTaskInput(bucket.id)"
|
variant="secondary"
|
||||||
:placeholder="$t('list.kanban.addTaskPlaceholder')"
|
>
|
||||||
type="text"
|
{{ bucket.tasks.length === 0 ? $t('list.kanban.addTask') : $t('list.kanban.addAnotherTask') }}
|
||||||
v-focus.always
|
</x-button>
|
||||||
v-model="newTaskText"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="help is-danger" v-if="newTaskError[bucket.id] && newTaskText === ''">
|
</template>
|
||||||
{{ $t('list.create.addTitleRequired') }}
|
|
||||||
</p>
|
<template #item="{element: task}">
|
||||||
</div>
|
<div class="task-item">
|
||||||
<x-button
|
<kanban-card class="kanban-card" :task="task"/>
|
||||||
@click="toggleShowNewTaskInput(bucket.id)"
|
</div>
|
||||||
class="is-transparent is-fullwidth has-text-centered"
|
</template>
|
||||||
:shadow="false"
|
</draggable>
|
||||||
v-if="!showNewTaskInput[bucket.id]"
|
|
||||||
icon="plus"
|
|
||||||
variant="secondary"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
bucket.tasks.length === 0 ? $t('list.kanban.addTask') : $t('list.kanban.addAnotherTask')
|
|
||||||
}}
|
|
||||||
</x-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
|
@ -197,10 +195,10 @@
|
||||||
v-model="newBucketTitle"
|
v-model="newBucketTitle"
|
||||||
/>
|
/>
|
||||||
<x-button
|
<x-button
|
||||||
|
v-else
|
||||||
@click="() => showNewBucketInput = true"
|
@click="() => showNewBucketInput = true"
|
||||||
:shadow="false"
|
:shadow="false"
|
||||||
class="is-transparent is-fullwidth has-text-centered"
|
class="is-transparent is-fullwidth has-text-centered"
|
||||||
v-else
|
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
icon="plus"
|
icon="plus"
|
||||||
>
|
>
|
||||||
|
@ -313,6 +311,20 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
getTaskDraggableTaskComponentData() {
|
||||||
|
return (bucket) => ({
|
||||||
|
ref: (el) => this.setTaskContainerRef(bucket.id, el),
|
||||||
|
onScroll: (event) => this.handleTaskContainerScroll(bucket.id, bucket.listId, event.target),
|
||||||
|
type: 'transition',
|
||||||
|
tag: 'div',
|
||||||
|
name: !this.drag ? 'move-card' : null,
|
||||||
|
class: [
|
||||||
|
'tasks',
|
||||||
|
{'dragging-disabled': !this.canWrite},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
isSavedFilter() {
|
isSavedFilter() {
|
||||||
return this.list.isSavedFilter && !this.list.isSavedFilter()
|
return this.list.isSavedFilter && !this.list.isSavedFilter()
|
||||||
},
|
},
|
||||||
|
@ -333,17 +345,6 @@ export default {
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
taskDraggableTaskComponentData() {
|
|
||||||
return {
|
|
||||||
type: 'transition',
|
|
||||||
tag: 'div',
|
|
||||||
name: !this.drag ? 'move-card' : null,
|
|
||||||
class: [
|
|
||||||
'dropper',
|
|
||||||
{'dragging-disabled': !this.canWrite},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
buckets() {
|
buckets() {
|
||||||
return this.$store.state.kanban.buckets
|
return this.$store.state.kanban.buckets
|
||||||
},
|
},
|
||||||
|
@ -406,10 +407,25 @@ export default {
|
||||||
// of the drop target works all the time.
|
// of the drop target works all the time.
|
||||||
const bucketIndex = parseInt(e.to.dataset.bucketIndex)
|
const bucketIndex = parseInt(e.to.dataset.bucketIndex)
|
||||||
|
|
||||||
|
|
||||||
const newBucket = this.buckets[bucketIndex]
|
const newBucket = this.buckets[bucketIndex]
|
||||||
const task = newBucket.tasks[e.newIndex]
|
|
||||||
const taskBefore = newBucket.tasks[e.newIndex - 1] ?? null
|
// HACK:
|
||||||
const taskAfter = newBucket.tasks[e.newIndex + 1] ?? null
|
// this is a hacky workaround for a known problem of vue.draggable.next when using the footer slot
|
||||||
|
// the problem: https://github.com/SortableJS/vue.draggable.next/issues/108
|
||||||
|
// This hack doesn't remove the problem that the ghost item is still displayed below the footer
|
||||||
|
// It just makes releasing the item possible.
|
||||||
|
|
||||||
|
// The newIndex of the event doesn't count in the elements of the footer slot.
|
||||||
|
// This is why in case the length of the tasks is identical with the newIndex
|
||||||
|
// we have to remove 1 to get the correct index.
|
||||||
|
const newTaskIndex = newBucket.tasks.length === e.newIndex
|
||||||
|
? e.newIndex - 1
|
||||||
|
: e.newIndex
|
||||||
|
|
||||||
|
const task = newBucket.tasks[newTaskIndex]
|
||||||
|
const taskBefore = newBucket.tasks[newTaskIndex - 1] ?? null
|
||||||
|
const taskAfter = newBucket.tasks[newTaskIndex + 1] ?? null
|
||||||
|
|
||||||
const newTask = cloneDeep(task) // cloning the task to avoid vuex store mutations
|
const newTask = cloneDeep(task) // cloning the task to avoid vuex store mutations
|
||||||
newTask.bucketId = newBucket.id,
|
newTask.bucketId = newBucket.id,
|
||||||
|
@ -525,7 +541,10 @@ export default {
|
||||||
|
|
||||||
const updatedData = {
|
const updatedData = {
|
||||||
id: bucket.id,
|
id: bucket.id,
|
||||||
position: calculateItemPosition(bucketBefore !== null ? bucketBefore.position : null, bucketAfter !== null ? bucketAfter.position : null),
|
position: calculateItemPosition(
|
||||||
|
bucketBefore !== null ? bucketBefore.position : null,
|
||||||
|
bucketAfter !== null ? bucketAfter.position : null,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('kanban/updateBucket', updatedData)
|
this.$store.dispatch('kanban/updateBucket', updatedData)
|
||||||
|
@ -546,9 +565,14 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
shouldAcceptDrop(bucket) {
|
shouldAcceptDrop(bucket) {
|
||||||
return bucket.id === this.sourceBucket || // When dragging from a bucket who has its limit reached, dragging should still be possible
|
return (
|
||||||
bucket.limit === 0 || // If there is no limit set, dragging & dropping should always work
|
// When dragging from a bucket who has its limit reached, dragging should still be possible
|
||||||
bucket.tasks.length < bucket.limit // Disallow dropping to buckets which have their limit reached
|
bucket.id === this.sourceBucket ||
|
||||||
|
// If there is no limit set, dragging & dropping should always work
|
||||||
|
bucket.limit === 0 ||
|
||||||
|
// Disallow dropping to buckets which have their limit reached
|
||||||
|
bucket.tasks.length < bucket.limit
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
dragstart(bucket) {
|
dragstart(bucket) {
|
||||||
|
@ -597,7 +621,6 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanban {
|
.kanban {
|
||||||
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
height: calc(#{$crazy-height-calculation});
|
height: calc(#{$crazy-height-calculation});
|
||||||
|
@ -610,21 +633,28 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
|
|
||||||
&-bucket-container {
|
&-bucket-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ghost {
|
.ghost {
|
||||||
background: transparent !important;
|
position: relative;
|
||||||
border: 3px dashed var(--grey-300) !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
top: 0.25rem;
|
||||||
|
right: 0.5rem;
|
||||||
|
bottom: 0.25rem;
|
||||||
|
left: 0.5rem;
|
||||||
|
border: 3px dashed var(--grey-300);
|
||||||
|
border-radius: $radius;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bucket {
|
.bucket {
|
||||||
background-color: var(--grey-100);
|
|
||||||
border-radius: $radius;
|
border-radius: $radius;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -632,24 +662,24 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
min-height: 20px;
|
min-height: 20px;
|
||||||
width: $bucket-width;
|
width: $bucket-width;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.tasks {
|
.tasks {
|
||||||
max-height: calc(#{$crazy-height-calculation-tasks});
|
overflow: hidden auto;
|
||||||
overflow: auto;
|
height: 100%;
|
||||||
|
|
||||||
@media screen and (max-width: $tablet) {
|
|
||||||
max-height: calc(#{$crazy-height-calculation-tasks} - #{$filter-container-height});
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropper {
|
|
||||||
&, > div {
|
|
||||||
min-height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.move-card-move {
|
.task-item {
|
||||||
transition: transform $transition-duration;
|
background-color: var(--grey-100);
|
||||||
|
padding: .25rem .5rem;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
padding-top: .5rem;
|
||||||
|
}
|
||||||
|
&:last-of-type {
|
||||||
|
padding-bottom: .5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-move {
|
.no-move {
|
||||||
|
@ -682,10 +712,11 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-collapsed {
|
&.is-collapsed {
|
||||||
transform: rotate(90deg) translateX(math.div($bucket-width, 2) - math.div($bucket-header-height, 2));
|
align-self: flex-start;
|
||||||
|
transform: rotate(90deg) translateY(-100%);
|
||||||
|
transform-origin: top left;
|
||||||
// Using negative margins instead of translateY here to make all other buckets fill the empty space
|
// Using negative margins instead of translateY here to make all other buckets fill the empty space
|
||||||
margin-left: (math.div($bucket-width, 2) - math.div($bucket-header-height, 2)) * -1;
|
margin-right: calc((#{$bucket-width} - #{$bucket-header-height} - #{$bucket-right-margin}) * -1);
|
||||||
margin-right: calc(#{(math.div($bucket-width, 2) - math.div($bucket-header-height, 2)) * -1} + #{$bucket-right-margin});
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.tasks, .bucket-footer {
|
.tasks, .bucket-footer {
|
||||||
|
@ -695,6 +726,8 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
}
|
}
|
||||||
|
|
||||||
.bucket-header {
|
.bucket-header {
|
||||||
|
background-color: var(--grey-100);
|
||||||
|
height: min-content;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -724,7 +757,13 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
}
|
}
|
||||||
|
|
||||||
.bucket-footer {
|
.bucket-footer {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
height: min-content;
|
||||||
padding: .5rem;
|
padding: .5rem;
|
||||||
|
background-color: var(--grey-100);
|
||||||
|
border-bottom-left-radius: $radius;
|
||||||
|
border-bottom-right-radius: $radius;
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -737,8 +776,13 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-dragging {
|
.task-dragging {
|
||||||
|
transform: rotateZ(3deg);
|
||||||
transition: transform 0.18s ease;
|
transition: transform 0.18s ease;
|
||||||
transform: rotateZ(3deg)
|
}
|
||||||
|
|
||||||
|
.move-card-move {
|
||||||
|
transform: rotateZ(3deg);
|
||||||
|
transition: transform $transition-duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
.move-card-leave-from,
|
.move-card-leave-from,
|
||||||
|
|
|
@ -37,12 +37,13 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
async archiveNamespace() {
|
async archiveNamespace() {
|
||||||
try {
|
try {
|
||||||
|
const isArchived = !this.namespace.isArchived
|
||||||
const namespace = await this.namespaceService.update({
|
const namespace = await this.namespaceService.update({
|
||||||
...this.namespace,
|
...this.namespace,
|
||||||
isArchived: !this.namespace.isArchived,
|
isArchived,
|
||||||
})
|
})
|
||||||
this.$store.commit('namespaces/setNamespaceById', namespace)
|
this.$store.commit('namespaces/setNamespaceById', namespace)
|
||||||
this.$message.success({message: this.$t('namespace.archive.success')})
|
this.$message.success({message: this.$t(isArchived ? 'namespace.archive.success' : 'namespace.archive.unarchiveSuccess')})
|
||||||
} finally {
|
} finally {
|
||||||
this.$router.back()
|
this.$router.back()
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
</transition>
|
</transition>
|
||||||
<transition name="flash-background" appear>
|
<transition name="flash-background" appear>
|
||||||
<div class="column" v-if="activeFields.percentDone">
|
<div class="column" v-if="activeFields.percentDone">
|
||||||
<!-- Percent Done -->
|
<!-- Progress -->
|
||||||
<div class="detail-title">
|
<div class="detail-title">
|
||||||
<icon icon="percent"/>
|
<icon icon="percent"/>
|
||||||
{{ $t('task.attributes.percentDone') }}
|
{{ $t('task.attributes.percentDone') }}
|
||||||
|
@ -246,11 +246,11 @@
|
||||||
<!-- Comments -->
|
<!-- Comments -->
|
||||||
<comments :can-write="canWrite" :task-id="taskId"/>
|
<comments :can-write="canWrite" :task-id="taskId"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-one-third action-buttons">
|
<div class="column is-one-third action-buttons" v-if="canWrite || shouldShowClosePopup">
|
||||||
<a @click="$router.back()" class="is-fullwidth is-block has-text-centered mb-4" v-if="shouldShowClosePopup">
|
<BaseButton @click="$router.back()" class="is-fullwidth is-block has-text-centered mb-4 has-text-primary" v-if="shouldShowClosePopup">
|
||||||
<icon icon="arrow-left"/>
|
<icon icon="arrow-left"/>
|
||||||
{{ $t('task.detail.closePopup') }}
|
{{ $t('task.detail.closePopup') }}
|
||||||
</a>
|
</BaseButton>
|
||||||
<template v-if="canWrite">
|
<template v-if="canWrite">
|
||||||
<x-button
|
<x-button
|
||||||
:class="{'is-success': !task.done}"
|
:class="{'is-success': !task.done}"
|
||||||
|
@ -386,33 +386,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Created / Updated [by] -->
|
<!-- Created / Updated [by] -->
|
||||||
<p class="created">
|
<created-updated :task="task"/>
|
||||||
<time :datetime="formatISO(task.created)" v-tooltip="formatDate(task.created)">
|
|
||||||
<i18n-t keypath="task.detail.created">
|
|
||||||
<span>{{ formatDateSince(task.created) }}</span>
|
|
||||||
{{ task.createdBy.getDisplayName() }}
|
|
||||||
</i18n-t>
|
|
||||||
</time>
|
|
||||||
<template v-if="+new Date(task.created) !== +new Date(task.updated)">
|
|
||||||
<br/>
|
|
||||||
<!-- Computed properties to show the actual date every time it gets updated -->
|
|
||||||
<time :datetime="formatISO(task.updated)" v-tooltip="updatedFormatted">
|
|
||||||
<i18n-t keypath="task.detail.updated">
|
|
||||||
<span>{{ updatedSince }}</span>
|
|
||||||
</i18n-t>
|
|
||||||
</time>
|
|
||||||
</template>
|
|
||||||
<template v-if="task.done">
|
|
||||||
<br/>
|
|
||||||
<time :datetime="formatISO(task.doneAt)" v-tooltip="doneFormatted">
|
|
||||||
<i18n-t keypath="task.detail.doneAt">
|
|
||||||
<span>{{ doneSince }}</span>
|
|
||||||
</i18n-t>
|
|
||||||
</time>
|
|
||||||
</template>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Created / Updated [by] -->
|
||||||
|
<created-updated :task="task" v-if="!canWrite && !shouldShowClosePopup"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="modal">
|
<transition name="modal">
|
||||||
|
@ -453,18 +431,22 @@ import description from '@/components/tasks/partials/description.vue'
|
||||||
import ColorPicker from '../../components/input/colorPicker'
|
import ColorPicker from '../../components/input/colorPicker'
|
||||||
import heading from '@/components/tasks/partials/heading.vue'
|
import heading from '@/components/tasks/partials/heading.vue'
|
||||||
import Datepicker from '@/components/input/datepicker.vue'
|
import Datepicker from '@/components/input/datepicker.vue'
|
||||||
|
import BaseButton from '@/components/base/BaseButton'
|
||||||
import {playPop} from '@/helpers/playPop'
|
import {playPop} from '@/helpers/playPop'
|
||||||
import TaskSubscription from '@/components/misc/subscription.vue'
|
import TaskSubscription from '@/components/misc/subscription.vue'
|
||||||
import {CURRENT_LIST} from '@/store/mutation-types'
|
import {CURRENT_LIST} from '@/store/mutation-types'
|
||||||
|
|
||||||
import {uploadFile} from '@/helpers/attachments'
|
import {uploadFile} from '@/helpers/attachments'
|
||||||
import ChecklistSummary from '../../components/tasks/partials/checklist-summary'
|
import ChecklistSummary from '../../components/tasks/partials/checklist-summary'
|
||||||
|
import CreatedUpdated from '@/components/tasks/partials/createdUpdated'
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'TaskDetailView',
|
name: 'TaskDetailView',
|
||||||
compatConfig: { ATTR_FALSE_VALUE: false },
|
compatConfig: { ATTR_FALSE_VALUE: false },
|
||||||
components: {
|
components: {
|
||||||
|
BaseButton,
|
||||||
|
CreatedUpdated,
|
||||||
ChecklistSummary,
|
ChecklistSummary,
|
||||||
TaskSubscription,
|
TaskSubscription,
|
||||||
Datepicker,
|
Datepicker,
|
||||||
|
@ -560,18 +542,6 @@ export default {
|
||||||
canWrite() {
|
canWrite() {
|
||||||
return typeof this.task !== 'undefined' && typeof this.task.maxRight !== 'undefined' && this.task.maxRight > rights.READ
|
return typeof this.task !== 'undefined' && typeof this.task.maxRight !== 'undefined' && this.task.maxRight > rights.READ
|
||||||
},
|
},
|
||||||
updatedSince() {
|
|
||||||
return this.formatDateSince(this.task.updated)
|
|
||||||
},
|
|
||||||
updatedFormatted() {
|
|
||||||
return this.formatDate(this.task.updated)
|
|
||||||
},
|
|
||||||
doneSince() {
|
|
||||||
return this.formatDateSince(this.task.doneAt)
|
|
||||||
},
|
|
||||||
doneFormatted() {
|
|
||||||
return this.formatDate(this.task.doneAt)
|
|
||||||
},
|
|
||||||
hasAttachments() {
|
hasAttachments() {
|
||||||
return this.$store.state.attachments.attachments.length > 0
|
return this.$store.state.attachments.attachments.length > 0
|
||||||
},
|
},
|
||||||
|
@ -723,7 +693,7 @@ $flash-background-duration: 750ms;
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
color: var(--grey-500);
|
color: var(--grey-500);
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--grey-800);
|
color: var(--grey-800);
|
||||||
|
@ -751,15 +721,15 @@ $flash-background-duration: 750ms;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title.input {
|
.title.input {
|
||||||
// 1.8rem is the font-size, 1.125 is the line-height, .3rem padding everywhere, 1px border around the whole thing.
|
// 1.8rem is the font-size, 1.125 is the line-height, .3rem padding everywhere, 1px border around the whole thing.
|
||||||
min-height: calc(1.8rem * 1.125 + .6rem + 2px);
|
min-height: calc(1.8rem * 1.125 + .6rem + 2px);
|
||||||
|
|
||||||
@media screen and (max-width: $tablet) {
|
@media screen and (max-width: $tablet) {
|
||||||
margin: 0 -.3rem .5rem -.3rem; // the title has 0.3rem padding - this make the text inside of it align with the rest
|
margin: 0 -.3rem .5rem -.3rem; // the title has 0.3rem padding - this make the text inside of it align with the rest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.title.task-id {
|
.title.task-id {
|
||||||
|
@ -823,7 +793,7 @@ $flash-background-duration: 750ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.labels-list,
|
&.labels-list,
|
||||||
.assignees {
|
.assignees {
|
||||||
:deep(.multiselect) {
|
:deep(.multiselect) {
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
&:not(:focus-within):not(:hover) {
|
&:not(:focus-within):not(:hover) {
|
||||||
|
@ -908,7 +878,7 @@ $flash-background-duration: 750ms;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
|
|
||||||
@media screen and (max-width: $desktop) {
|
@media screen and (max-width: $desktop) {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-view * {
|
.task-view * {
|
||||||
|
@ -935,7 +905,7 @@ $flash-background-duration: 750ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flash-background-enter-from,
|
.flash-background-enter-from,
|
||||||
.flash-background-enter-active {
|
.flash-background-enter-active {
|
||||||
animation: flash-background $flash-background-duration ease 1;
|
animation: flash-background $flash-background-duration ease 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,12 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">
|
||||||
|
<input type="checkbox" v-model="rememberMe" class="mr-1"/>
|
||||||
|
{{ $t('user.auth.remember') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-button
|
<x-button
|
||||||
@click="submit"
|
@click="submit"
|
||||||
|
@ -118,6 +124,7 @@ export default {
|
||||||
usernameValid: true,
|
usernameValid: true,
|
||||||
password: '',
|
password: '',
|
||||||
validatePasswordInitially: false,
|
validatePasswordInitially: false,
|
||||||
|
rememberMe: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
|
@ -197,6 +204,7 @@ export default {
|
||||||
const credentials = {
|
const credentials = {
|
||||||
username: this.$refs.username.value,
|
username: this.$refs.username.value,
|
||||||
password: this.password,
|
password: this.password,
|
||||||
|
longToken: this.rememberMe,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (credentials.username === '' || credentials.password === '') {
|
if (credentials.username === '' || credentials.password === '') {
|
||||||
|
|
|
@ -92,9 +92,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="is-flex is-align-items-center">
|
<label class="is-flex is-align-items-center">
|
||||||
<span>
|
<span>
|
||||||
{{ $t('user.settings.appearance.title') }}
|
{{ $t('user.settings.appearance.title') }}
|
||||||
</span>
|
</span>
|
||||||
<div class="select ml-2">
|
<div class="select ml-2">
|
||||||
<select v-model="activeColorSchemeSetting">
|
<select v-model="activeColorSchemeSetting">
|
||||||
<!-- TODO: use the Vikunja logo in color scheme as option buttons -->
|
<!-- TODO: use the Vikunja logo in color scheme as option buttons -->
|
||||||
|
@ -105,6 +105,20 @@
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="is-flex is-align-items-center">
|
||||||
|
<span>
|
||||||
|
{{ $t('user.settings.general.timezone') }}
|
||||||
|
</span>
|
||||||
|
<div class="select ml-2">
|
||||||
|
<select v-model="settings.timezone">
|
||||||
|
<option v-for="tz in availableTimezones" :key="tz">
|
||||||
|
{{ tz }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-button
|
<x-button
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
@ -118,7 +132,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {computed, watch} from 'vue'
|
import {computed, watch, ref} from 'vue'
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
|
|
||||||
import {playSoundWhenDoneKey, playPop} from '@/helpers/playPop'
|
import {playSoundWhenDoneKey, playPop} from '@/helpers/playPop'
|
||||||
|
@ -129,6 +143,7 @@ import ListSearch from '@/components/tasks/partials/listSearch'
|
||||||
import {createRandomID} from '@/helpers/randomId'
|
import {createRandomID} from '@/helpers/randomId'
|
||||||
import {useColorScheme} from '@/composables/useColorScheme'
|
import {useColorScheme} from '@/composables/useColorScheme'
|
||||||
import {success} from '@/message'
|
import {success} from '@/message'
|
||||||
|
import {AuthenticatedHTTPFactory} from '@/http-common'
|
||||||
|
|
||||||
const DEFAULT_LIST_ID = 0
|
const DEFAULT_LIST_ID = 0
|
||||||
|
|
||||||
|
@ -155,6 +170,18 @@ function useColorSchemeSetting() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useAvailableTimezones() {
|
||||||
|
const availableTimezones = ref([])
|
||||||
|
|
||||||
|
const HTTP = AuthenticatedHTTPFactory()
|
||||||
|
HTTP.get('user/timezones')
|
||||||
|
.then(r => {
|
||||||
|
availableTimezones.value = r.data.sort()
|
||||||
|
})
|
||||||
|
|
||||||
|
return availableTimezones
|
||||||
|
}
|
||||||
|
|
||||||
function getPlaySoundWhenDoneSetting() {
|
function getPlaySoundWhenDoneSetting() {
|
||||||
return localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
|
return localStorage.getItem(playSoundWhenDoneKey) === 'true' || localStorage.getItem(playSoundWhenDoneKey) === null
|
||||||
}
|
}
|
||||||
|
@ -193,6 +220,7 @@ export default {
|
||||||
setup() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
...useColorSchemeSetting(),
|
...useColorSchemeSetting(),
|
||||||
|
availableTimezones: useAvailableTimezones(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"strictNullChecks": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"types": [
|
"types": [
|
||||||
"vite/client"
|
"vite/client"
|
||||||
|
|
|
@ -132,7 +132,7 @@ export default defineConfig({
|
||||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
|
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 5000,
|
port: 4173,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|
Loading…
Reference in a new issue