Compare commits

..

11 Commits

Author SHA1 Message Date
e3e4b8a563
fix: follow the happy path 2023-04-11 18:40:22 +02:00
367459edd2
feat: change the link share hash name 2023-04-04 11:35:45 +02:00
2d66393874
feat: check link share auth from store instead 2023-04-01 17:56:30 +02:00
007282b758
chore: follow the happy path 2023-04-01 17:16:51 +02:00
56396643dd
chore: move const 2023-04-01 15:17:09 +02:00
e8cb7c1083
chore: reduce nesting 2023-04-01 14:19:28 +02:00
a7fdec956f
fix: return redirect 2023-04-01 14:18:38 +02:00
90d54bdae8
feat: rename link share hash prefix 2023-04-01 14:17:05 +02:00
c21587d779
chore: import const instead of redeclaring it 2023-04-01 14:15:54 +02:00
6bf378ec90
chore: rename getRedirectRoute 2023-04-01 14:12:47 +02:00
9c81a57791
feat: persist link share auth rule in url hash
This allows sharing links to a task directly. We're using hashes instead
of query parameters because hash values are usually not logged in access
logs.

With this change, when a user uses a link share, the link share hash
will be appended to all urls while browsing. When a link share hash is
encountered in the current url and the user is not authenticated, they
will be redirected to the link share auth page, get authenticated and
then get redirected to whatever url they were previously on.
2023-04-01 12:15:02 +02:00
60 changed files with 7160 additions and 1565 deletions

View File

@ -42,12 +42,11 @@ steps:
# - .cache
- name: dependencies
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
CYPRESS_CACHE_FOLDER: .cache/cypress
PUPPETEER_SKIP_DOWNLOAD: true
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm install --fetch-timeout 100000
@ -55,7 +54,7 @@ steps:
# - restore-cache
- name: lint
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -66,7 +65,7 @@ steps:
- dependencies
- name: build-prod
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -77,7 +76,7 @@ steps:
- dependencies
- name: test-unit
image: node:20-alpine
image: node:18-alpine
pull: always
commands:
- corepack enable && pnpm config set store-dir .cache/pnpm
@ -87,7 +86,7 @@ steps:
- name: typecheck
failure: ignore
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -137,9 +136,8 @@ steps:
# - dependencies
- name: deploy-preview
image: williamjackson/netlify-cli
image: node:18-alpine
pull: always
user: root # The rest runs as root and thus the permissions wouldn't work
environment:
NETLIFY_AUTH_TOKEN:
from_secret: netlify_auth_token
@ -202,7 +200,7 @@ steps:
# - .cache
- name: build
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -279,7 +277,7 @@ steps:
# - .cache
- name: build
image: node:20-alpine
image: node:18-alpine
pull: always
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
@ -524,6 +522,6 @@ steps:
from_secret: crowdin_key
---
kind: signature
hmac: 511c2a090e9efd4c942980d971204adb6321540bb01c92409dd9bf8463b7f6f4
hmac: 303afeb09b75a57ba88720b45dc06c8bf2c7320e19d738d8299f325438246f75
...

2
.nvmrc
View File

@ -1 +1 @@
18.16.0
18.15.0

View File

@ -8,7 +8,6 @@
"lokalise.i18n-ally",
"mgmcdermott.vscode-language-babel",
"mikestead.dotenv",
"Syler.sass-indented",
"zixuanchen.vitest-explorer"
"Syler.sass-indented"
]
}

View File

@ -3,7 +3,7 @@
# │─││ │││ │ │
# ┘─┘┘─┘┘┘─┘┘─┘
FROM --platform=$BUILDPLATFORM node:20-alpine AS builder
FROM --platform=$BUILDPLATFORM node:18-alpine AS builder
WORKDIR /build
@ -13,7 +13,6 @@ ENV PNPM_CACHE_FOLDER .cache/pnpm/
COPY package.json ./
COPY pnpm-lock.yaml ./
COPY patches /build/patches
RUN if [ "$USE_RELEASE" != true ]; then \
# https://pnpm.io/installation#using-corepack

View File

@ -1,5 +1,5 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["./**/*", "../support/**/*", "../factories/**/*"],
"compilerOptions": {
"baseUrl": ".",

0
docker/injector.sh Executable file → Normal file
View File

0
docker/ipv6-disable.sh Executable file → Normal file
View File

View File

@ -4,6 +4,7 @@
pid /tmp/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
multi_accept on;

View File

@ -13,7 +13,7 @@
},
"homepage": "https://vikunja.io/",
"funding": "https://opencollective.com/vikunja",
"packageManager": "pnpm@8.5.0",
"packageManager": "pnpm@7.30.5",
"keywords": [
"todo",
"productivity",
@ -53,37 +53,37 @@
"@infectoone/vue-ganttastic": "2.1.4",
"@intlify/unplugin-vue-i18n": "0.10.0",
"@kyvg/vue3-notification": "2.9.0",
"@sentry/tracing": "7.51.2",
"@sentry/vue": "7.51.2",
"@vueuse/core": "10.1.2",
"axios": "1.4.0",
"@sentry/tracing": "7.46.0",
"@sentry/vue": "7.46.0",
"@vueuse/core": "9.13.0",
"axios": "1.3.4",
"blurhash": "2.0.5",
"bulma-css-variables": "0.9.33",
"camel-case": "4.1.2",
"codemirror": "5.65.13",
"date-fns": "2.30.0",
"codemirror": "5.65.12",
"date-fns": "2.29.3",
"dayjs": "1.11.7",
"dompurify": "3.0.3",
"dompurify": "3.0.1",
"easymde": "2.18.0",
"fast-deep-equal": "3.1.3",
"flatpickr": "4.6.13",
"flexsearch": "0.7.31",
"floating-vue": "2.0.0-beta.20",
"highlight.js": "11.8.0",
"highlight.js": "11.7.0",
"is-touch-device": "1.0.1",
"klona": "2.0.6",
"lodash.debounce": "4.0.8",
"marked": "5.0.2",
"pinia": "2.0.36",
"marked": "4.3.0",
"pinia": "2.0.33",
"register-service-worker": "1.7.2",
"snake-case": "3.0.4",
"sortablejs": "1.15.0",
"ufo": "1.1.2",
"ufo": "1.1.1",
"vue": "3.2.47",
"vue-advanced-cropper": "2.8.8",
"vue-flatpickr-component": "11.0.3",
"vue-i18n": "9.2.2",
"vue-router": "4.2.0",
"vue-router": "4.1.6",
"workbox-precaching": "6.5.4",
"zhyswan-vuedraggable": "4.1.3"
},
@ -91,54 +91,54 @@
"@4tw/cypress-drag-drop": "2.2.3",
"@cypress/vite-dev-server": "5.0.5",
"@cypress/vue": "5.0.5",
"@faker-js/faker": "8.0.0",
"@histoire/plugin-screenshot": "0.16.1",
"@histoire/plugin-vue": "0.16.1",
"@faker-js/faker": "7.6.0",
"@histoire/plugin-screenshot": "0.15.9",
"@histoire/plugin-vue": "0.15.8",
"@rushstack/eslint-patch": "1.2.0",
"@tsconfig/node18": "2.0.1",
"@types/codemirror": "5.60.7",
"@types/dompurify": "3.0.2",
"@types/dompurify": "3.0.0",
"@types/flexsearch": "0.7.3",
"@types/is-touch-device": "1.0.0",
"@types/lodash.debounce": "4.0.7",
"@types/marked": "4.3.0",
"@types/node": "18.16.8",
"@types/marked": "4.0.8",
"@types/node": "18.15.11",
"@types/postcss-preset-env": "7.7.0",
"@types/sortablejs": "1.15.1",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"@vitejs/plugin-legacy": "4.0.3",
"@vitejs/plugin-vue": "4.2.3",
"@vue/eslint-config-typescript": "11.0.3",
"@typescript-eslint/eslint-plugin": "5.57.0",
"@typescript-eslint/parser": "5.57.0",
"@vitejs/plugin-legacy": "4.0.2",
"@vitejs/plugin-vue": "4.1.0",
"@vue/eslint-config-typescript": "11.0.2",
"@vue/test-utils": "2.3.2",
"@vue/tsconfig": "0.4.0",
"@vue/tsconfig": "0.1.3",
"autoprefixer": "10.4.14",
"browserslist": "4.21.5",
"caniuse-lite": "1.0.30001486",
"caniuse-lite": "1.0.30001470",
"css-has-pseudo": "5.0.2",
"csstype": "3.1.2",
"cypress": "12.12.0",
"esbuild": "0.17.18",
"eslint": "8.40.0",
"eslint-plugin-vue": "9.12.0",
"happy-dom": "9.10.9",
"histoire": "0.16.1",
"postcss": "8.4.23",
"csstype": "3.1.1",
"cypress": "12.9.0",
"esbuild": "0.17.14",
"eslint": "8.37.0",
"eslint-plugin-vue": "9.10.0",
"happy-dom": "8.9.0",
"histoire": "0.15.9",
"netlify-cli": "13.2.1",
"postcss": "8.4.21",
"postcss-easing-gradients": "3.0.1",
"postcss-easings": "3.0.1",
"postcss-focus-within": "7.0.2",
"postcss-preset-env": "8.3.2",
"rollup": "3.21.6",
"postcss-preset-env": "8.3.0",
"rollup": "3.20.2",
"rollup-plugin-visualizer": "5.9.0",
"sass": "1.62.1",
"sass": "1.60.0",
"start-server-and-test": "2.0.0",
"typescript": "5.0.4",
"vite": "4.3.5",
"typescript": "5.0.3",
"vite": "4.2.1",
"vite-plugin-inject-preload": "1.3.1",
"vite-plugin-pwa": "0.14.7",
"vite-svg-loader": "4.0.0",
"vitest": "0.31.0",
"vue-tsc": "1.6.4",
"vitest": "0.29.8",
"vue-tsc": "1.2.0",
"wait-on": "7.0.1",
"workbox-cli": "6.5.4"
},

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@
],
"packageRules": [
{
"matchPackageNames": ["happy-dom"],
"matchPackageNames": ["netlify-cli", "happy-dom"],
"extends": ["schedule:weekly"]
},
{

View File

@ -33,9 +33,9 @@ const promiseExec = cmd => {
}
(async function () {
let stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify link --id ${siteId}`)
let stdout = await promiseExec(`./node_modules/.bin/netlify link --id ${siteId}`)
console.log(stdout)
stdout = await promiseExec(`/home/node/docker-netlify-cli/node_modules/.bin/netlify deploy --alias ${alias}`)
stdout = await promiseExec(`./node_modules/.bin/netlify deploy --alias ${alias}`)
console.log(stdout)
const data = await fetch(prIssueCommentsUrl).then(response => response.json())

View File

@ -1 +1 @@
4a7c1293c7b12e9ab476cdf35251a407c6a1cd005d22c06df994222cccfb25cde5f47d15866a098c9d739778fee4dc19 ./scripts/deploy-preview-netlify.mjs
57af69409e66bc87f4f2fc5822dd8d3c2eb47c601f81af1ac4a56f3e2d80837b1a2de06f4ff57695ec379b7c15b881e3 ./scripts/deploy-preview-netlify.mjs

View File

@ -32,7 +32,7 @@ import {computed, ref} from 'vue'
import {getInheritedBackgroundColor} from '@/helpers/getInheritedBackgroundColor'
const props = defineProps({
/** Whether the Expandable is open or not */
/** Wheather the Expandable is open or not */
open: {
type: Boolean,
default: false,

View File

@ -1,11 +0,0 @@
<script setup lang="ts">
import datemathHelp from './datemathHelp.vue'
</script>
<template>
<Story>
<Variant title="Default">
<datemathHelp />
</Variant>
</Story>
</template>

View File

@ -1,8 +1,7 @@
<template>
<card
class="has-no-shadow how-it-works-modal"
:title="$t('input.datemathHelp.title')"
>
:title="$t('input.datemathHelp.title')">
<p>
{{ $t('input.datemathHelp.intro') }}
</p>
@ -28,11 +27,11 @@
</p>
<p>{{ $t('misc.forExample') }}</p>
<ul>
<li><code>+1d</code> {{ $t('input.datemathHelp.add1Day') }}</li>
<li><code>-1d</code> {{ $t('input.datemathHelp.minus1Day') }}</li>
<li><code>/d</code> {{ $t('input.datemathHelp.roundDay') }}</li>
<li><code>+1d</code>{{ $t('input.datemathHelp.add1Day') }}</li>
<li><code>-1d</code>{{ $t('input.datemathHelp.minus1Day') }}</li>
<li><code>/d</code>{{ $t('input.datemathHelp.roundDay') }}</li>
</ul>
<h3>{{ $t('input.datemathHelp.supportedUnits') }}</h3>
<p>{{ $t('input.datemathHelp.supportedUnits') }}</p>
<table class="table">
<tbody>
<tr>
@ -70,7 +69,7 @@
</tbody>
</table>
<h3>{{ $t('input.datemathHelp.someExamples') }}</h3>
<p>{{ $t('input.datemathHelp.someExamples') }}</p>
<table class="table">
<tbody>
<tr>
@ -101,7 +100,7 @@
<td><code>{{ exampleDate }}||+1M/d</code></td>
<td>
<i18n-t keypath="input.datemathHelp.examples.datePlusMonth" scope="global">
<strong>{{ exampleDate }}</strong>
<code>{{ exampleDate }}</code>
</i18n-t>
</td>
</tr>
@ -111,15 +110,13 @@
</template>
<script lang="ts" setup>
import {formatDateShort} from '@/helpers/time/formatDate'
import {formatDate} from '@/helpers/time/formatDate'
import BaseButton from '@/components/base/BaseButton.vue'
const exampleDate = formatDateShort(new Date())
const exampleDate = formatDate(new Date(), 'yyyy-MM-dd')
</script>
<style scoped lang="scss">
// FIXME: Remove style overwrites
.how-it-works-modal {
font-size: 1rem;
}

View File

@ -140,18 +140,6 @@ export const KEYBOARD_SHORTCUTS : ShortcutGroup[] = [
title: 'keyboardShortcuts.task.description',
keys: ['e'],
},
{
title: 'keyboardShortcuts.task.priority',
keys: ['p'],
},
{
title: 'keyboardShortcuts.task.delete',
keys: ['shift', 'delete'],
},
{
title: 'keyboardShortcuts.task.favorite',
keys: ['s'],
},
],
},
]
]

View File

@ -56,11 +56,13 @@ import {useOnline} from '@/composables/useOnline'
import {getAuthForRoute} from '@/router'
import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth'
const router = useRouter()
const route = useRoute()
const baseStore = useBaseStore()
const authStore = useAuthStore()
const ready = computed(() => baseStore.ready)
const online = useOnline()
@ -72,7 +74,7 @@ async function load() {
try {
await baseStore.loadApp()
baseStore.setReady(true)
const redirectTo = await getAuthForRoute(route)
const redirectTo = await getAuthForRoute(route, authStore)
if (typeof redirectTo !== 'undefined') {
await router.push(redirectTo)
}

View File

@ -49,11 +49,9 @@ const displayName = computed(() => getDisplayName(props.user))
<style lang="scss" scoped>
.user {
margin: .5rem;
display: flex;
justify-items: center;
&.is-inline {
display: inline-flex;
display: inline;
}
}

View File

@ -145,13 +145,12 @@ function to(n, index) {
.trigger-button {
width: 100%;
position: relative;
}
.unread-indicator {
position: absolute;
top: 1rem;
right: .5rem;
top: .75rem;
right: 1.15rem;
width: .75rem;
height: .75rem;

View File

@ -442,6 +442,5 @@ async function toggleTaskDone(task: ITask) {
.task-done-checkbox {
padding: 0;
height: 18px; // The exact height of the checkbox in the container
margin-right: .75rem;
}
</style>

View File

@ -5,22 +5,31 @@ export function useRedirectToLastVisited() {
const router = useRouter()
function redirectIfSaved() {
function getLastVisitedRoute() {
const last = getLastVisited()
if (last !== null) {
router.push({
name: last.name,
params: last.params,
query: last.query,
})
clearLastVisited()
return
if (last === null) {
return null
}
router.push({name: 'home'})
clearLastVisited()
return {
name: last.name,
params: last.params,
query: last.query,
}
}
function redirectIfSaved() {
const lastRoute = getLastVisitedRoute()
if (!lastRoute) {
return router.push({name: 'home'})
}
return router.push(lastRoute)
}
return {
redirectIfSaved,
getLastVisitedRoute,
}
}

View File

@ -1,7 +1,7 @@
import {computed} from 'vue'
import type {Ref} from 'vue'
import { computed } from 'vue'
import type { Ref } from 'vue'
import {useTitle as useTitleVueUse, toRef} from '@vueuse/core'
import {useTitle as useTitleVueUse, resolveRef} from '@vueuse/core'
type UseTitleParameters = Parameters<typeof useTitleVueUse>
@ -9,12 +9,12 @@ export function useTitle(...args: UseTitleParameters) {
const [newTitle, ...restArgs] = args
const pageTitle = toRef(newTitle) as Ref<string>
const pageTitle = resolveRef(newTitle) as Ref<string>
const completeTitle = computed(() =>
const completeTitle = computed(() =>
(typeof pageTitle.value === 'undefined' || pageTitle.value === '')
? 'Vikunja'
: `${pageTitle.value} | Vikunja`,
? 'Vikunja'
: `${pageTitle.value} | Vikunja`,
)
return useTitleVueUse(completeTitle, ...restArgs)

View File

@ -0,0 +1 @@
export const LINK_SHARE_HASH_PREFIX = '#share-auth-token='

View File

@ -129,7 +129,7 @@ const addTimeToDate = (text: string, date: Date, previousMatch: string | null):
}
export const getDateFromText = (text: string, now: Date = new Date()) => {
const fullDateRegex = /(^| )([0-9][0-9]?\/[0-9][0-9]?\/[0-9][0-9]([0-9][0-9])?|[0-9][0-9][0-9][0-9]\/[0-9][0-9]?\/[0-9][0-9]?|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?)/ig
const fullDateRegex = / ([0-9][0-9]?\/[0-9][0-9]?\/[0-9][0-9]([0-9][0-9])?|[0-9][0-9][0-9][0-9]\/[0-9][0-9]?\/[0-9][0-9]?|[0-9][0-9][0-9][0-9]-[0-9][0-9]?-[0-9][0-9]?)/ig
// 1. Try parsing the text as a "usual" date, like 2021-06-24 or 06/24/2021
let results: string[] | null = fullDateRegex.exec(text)
@ -138,7 +138,7 @@ export const getDateFromText = (text: string, now: Date = new Date()) => {
let containsYear = true
if (result === null) {
// 2. Try parsing the date as something like "jan 21" or "21 jan"
const monthRegex = new RegExp(`(^| )(${monthsRegexGroup} [0-9][0-9]?|[0-9][0-9]? ${monthsRegexGroup})`, 'ig')
const monthRegex = new RegExp(` (${monthsRegexGroup} [0-9][0-9]?|[0-9][0-9]? ${monthsRegexGroup})`, 'ig')
results = monthRegex.exec(text)
result = results === null ? null : `${results[0]} ${now.getFullYear()}`.trim()
foundText = results === null ? '' : results[0].trim()
@ -146,7 +146,7 @@ export const getDateFromText = (text: string, now: Date = new Date()) => {
if (result === null) {
// 3. Try parsing the date as "27/01" or "01/27"
const monthNumericRegex = /(^| )([0-9][0-9]?\/[0-9][0-9]?)/ig
const monthNumericRegex = / ([0-9][0-9]?\/[0-9][0-9]?)/ig
results = monthNumericRegex.exec(text)
// Put the year before or after the date, depending on what works
@ -299,7 +299,7 @@ const getDateFromWeekday = (text: string): dateFoundResult => {
}
const getDayFromText = (text: string) => {
const matcher = /(^| )(([1-2][0-9])|(3[01])|(0?[1-9]))(st|nd|rd|th|\.)($| )/ig
const matcher = /($| )(([1-2][0-9])|(3[01])|(0?[1-9]))(st|nd|rd|th|\.)($| )/ig
const results = matcher.exec(text)
if (results === null) {
return {

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Kód",
"quote": "Citace",
"unorderedList": "Seznam s odrážkami",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Čistý blok",
"link": "Odkaz",
"image": "Obrázek",
@ -566,14 +566,14 @@
"canuse": "Můžete použít vzorec pro filtrování podle relativních datumů.",
"learnhow": "Podívejte se, jak to funguje",
"title": "Datumový vzorec",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Datumový vzorec umožňuje určit relativní data, která jsou při použití filtru vyřešena za běhu Vikunjou.",
"expression": "Každý datumový matematický výraz začíná datem ukotvení, které může být buď {0}, nebo datový řetězec končící {1}. Po tomto ukotvení může volitelně následovat jeden nebo více matematických výrazů.",
"similar": "Tyto výrazy jsou podobné výrazům poskytnutým {0} a {1}.",
"add1Day": "Přidat jeden den",
"minus1Day": "Odečíst jeden den",
"roundDay": "Zaokrouhlit dolů na nejbližší den",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Podporované časové jednotky jsou:",
"someExamples": "Některé příklady časových výrazů:",
"units": {
"seconds": "Sekundy",
"minutes": "Minuty",
@ -894,10 +894,7 @@
"color": "Změnit barvu tohoto úkolu",
"move": "Move this task to another project",
"reminder": "Spravovat připomenutí této úlohy",
"description": "Přepnout úpravy popisu úkolu",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Přepnout úpravy popisu úkolu"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Verze frontendu: {version}",
"apiVersion": "Verze API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Kode",
"quote": "Citat",
"unorderedList": "Usorteret liste",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Ryd Blok",
"link": "Link",
"image": "Billede",
@ -566,14 +566,14 @@
"canuse": "Du kan bruge datomatematik til at filtrere for relative datoer.",
"learnhow": "Se hvordan det virker",
"title": "Datomatematik",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Dato Matematik giver dig mulighed for at angive relative datoer, som er løst løbende af Vikunja, når du anvender filteret.",
"expression": "Hver Datomatematik udtryk starter med en ankerdato, som enten kan være {0} eller en datostreng, der slutter med {1}. Denneanker dato kan eventuelt efterfølges af en eller flere matematik udtryk.",
"similar": "Disse udtryk ligner dem fra {0} og {1}.",
"add1Day": "Læg en dag til",
"minus1Day": "Træk en dag fra",
"roundDay": "Rund ned til nærmeste dag",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Understøttede tidsenheder er:",
"someExamples": "Eksempler på tidsudtryk:",
"units": {
"seconds": "Sekunder",
"minutes": "Minutter",
@ -894,10 +894,7 @@
"color": "Skift farven på denne opgave",
"move": "Move this task to another project",
"reminder": "Administrer påmindelser om denne opgave",
"description": "Slå redigering af opgavebeskrivelse til/fra",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Slå redigering af opgavebeskrivelse til/fra"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Zitat",
"unorderedList": "Ungeordnete Liste",
"orderedList": "Geordnete Liste",
"orderedList ": "Ordered List",
"cleanBlock": "Formatierung löschen",
"link": "Link",
"image": "Bild",
@ -566,14 +566,14 @@
"canuse": "Du kannst Datumsberechnung verwenden, um nach relativen Daten zu filtern.",
"learnhow": "Sieh dir an, wie es funktioniert",
"title": "Datumsberechnung",
"intro": "Du kannst relative Daten angeben, die bei der Anwendung des Filters von Vikunja aufgelöst werden.",
"intro": "Die Datumsberechnung erlaubt es, relative Daten anzugeben, die bei der Anwendung des Filters von Vikunja aufgelöst werden.",
"expression": "Jeder Ausdruck der Datumsberechnung beginnt mit einem Datumswert, welcher entweder {0} sein kann oder mit {1} endet. Auf diesen Datumswert kann optional ein oder mehrere mathematische Ausdrücke folgen.",
"similar": "Diese Ausdrücke ähneln denen von {0} und {1}.",
"add1Day": "Einen Tag hinzufügen",
"minus1Day": "Einen Tag abziehen",
"roundDay": "Auf den nächsten Tag abrunden",
"supportedUnits": "Unterstützte Zeiteinheiten",
"someExamples": "Beispiele für Zeitausdrücke",
"supportedUnits": "Unterstützte Zeiteinheiten sind:",
"someExamples": "Einige Beispiele für Zeitausdrücke:",
"units": {
"seconds": "Sekunden",
"minutes": "Minuten",
@ -894,10 +894,7 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Aufgabenbeschreibung bearbeiten"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend-Version: {version}",
"apiVersion": "API-Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Zitaat",
"unorderedList": "Ungordnedi Listä",
"orderedList": "Geordnete Liste",
"orderedList ": "Ordered List",
"cleanBlock": "Formatierig Lösche",
"link": "Link",
"image": "Bild",
@ -566,14 +566,14 @@
"canuse": "Du kannst Datumsberechnung verwenden, um nach relativen Daten zu filtern.",
"learnhow": "Sieh dir an, wie es funktioniert",
"title": "Datumsberechnung",
"intro": "Du kannst relative Daten angeben, die bei der Anwendung des Filters von Vikunja aufgelöst werden.",
"intro": "Die Datumsberechnung erlaubt es, relative Daten anzugeben, die bei der Anwendung des Filters von Vikunja aufgelöst werden.",
"expression": "Jeder Ausdruck der Datumsberechnung beginnt mit einem Datumswert, welcher entweder {0} sein kann oder mit {1} endet. Auf diesen Datumswert kann optional ein oder mehrere mathematische Ausdrücke folgen.",
"similar": "Diese Ausdrücke ähneln denen von {0} und {1}.",
"add1Day": "Einen Tag hinzufügen",
"minus1Day": "Einen Tag abziehen",
"roundDay": "Auf den nächsten Tag abrunden",
"supportedUnits": "Unterstützte Zeiteinheiten",
"someExamples": "Beispiele für Zeitausdrücke",
"supportedUnits": "Unterstützte Zeiteinheiten sind:",
"someExamples": "Einige Beispiele für Zeitausdrücke:",
"units": {
"seconds": "Sekunden",
"minutes": "Minuten",
@ -894,10 +894,7 @@
"color": "Die Farbe dieser Aufgabe ändern",
"move": "Move this task to another project",
"reminder": "Erinnerungen für diese Aufgabe verwalten",
"description": "Aufgabenbeschreibung bearbeiten",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Aufgabenbeschreibung bearbeiten"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -569,14 +569,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -897,10 +897,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1059,4 +1056,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Código",
"quote": "Cita",
"unorderedList": "Lista no ordenada",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Borrar Bloque",
"link": "Enlace",
"image": "Imagen",
@ -566,14 +566,14 @@
"canuse": "Puedes usar ecuaciones para filtrar por fechas relacionadas.",
"learnhow": "Mira cómo funciona",
"title": "Ecuaciones",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Las Ecuaciones permiten determinar qué fechas relacionadas te mostrará Vikunja al aplicar este filtro.",
"expression": "Cada expresión matemática empieza con una fecha ancla, que puede ser {0}, o una cadena de texto que acabe en {1}. Opcionalmente, esta fecha puede estar seguida de una o más expresiones.",
"similar": "Estas expresiones son similares a las definidas en {0} y {1}.",
"add1Day": "Añadir un día",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Cambia el color de esta tarea",
"move": "Move this task to another project",
"reminder": "Administrar recordatorios de esta tarea",
"description": "Editar la descripción de la tarea",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Editar la descripción de la tarea"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "Versión de la API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Citation",
"unorderedList": "Liste non ordonnée",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Bloc propre",
"link": "Lien",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Changer la couleur de cette tâche",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Version : {version}",
"apiVersion": "Version de lAPI : {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Codice",
"quote": "Citazione",
"unorderedList": "Elenco puntato",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Pulisci Blocco",
"link": "Link",
"image": "Immagine",
@ -566,14 +566,14 @@
"canuse": "Puoi usare le date calcolate per filtrare per date relative.",
"learnhow": "Scopri come funziona",
"title": "Date Calcolate",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Le Date Calcolate ti permettono di specificare date relative che vengono calcolate al volo da Vikunja quando viene applicato il filtro.",
"expression": "Ogni Data Calcolata inizia con una data base, che può essere {0}, o una data con {1} alla fine. Questa data base può essere seguita da una o più espressioni matematiche.",
"similar": "Queste espressioni sono simili a quelle fornite da {0} e {1}.",
"add1Day": "Aggiungi un giorno",
"minus1Day": "Sottrai un giorno",
"roundDay": "Arrotonda per difetto al giorno più vicino",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Le unità di tempo supportate sono:",
"someExamples": "Alcuni esempi di espressione temporale:",
"units": {
"seconds": "Secondi",
"minutes": "Minuti",
@ -894,10 +894,7 @@
"color": "Cambia il colore di questa attività",
"move": "Move this task to another project",
"reminder": "Gestisci i promemoria di questa attività",
"description": "Attiva/Disattiva modifica della descrizione dell'attività",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Attiva/Disattiva modifica della descrizione dell'attività"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Versione Frontend: {version}",
"apiVersion": "Versione API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Citaat",
"unorderedList": "Ongesorteerde lijst",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Afbeelding",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend versie: {version}",
"apiVersion": "API Versie: {version}"
}
}
}

View File

@ -6,10 +6,10 @@
"welcomeEvening": "God Morgen {username}!",
"lastViewed": "Sist sett",
"project": {
"newText": "Du kan opprette en ny liste for dine nye oppgaver:",
"new": "Nytt prosjekt",
"importText": "Eller importer lister og oppgaver fra andre tjenester til Vikunja:",
"import": "Importer dine data til Vikunja"
"newText": "You can create a new project for your new tasks:",
"new": "New project",
"importText": "Or import your projects and tasks from other services into Vikunja:",
"import": "Import your data into Vikunja"
}
},
"404": {
@ -85,7 +85,7 @@
"weekStartSunday": "Søndag",
"weekStartMonday": "Mandag",
"language": "Språk",
"defaultProject": "Standard prosjekt",
"defaultProject": "Default Project",
"timezone": "Tidssone",
"overdueTasksRemindersTime": "Utløpte påminnelses-tid for oppgaver"
},
@ -143,7 +143,7 @@
},
"deletion": {
"title": "Slett kontoen din",
"text1": "Sletting av din konto er permanent og kan ikke angres. Vi vil slette alle dine navneområder og prosjekter, oppgaver og alt forbundet med den.",
"text1": "The deletion of your account is permanent and cannot be undone. We will delete all your namespaces, projects, tasks and everything associated with it.",
"text2": "For å fortsette, skriv inn passordet ditt. Du vil motta en e-post med ytterligere instruksjoner.",
"confirm": "Slett min konto",
"requestSuccess": "Forespørselen var vellykket. Du vil motta en e-post med ytterligere instruksjoner.",
@ -157,7 +157,7 @@
},
"export": {
"title": "Eksporter dine kontodata",
"description": "Du kan be om en kopi av alle Vikunja dataene dine. Dette inkluderer navneområder, lister, oppgaver og alt tilknyttet dem.",
"description": "You can request a copy of all your Vikunja data. This include Namespaces, Projects, Tasks and everything associated to them. You can import this data in any Vikunja instance through the migration function.",
"descriptionPasswordRequired": "Skriv inn passordet for å fortsette:",
"request": "Be om kopi av mine Vikunja Data",
"success": "Du har spurt om dine Vikunja data! Vi sender deg en e-post når den er klar til å laste ned.",
@ -165,193 +165,193 @@
}
},
"project": {
"archived": "Dette prosjektet er arkivert. Det er ikke mulig å opprette nye eller redigere oppgaver for det.",
"title": "Prosjekt tittel",
"color": "Farger",
"projects": "Prosjekter",
"search": "Tast for å søke etter et prosjekt…",
"searchSelect": "Klikk eller trykk enter for å velge dette prosjektet",
"shared": "Delte prosjekter",
"noDescriptionAvailable": "Ingen prosjektbeskrivelse er tilgjengelig.",
"archived": "This project is archived. It is not possible to create new or edit tasks for it.",
"title": "Project Title",
"color": "Color",
"projects": "Projects",
"search": "Type to search for a project…",
"searchSelect": "Click or press enter to select this project",
"shared": "Shared Projects",
"noDescriptionAvailable": "No project description is available.",
"create": {
"header": "Nytt prosjekt",
"titlePlaceholder": "Prosjektets tittel er her…",
"addTitleRequired": "Angi den nye tittelen.",
"createdSuccess": "Prosjektet ble opprettet.",
"addProjectRequired": "Vennligst spesifiser et prosjekt eller angi et standardprosjekt i innstillingene."
"header": "New project",
"titlePlaceholder": "The project's title goes here…",
"addTitleRequired": "Please specify a title.",
"createdSuccess": "The project was successfully created.",
"addProjectRequired": "Please specify a project or set a default project in the settings."
},
"archive": {
"title": "Arkiver{project}\"",
"archive": "Arkiver dette prosjektet",
"unarchive": "Av-arkivere dette prosjektet",
"unarchiveText": "Du vil kunne opprette nye oppgaver eller redigere den.",
"archiveText": "Du vil ikke være i stand til å redigere denne listen eller opprette nye oppgaver før du fjerner arkiveringen.",
"success": "Prosjektet ble vellykket arkivert."
"title": "Archive \"{project}\"",
"archive": "Archive this project",
"unarchive": "Un-Archive this project",
"unarchiveText": "You will be able to create new tasks or edit it.",
"archiveText": "You won't be able to edit this project or create new tasks until you un-archive it.",
"success": "The project was successfully archived."
},
"background": {
"title": "Angi prosjektbakgrunn",
"remove": "Fjern bakgrunn",
"upload": "Velg en bakgrunn fra din pc",
"searchPlaceholder": "Søk etter en bakgrunn…",
"poweredByUnsplash": "Drevet av Unsplash",
"loadMore": "Laste inn flere bilder",
"success": "Bakgrunnen er satt vellykket!",
"removeSuccess": "Bakgrunnen har blitt fjernet!"
"title": "Set project background",
"remove": "Remove Background",
"upload": "Choose a background from your pc",
"searchPlaceholder": "Search for a background…",
"poweredByUnsplash": "Powered by Unsplash",
"loadMore": "Load more photos",
"success": "The background has been set successfully!",
"removeSuccess": "The background has been removed successfully!"
},
"delete": {
"title": "Slett \"{project}",
"header": "Slett dette prosjektet",
"text1": "Er du sikker på at du vil slette dette prosjektet og alle relaterte data?",
"text2": "Dette inkluderer alle oppgaver og KAN IKKE ANGRES!",
"success": "Prosjektet ble slettet.",
"tasksToDelete": "Dette vil ugjenkallelig fjerne ca. {count} oppgaver.",
"noTasksToDelete": "Dette prosjektet inneholder ingen oppgaver, det bør være trygt å slette."
"title": "Delete \"{project}\"",
"header": "Delete this project",
"text1": "Are you sure you want to delete this project and all of its contents?",
"text2": "This includes all tasks and CANNOT BE UNDONE!",
"success": "The project was successfully deleted.",
"tasksToDelete": "This will irrevocably remove approx. {count} tasks.",
"noTasksToDelete": "This project does not contain any tasks, it should be safe to delete."
},
"duplicate": {
"title": "Dupliser dette prosjektet",
"label": "Dupliser",
"text": "Velg et navneområde som skal holde det dupliserte prosjektet:",
"success": "Prosjektet ble duplisert."
"title": "Duplicate this project",
"label": "Duplicate",
"text": "Select a namespace which should hold the duplicated project:",
"success": "The project was successfully duplicated."
},
"edit": {
"header": "Rediger prosjekt",
"title": "Rediger \"{project}",
"titlePlaceholder": "Prosjekttittelen går her…",
"identifierTooltip": "Prosjektidentifikatoren kan brukes til å identifisere en oppgave på tvers av prosjekter. Du kan sette den til tom for å deaktivere den.",
"identifier": "Prosjekt identifikator",
"identifierPlaceholder": "Prosjektidentifikatoren kommer her…",
"description": "Beskrivelse",
"descriptionPlaceholder": "Beskrivelsen gis her…",
"color": "Farger",
"success": "Prosjektet ble opprettet."
"header": "Edit This Project",
"title": "Edit \"{project}\"",
"titlePlaceholder": "The project title goes here…",
"identifierTooltip": "The project identifier can be used to uniquely identify a task across projects. You can set it to empty to disable it.",
"identifier": "Project Identifier",
"identifierPlaceholder": "The project identifier goes here…",
"description": "Description",
"descriptionPlaceholder": "The projects description goes here…",
"color": "Color",
"success": "The project was successfully updated."
},
"share": {
"header": "Del dette prosjektet",
"title": "Del \"{project}\"",
"share": "Del",
"header": "Share this project",
"title": "Share \"{project}\"",
"share": "Share",
"links": {
"title": "Del link",
"what": "Hva er en lenke for deling?",
"explanation": "Lenker lar deg enkelt dele et prosjekt med andre brukere som ikke har en konto på Vikunja.",
"create": "Opprett en ny lenkedeling",
"name": "Navn (valgfritt)",
"title": "Share Links",
"what": "What is a share link?",
"explanation": "Share Links allow you to easily share a project with other users who don't have an account on Vikunja.",
"create": "Create a new link share",
"name": "Name (optional)",
"namePlaceholder": "e.g. Lorem Ipsum",
"nameExplanation": "Alle handlinger utført av denne koblingsdelingen vises med navnet.",
"password": "Passord (valgfritt)",
"passwordExplanation": "Når brukeren autentiseres, må vedkommende angi dette passordet.",
"noName": "Ingen navn satt",
"remove": "Fjern en link deling",
"removeText": "Er du sikker på at du vil fjerne denne lenkedelen? Det vil ikke lenger være mulig å åpne dette prosjektet med denne lenkedelingen. Dette kan ikke angres!",
"createSuccess": "Delingen ble opprettet.",
"deleteSuccess": "Delingen ble slettet",
"view": "Vis",
"sharedBy": "Delt av {0}"
"nameExplanation": "All actions done by this link share will show up with the name.",
"password": "Password (optional)",
"passwordExplanation": "When authenticating, the user will be required to enter this password.",
"noName": "No name set",
"remove": "Remove a link share",
"removeText": "Are you sure you want to remove this link share? It will no longer be possible to access this project with this link share. This cannot be undone!",
"createSuccess": "The link share was successfully created.",
"deleteSuccess": "The link share was successfully deleted",
"view": "View",
"sharedBy": "Shared by {0}"
},
"userTeam": {
"typeUser": "bruker | brukere",
"typeUser": "user | users",
"typeTeam": "team | teams",
"shared": "Delt med disse {type}",
"you": "Du",
"notShared": "Ikke delt med noen {type} ennå.",
"removeHeader": "Fjern en {type} fra {sharable}",
"removeText": "Er du sikker på at du vil fjerne denne {sharable} fra {type}? Dette kan ikke angres!",
"removeSuccess": "{sharable} ble fjernet fra {type}.",
"addedSuccess": "{type} ble lagt til.",
"updatedSuccess": "{type} ble lagt til."
"shared": "Shared with these {type}",
"you": "You",
"notShared": "Not shared with any {type} yet.",
"removeHeader": "Remove a {type} from the {sharable}",
"removeText": "Are you sure you want to remove this {sharable} from the {type}? This cannot be undone!",
"removeSuccess": "The {sharable} was successfully removed from the {type}.",
"addedSuccess": "The {type} was successfully added.",
"updatedSuccess": "The {type} was successfully added."
},
"right": {
"title": "Rettighet",
"read": "Kun lese",
"readWrite": "Lese og skrive",
"admin": "Administrator"
"title": "Permission",
"read": "Read only",
"readWrite": "Read & write",
"admin": "Admin"
},
"attributes": {
"link": "Link",
"delete": "Slett"
"delete": "Delete"
}
},
"list": {
"title": "Liste",
"add": "Legg til",
"addPlaceholder": "Legg til ny oppgave…",
"empty": "Dette prosjektet er for øyeblikket tomt.",
"newTaskCta": "Lage en ny oppgave.",
"editTask": "Endre oppgave"
"title": "List",
"add": "Add",
"addPlaceholder": "Add a new task…",
"empty": "This project is currently empty.",
"newTaskCta": "Create a new task.",
"editTask": "Edit Task"
},
"gantt": {
"title": "Gantt",
"showTasksWithoutDates": "Vis oppgaver som ikke har datoer angitt",
"size": "Størrelse",
"default": "Standard",
"month": "Måned",
"day": "Dag",
"hour": "Time",
"range": "Datointervall",
"noDates": "Denne oppgaven har ingen datoer satt."
"showTasksWithoutDates": "Show tasks which don't have dates set",
"size": "Size",
"default": "Default",
"month": "Month",
"day": "Day",
"hour": "Hour",
"range": "Date Range",
"noDates": "This task has no dates set."
},
"table": {
"title": "Tabell",
"columns": "Kolonner"
"title": "Table",
"columns": "Columns"
},
"kanban": {
"title": "Kanban",
"limit": "Grense: {limit}",
"noLimit": "Ikke Angitt",
"doneBucket": "Ferdig bøtte",
"doneBucketHint": "Alle oppgaver som flyttet til denne bøtte vil automatisk bli markert som ferdig.",
"doneBucketHintExtended": "Alle oppgaver som er flyttet inn i den utførte bøtten, vil bli merket som utført automatisk. Alle oppgaver merket som gjort fra andre steder vil også bli flyttet.",
"doneBucketSavedSuccess": "Bøtten er lagret.",
"deleteLast": "Du kan ikke fjerne den siste bøtten.",
"addTaskPlaceholder": "Angi den nye oppgavens tittel…",
"addTask": "Legg til oppgave",
"addAnotherTask": "Legg til en annen oppgave",
"addBucket": "Lag en ny bøtte",
"addBucketPlaceholder": "Angi den nye bøtte tittelen…",
"deleteHeaderBucket": "Slett bøtte",
"deleteBucketText1": "Er du sikker på at du vil slette denne bøtte?",
"deleteBucketText2": "Dette vil ikke slette noen oppgaver, men flytte dem til standard bøtte.",
"deleteBucketSuccess": "Bøtten er slettet.",
"bucketTitleSavedSuccess": "Bøtten er lagret.",
"bucketLimitSavedSuccess": "Grensen på bøtte er lagret.",
"collapse": "Skjul denne bøtten"
"limit": "Limit: {limit}",
"noLimit": "Not Set",
"doneBucket": "Done bucket",
"doneBucketHint": "All tasks moved into this bucket will automatically marked as done.",
"doneBucketHintExtended": "All tasks moved into the done bucket will be marked as done automatically. All tasks marked as done from elsewhere will be moved as well.",
"doneBucketSavedSuccess": "The done bucket has been saved successfully.",
"deleteLast": "You cannot remove the last bucket.",
"addTaskPlaceholder": "Enter the new task title…",
"addTask": "Add a task",
"addAnotherTask": "Add another task",
"addBucket": "Create a new bucket",
"addBucketPlaceholder": "Enter the new bucket title…",
"deleteHeaderBucket": "Delete the bucket",
"deleteBucketText1": "Are you sure you want to delete this bucket?",
"deleteBucketText2": "This will not delete any tasks but move them into the default bucket.",
"deleteBucketSuccess": "The bucket has been deleted successfully.",
"bucketTitleSavedSuccess": "The bucket title has been saved successfully.",
"bucketLimitSavedSuccess": "The bucket limit been saved successfully.",
"collapse": "Collapse this bucket"
},
"pseudo": {
"favorites": {
"title": "Favoritter"
"title": "Favorites"
}
}
},
"namespace": {
"title": "Navneområder & lister",
"title": "Namespaces & Projects",
"namespace": "Navneområde",
"showArchived": "Vis arkiverte",
"noneAvailable": "Du har ingen navneområder akkurat nå.",
"unarchive": "Av-arkiver",
"archived": "Arkivert",
"noProjects": "Dette navneområdet inneholder ikke noen prosjekter.",
"createProject": "Opprett et nytt prosjekt i dette navneområdet.",
"noProjects": "This namespace does not contain any projects.",
"createProject": "Create a new project in this namespace.",
"namespaces": "Navnerom",
"search": "Skriv for å søke etter en etikett…",
"create": {
"title": "Nytt navneområde",
"titleRequired": "Angi den nye tittelen.",
"explanation": "Et navneområde er en samling av lister du kan dele og bruke til å organisere listene dine med. I realiteten hører hver liste til et navneområde.",
"explanation": "A namespace is a collection of projects you can share and use to organize your projects with. In fact, every project belongs to a namespace.",
"tooltip": "Hva er et navneområde?",
"success": "Navneområdet ble opprettet."
},
"archive": {
"titleArchive": "Arkiv \"{namespace}\"",
"titleUnarchive": "Av-Arkiv \"{namespace}\"",
"archiveText": "Du vil ikke kunne redigere dette navneområdet eller opprette nye lister før du avlaster arkivet. Dette vil også arkivere alle lister i dette navneområdet.",
"unarchiveText": "Du vil kunne opprette nye oppgaver eller redigere den.",
"archiveText": "You won't be able to edit this namespace or create new projects until you un-archive it. This will also archive all projects in this namespace.",
"unarchiveText": "You will be able to create new projects or edit it.",
"success": "Navnerommet ble arkivert.",
"unarchiveSuccess": "Navnerommet ble vellykket fjernet fra arkivet.",
"description": "Hvis navneområdet er arkivert, kan du ikke opprette nye lister eller redigere det."
"description": "If a namespace is archived, you cannot create new projects or edit it."
},
"delete": {
"title": "Slett \"{namespace}",
"text1": "Er du sikker på at du vil slette dette navneområdet og alt innholdet?",
"text2": "Dette inkluderer alle oppgaver og KAN IKKE ANGRES!",
"text2": "This includes all projects and tasks and CANNOT BE UNDONE!",
"success": "Navnområdet ble slettet."
},
"edit": {
@ -372,7 +372,7 @@
},
"pseudo": {
"sharedProjects": {
"title": "Delte prosjekter"
"title": "Shared Projects"
},
"favorites": {
"title": "Favoritter"
@ -403,9 +403,9 @@
},
"create": {
"title": "Nytt lagret filter",
"description": "Et lagret filter er en virtuell liste som beregnes fra et sett med filtre hver gang det åpnes. Når du er opprettet, vil det vises i et eget navneområde.",
"description": "A saved filter is a virtual project which is computed from a set of filters each time it is accessed. Once created, it will appear in a special namespace.",
"action": "Opprett nytt filter",
"titleRequired": "Skriv inn en tittel for filteret."
"titleRequired": "Please provide a title for the filter."
},
"delete": {
"header": "Slett dette lagrede filteret",
@ -435,7 +435,7 @@
"label": {
"title": "Etiketter",
"manage": "Behandle etiketter",
"description": "Klikk på en etikett for å redigere den. Du kan redigere alle etikettene du lagde, du kan bruke alle etikettene som er tilknyttet en oppgave som du har tilgang til.",
"description": "Click on a label to edit it. You can edit all labels you created, you can use all labels which are associated with a task to whose project you have access.",
"newCTA": "Du har ingen etiketter for øyeblikket.",
"search": "Skriv for å søke etter en etikett…",
"create": {
@ -460,7 +460,7 @@
},
"sharing": {
"authenticating": "Autentiserer…",
"passwordRequired": "Denne delte listen krever et passord. Vennligst skriv det nedenfor:",
"passwordRequired": "This shared project requires a password. Please enter it below:",
"error": "En feil oppsto.",
"invalidPassword": "Det oppgitte passordet er ugyldig."
},
@ -529,7 +529,7 @@
"code": "Kode",
"quote": "Sitat",
"unorderedList": "Uordnet liste",
"orderedList": "Sortert liste",
"orderedList ": "Ordered List",
"cleanBlock": "Tøm blokk",
"link": "Link",
"image": "Bilde",
@ -572,8 +572,8 @@
"add1Day": "Legg til en dag",
"minus1Day": "Trekk fra en dag",
"roundDay": "Rund ned til nærmeste verdi",
"supportedUnits": "Støttede tidsenheter",
"someExamples": "Noen eksempler på tidsuttrykk",
"supportedUnits": "Støttede tidsenheter er:",
"someExamples": "Noen eksempler på tidsuttrykk:",
"units": {
"seconds": "Sekunder",
"minutes": "Minutter",
@ -602,7 +602,7 @@
"addReminder": "Legg til en ny påminnelse…",
"doneSuccess": "Oppgaven ble markert som ferdig.",
"undoneSuccess": "Oppgaven ble fjernet som ferdig.",
"undo": "Angre",
"undo": "Undo",
"openDetail": "Åpne detaljvisning",
"checklistTotal": "{checked} av {total} oppgaver",
"checklistAllDone": "{total} oppgaver",
@ -619,7 +619,7 @@
"chooseDueDate": "Klikk her for å angi en forfallsdato",
"chooseStartDate": "Klikk her for å angi en startdato",
"chooseEndDate": "Klikk her for å angi en sluttdato",
"move": "Flytt oppgaven til en annen liste",
"move": "Move task to a different project",
"done": "Marker som utført!",
"undone": "Merk som uferdig",
"created": "Opprettet {0} av {1}",
@ -627,7 +627,7 @@
"doneAt": "Ferdig {0}",
"updateSuccess": "Oppgaven ble lagret.",
"deleteSuccess": "Oppgaven har blitt slettet.",
"belongsToProject": "Denne oppgaven tilhører listen '{project}'",
"belongsToProject": "This task belongs to project '{project}'",
"due": "Forfallsdato {at}",
"closePopup": "Lukk popup",
"delete": {
@ -647,7 +647,7 @@
"percentDone": "Angi fremdrift",
"attachments": "Legg til vedlegg",
"relatedTasks": "Legg til relasjon",
"moveProject": "Flytt",
"moveProject": "Move",
"color": "Sett Farge",
"delete": "Slett",
"favorite": "Legg til i favoritter",
@ -674,21 +674,21 @@
"updated": "Oppdatert"
},
"subscription": {
"subscribedProjectThroughParentNamespace": "Du kan ikke slutte å abonnere her fordi du abonnerer på denne listen gjennom dens navneområde.",
"subscribedProjectThroughParentNamespace": "You can't unsubscribe here because you are subscribed to this project through its namespace.",
"subscribedTaskThroughParentNamespace": "Du kan ikke slutte å abonnere her fordi du abonnerer på denne oppgaven gjennom navneområdet.",
"subscribedTaskThroughParentProject": "Du kan ikke melde deg ut her fordi du abonnerer på denne oppgaven gjennom prosjektet.",
"subscribedTaskThroughParentProject": "You can't unsubscribe here because you are subscribed to this task through its project.",
"subscribedNamespace": "Du abonnerer for øyeblikket på dette navneområdet og vil motta varsler for endringer.",
"notSubscribedNamespace": "Du abonnerer ikke på dette navneområdet og vil ikke motta varsler for endringer.",
"subscribedProject": "Du abonnerer for øyeblikket på dette prosjektet og vil motta varsler for endringer.",
"notSubscribedProject": "Du abonnerer ikke på dette prosjektet og vil ikke motta varsler for endringer.",
"subscribedProject": "You are currently subscribed to this project and will receive notifications for changes.",
"notSubscribedProject": "You are not subscribed to this project and won't receive notifications for changes.",
"subscribedTask": "Du abonnerer for øyeblikket på denne oppgaven og vil motta varsler for endringer.",
"notSubscribedTask": "Du abonnerer ikke på denne oppgaven og vil ikke motta varsler for endringer.",
"subscribe": "Abonnerer",
"unsubscribe": "Avslutt abonnement",
"subscribeSuccessNamespace": "Du abonnerer nå på dette navneområdet",
"unsubscribeSuccessNamespace": "Du blir nå avmeldt dette navneområdet",
"subscribeSuccessProject": "Du abonnerer nå på dette prosjektet",
"unsubscribeSuccessProject": "Du har nå avsluttet abonnementet for dette prosjektet",
"subscribeSuccessProject": "You are now subscribed to this project",
"unsubscribeSuccessProject": "You are now unsubscribed to this project",
"subscribeSuccessTask": "Du abonnerer nå på denne oppgaven",
"unsubscribeSuccessTask": "Du har nå avsluttet abonnementet for denne oppgaven"
},
@ -762,7 +762,7 @@
"new": "Ny oppgaveforbindelse",
"searchPlaceholder": "Skriv søk etter en ny oppgave å legge til som relatert…",
"createPlaceholder": "Legg til denne som ny relatert oppgave",
"differentProject": "Denne oppgaven tilhører et annet prosjekt.",
"differentProject": "This task belongs to a different project.",
"differentNamespace": "Denne oppgaven tilhører en annen navneområde.",
"noneYet": "Ingen arbeidsrelasjoner ennå.",
"delete": "Slett relasjon",
@ -812,10 +812,10 @@
"priority1": "For å angi en oppgaves prioritet, legg til et nummer 1-5, med en {prefix} som prefiks.",
"priority2": "Jo høyere tallet er, desto høyere prioritet.",
"assignees": "For å direkte tilordne oppgaven til en bruker må du legge til brukernavnet deres med {prefix} som er prefikset på oppgaven.",
"project1": "For å angi et prosjekt for oppgaven som skal vises i, angi dets navn med {prefix}.",
"project2": "Dette vil returnere en feil dersom prosjektet ikke finnes.",
"project3": "For å bruke mellomrom, legg bare til en \" eller ' rundt navnet på prosjektet.",
"project4": "For eksempel: {prefix}\"Prosjekt med mellomrom\".",
"project1": "To set a project for the task to appear in, enter its name prefixed with {prefix}.",
"project2": "This will return an error if the project does not exist.",
"project3": "To use spaces, simply add a \" or ' around the project name.",
"project4": "For example: {prefix}\"Project with spaces\".",
"dateAndTime": "Dato og tid",
"date": "Hvilken som helst dato vil bli brukt som forfallsdato for den nye oppgaven. Du kan bruke datoer i hvilket som helst format:",
"dateWeekday": "hver ukedag vil bruke neste dato med den datoen",
@ -848,19 +848,19 @@
"delete": {
"header": "Slett gruppen",
"text1": "Er du sikker på at du vil slette denne gruppen og alle dets medlemmer?",
"text2": "Alle teammedlemmer vil miste tilgang til prosjekter og navneområder som deles med dette teamet. KAN IKKE ANGRES!",
"text2": "All team members will lose access to projects and namespaces shared with this team. This CANNOT BE UNDONE!",
"success": "Gruppen ble slettet."
},
"deleteUser": {
"header": "Fjerne en bruker fra gruppen",
"text1": "Er du sikker på at du vil fjerne bruker fra denne gruppen?",
"text2": "De vil miste tilgang til alle prosjekter og namespaces dette teamet har tilgang til. Dette KAN IKKE ANGRES!",
"text2": "They will lose access to all projects and namespaces this team has access to. This CANNOT BE UNDONE!",
"success": "Brukeren ble slettet fra gruppen."
},
"leave": {
"title": "Forlat gruppen",
"text1": "Er du sikker på at du vil forlate denne gruppen?",
"text2": "Du vil miste tilgang til alle prosjekter og namespaces dette teamet har tilgang til. Hvis du ombestemmer deg, må du ha en lagadministrator for å legge deg til igjen.",
"text2": "You will lose access to all projects and namespaces this team has access to. If you change your mind you'll need a team admin to add you again.",
"success": "Du har forlatt gruppen."
}
},
@ -892,25 +892,22 @@
"attachment": "Legg til et vedlegg til denne oppgaven",
"related": "Endre relaterte oppgaver for denne oppgaven",
"color": "Endre fargen på denne oppgaven",
"move": "Flytt denne oppgaven til et annet prosjekt",
"move": "Move this task to another project",
"reminder": "Behandle påminnelser om denne oppgaven",
"description": "Veksle redigering av oppgavebeskrivelsen",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Veksle redigering av oppgavebeskrivelsen"
},
"project": {
"title": "Prosjektvisning",
"switchToListView": "Byttet til listevisning",
"switchToGanttView": "Bytt til gantt-visning",
"switchToKanbanView": "Bytt til kanban visning",
"switchToTableView": "Bytt til tabellvisning"
"title": "Project Views",
"switchToListView": "Switch to list view",
"switchToGanttView": "Switch to gantt view",
"switchToKanbanView": "Switch to kanban view",
"switchToTableView": "Switch to table view"
},
"navigation": {
"title": "Navigasjon",
"overview": "Naviger til oversikt",
"upcoming": "Gå til kommende oppgaver",
"namespaces": "Gå til navneområder & prosjekter",
"namespaces": "Navigate to namespaces & projects",
"labels": "Naviger til etiketter",
"teams": "Naviger til gruppe"
}
@ -927,7 +924,7 @@
"unarchive": "Av-arkiver",
"setBackground": "Bruk som bakgrunn",
"share": "Del",
"newProject": "Nytt prosjekt"
"newProject": "New project"
},
"apiConfig": {
"url": "Vikunja URL",
@ -946,24 +943,24 @@
"notification": {
"title": "Varsler",
"none": "Du har ingen varsler på dette tidspunktet!",
"explainer": "Varsler vil vises her når handlinger på navneområder, prosjekter, lister eller oppgaver du abonnerer på."
"explainer": "Notifications will appear here when actions on namespaces, projects or tasks you subscribed to happen."
},
"quickActions": {
"commands": "Kommandoer",
"placeholder": "Skriv en kommando eller søk…",
"hint": "Du kan bruke {project} for å begrense søket til en liste. Kombiner {project} eller {label} (etiketter) med et søk for å søke etter en oppgave med disse etikettene eller på den listen. Bruk {assignee} for bare å søke etter lag.",
"hint": "You can use {project} to limit the search to a project. Combine {project} or {label} (labels) with a search query to search for a task with these labels or on that project. Use {assignee} to only search for teams.",
"tasks": "Oppgaver",
"projects": "Prosjekter",
"projects": "Projects",
"teams": "Grupper",
"newProject": "Skriv tittelen på det nye prosjektet…",
"newProject": "Enter the title of the new project…",
"newTask": "Skriv tittelen på den nye oppgaven…",
"newNamespace": "Skriv inn tittelen på det nye navneområdet…",
"newTeam": "Skriv inn navnet på den nye gruppen…",
"createTask": "Opprett en oppgave i det gjeldende prosjektet ({title})",
"createProject": "Opprett et prosjekt i gjeldende navneområde ({title})",
"createTask": "Create a task in the current project ({title})",
"createProject": "Create a project in the current namespace ({title})",
"cmds": {
"newTask": "Ny oppgave",
"newProject": "Nytt prosjekt",
"newProject": "New project",
"newNamespace": "Nytt navneområde",
"newTeam": "Ny gruppe"
}
@ -995,15 +992,15 @@
"1018": "Innstillingen av brukerens avatartype er ugyldig.",
"2001": "ID kan ikke være tom eller 0.",
"2002": "Noen av forespørselsdataene var ugyldig.",
"3001": "Prosjektet finnes ikke.",
"3004": "Du må ha lesetilgang til prosjektet for å utføre den handlingen.",
"3005": "Tittelen kan ikke være tom.",
"3006": "Prosjektdeling finnes ikke.",
"3007": "Et prosjekt med denne identifikatoren eksisterer allerede.",
"3008": "Prosjektet er arkivert og kan derfor bare leses inn. Dette gjelder også for alle oppgaver som er tilknyttet dette prosjektet.",
"4001": "Prosjektets oppgavetekst kan ikke være tom.",
"4002": "Prosjektoppgaven finnes ikke.",
"4003": "Alle bulkredigering oppgaver må tilhøre samme prosjekt.",
"3001": "The project does not exist.",
"3004": "You need to have read permissions on that project to perform that action.",
"3005": "The project title cannot be empty.",
"3006": "The project share does not exist.",
"3007": "A project with this identifier already exists.",
"3008": "The project is archived and can therefore only be accessed read only. This is also true for all tasks associated with this project.",
"4001": "The project task text cannot be empty.",
"4002": "The project task does not exist.",
"4003": "All bulk editing tasks must belong to the same project.",
"4004": "Trenger minst én oppgave når masseredigeringsoppgaver skal utføres.",
"4005": "Du har ikke rettigheter til å redigere denne siden.",
"4006": "Du kan ikke sette en overordnet oppgave som oppgaven selv.",
@ -1029,21 +1026,21 @@
"5012": "Navneområdet er arkivert og kan derfor kun leses på.",
"6001": "Gruppe nanvet kan ikke være tomt.",
"6002": "Gruppen finnes ikke.",
"6004": "Teamet har allerede tilgang til det navneområdet eller prosjektet.",
"6004": "The team already has access to that namespace or project.",
"6005": "Brukeren er allerede medlem av gruppen.",
"6006": "Kan ikke slette siste gruppemedlem.",
"6007": "Gruppen har ikke tilgang til prosjektet for å utføre den handlingen.",
"7002": "Brukeren har allerede tilgang til det prosjektet.",
"7003": "Du har ikke tilgang til det prosjektet.",
"6007": "The team does not have access to the project to perform that action.",
"7002": "The user already has access to that project.",
"7003": "You do not have access to that project.",
"8001": "Denne etiketten finnes allerede på den oppgaven.",
"8002": "Etiketten finnes ikke.",
"8003": "Du har ikke tilgang til denne etiketten.",
"9001": "Linken er ugyldig.",
"10001": "Bøtten finnes ikke.",
"10002": "Denne bøtte tilhører ikke det prosjektet.",
"10003": "Du kan ikke fjerne den siste bøtten på et prosjekt.",
"10002": "The bucket does not belong to that project.",
"10003": "You cannot remove the last bucket on a project.",
"10004": "Du kan ikke legge til oppgaven i denne bøtte fordi den allerede overskrider grensen på oppgaver som den kan holde.",
"10005": "Det kan bare finnes én ferdigstilt bøtte per prosjekt.",
"10005": "There can be only one done bucket per project.",
"11001": "Det lagrede filteret finnes ikke.",
"11002": "Lagrede filtre er ikke tilgjengelige for lenke delinger.",
"12001": "Abonnement enhetstypen er ugyldig.",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend versjon: {version}",
"apiVersion": "API versjon: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Kod",
"quote": "Cytat",
"unorderedList": "Lista nieuporządkowana",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Wyczyść blok",
"link": "Link",
"image": "Obraz",
@ -566,14 +566,14 @@
"canuse": "Możesz użyć kalkulacji dat do względnego filtrowania dat.",
"learnhow": "Sprawdź jak to działa",
"title": "Kalkulacja daty",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Kalkulacja daty pozwala względnie określić daty, które są przetwarzane przez Vikunję w locie, w czasie stosowania filtra.",
"expression": "Każde wyrażenie kalkulacji daty rozpoczyna się datą zakotwiczenia, którą może być {0} lub wyrażeniem daty zakończonym {1}. Po tej dacie zakotwiczenia opcjonalnie może następować jedno lub więcej wyrażeń matematycznych.",
"similar": "Te wyrażenia są podobne do tych dostarczonych przez {0} i {1}.",
"add1Day": "Dodaj jeden dzień",
"minus1Day": "Odejmij jeden dzień",
"roundDay": "Zaokrąglij w dół do najbliższego dnia",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Obsługiwane jednostki czasu to:",
"someExamples": "Kilka przykładów wyrażeń czasowych:",
"units": {
"seconds": "Sekundy",
"minutes": "Minuty",
@ -894,10 +894,7 @@
"color": "Zmień kolor tego zadania",
"move": "Move this task to another project",
"reminder": "Zarządzaj przypomnieniami o tym zadaniu",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Wersja frontendu: {version}",
"apiVersion": "Wersja API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Código",
"quote": "Citação",
"unorderedList": "Lista não ordenada",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Imagem",
@ -566,14 +566,14 @@
"canuse": "Você pode usar matemática de data para filtrar datas relativas.",
"learnhow": "Veja como funciona",
"title": "Matemática de Data",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "A matemática de data permite que você especifique datas relativas que são resolvidas em tempo real pelo Vikunja ao aplicar o filtro.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Adicionar um dia",
"minus1Day": "Subtrair um dia",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "As unidades de tempo suportadas são:",
"someExamples": "Alguns exemplos de expressões temporais:",
"units": {
"seconds": "Segundos",
"minutes": "Minutos",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Código",
"quote": "Citação",
"unorderedList": "Lista Não Ordenada",
"orderedList": "Lista Ordenada",
"orderedList ": "Lista Ordenada",
"cleanBlock": "Limpar Formatação",
"link": "Link",
"image": "Imagem",
@ -566,14 +566,14 @@
"canuse": "Podes utilizar cálculo de data para filtrar por datas relativas.",
"learnhow": "Vê como funciona",
"title": "Cálculo de Data",
"intro": "Especifica datas relativas que serão resolvidas em tempo real pela Vikunja ao aplicar o filtro.",
"intro": "O cálculo de data permite especificar datas relativas resolvidas em tempo real pelo Vikunja na aplicação do filtro.",
"expression": "Cada expressão de Cálculo de Data inicia com uma data âncora, que tanto pode ser {0}, como uma expressão de data terminada com {1}. Esta data âncora pode ser opcionalmente seguida de uma ou mais expressões matemáticas.",
"similar": "Essas expressões são semelhantes às fornecidas por {0} e {1}.",
"add1Day": "Adicionar um dia",
"minus1Day": "Subtrair um dia",
"roundDay": "Arredondar para baixo para o dia mais próximo",
"supportedUnits": "Unidades de tempo suportadas",
"someExamples": "Exemplos de expressões de tempo",
"supportedUnits": "As unidades de tempo suportadas são:",
"someExamples": "Alguns exemplos de expressões de tempo:",
"units": {
"seconds": "Segundos",
"minutes": "Minutos",
@ -894,10 +894,7 @@
"color": "Alterar a cor desta tarefa",
"move": "Mover esta tarefa para outro projeto",
"reminder": "Gerir lembretes desta tarefa",
"description": "Alternar edição da descrição da tarefa",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Alternar edição da descrição da tarefa"
},
"project": {
"title": "Vista do Projeto",
@ -1056,4 +1053,4 @@
"frontendVersion": "Versão Atual: {version}",
"apiVersion": "Versão da API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Код",
"quote": "Цитата",
"unorderedList": "Маркированный список",
"orderedList": "Нумерованный список",
"orderedList ": "Нумерованный список",
"cleanBlock": "Очистить блок",
"link": "Ссылка",
"image": "Изображение",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Как это работает",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "Это похоже на выражения, которые используются в {0} и {1}.",
"add1Day": "Добавить один день",
"minus1Day": "Вычесть один день",
"roundDay": "Округление вниз до начала дня",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Поддерживаемые единицы времени:",
"someExamples": "Примеры выражений:",
"units": {
"seconds": "Секунды",
"minutes": "Минуты",
@ -894,10 +894,7 @@
"color": "Изменить цвет этой задачи",
"move": "Переместить эту задачу в другой проект",
"reminder": "Управление напоминаниями об этой задаче",
"description": "Включить изменение описания задачи",
"delete": "Удалить задачу",
"priority": "Изменить приоритет задачи",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Включить изменение описания задачи"
},
"project": {
"title": "Просмотр проекта",
@ -1056,4 +1053,4 @@
"frontendVersion": "Версия фронтенда: {version}",
"apiVersion": "Версия API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Trích dẫn",
"unorderedList": "Gạch đầu dòng",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Làm sạch Khối",
"link": "Liên kết",
"image": "Ảnh",
@ -566,14 +566,14 @@
"canuse": "Bạn có thể sử dụng biểu thức tính ngày để lọc những ngày liên quan.",
"learnhow": "Xem cách hoạt động",
"title": "Tính Ngày",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Mỗi Biểu thức tính ngày bắt đầu bằng một ngày cố định, có thể là {0}, hoặc kết thúc bằng {1}. Ngày cố định này có thể được theo sau bởi một hoặc nhiều biểu thức toán học.",
"similar": "Những biểu thức này tương tự như những biểu thức được cung cấp bởi {0} và {1}.",
"add1Day": "Thêm một ngày",
"minus1Day": "Bớt đi một ngày",
"roundDay": "Làm tròn đến ngày gần nhất",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Các đơn vị thời gian hỗ trợ là:",
"someExamples": "Một vài ví dụ về cách hiển thị thời gian:",
"units": {
"seconds": "Giây",
"minutes": "Phút",
@ -894,10 +894,7 @@
"color": "Thay đổi màu công việc này",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Phiên bản giao diện người dùng: {version}",
"apiVersion": "Phiên bản API: {version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "代码",
"quote": "引用",
"unorderedList": "无序列表",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "清除格式",
"link": "链接",
"image": "图片",
@ -566,14 +566,14 @@
"canuse": "你可以使用 Date Math 来筛选相对日期。",
"learnhow": "查看它如何工作",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math 允许你在使用过滤器时由 Vikunja 动态解析相对日期。",
"expression": "每个 Date Math 表达式以锚点日期开头,可以是 {0},也可以是以 {1} 结尾的日期文本。 这个锚点日期后可以跟一个或多个数学表达式。",
"similar": "这些表达式类似于 {0} 和 {1} 提供的表达式。",
"add1Day": "加一天",
"minus1Day": "减一天",
"roundDay": "往最近的那天舍入",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "支持的时间单位是:",
"someExamples": "时间表达式的一些例子:",
"units": {
"seconds": "秒数。",
"minutes": "分钟",
@ -894,10 +894,7 @@
"color": "更改此任务的颜色",
"move": "Move this task to another project",
"reminder": "管理此任务的提醒",
"description": "切换编辑时的任务描述",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "切换编辑时的任务描述"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "前端版本:{version}",
"apiVersion": "API 版本:{version}"
}
}
}

View File

@ -529,7 +529,7 @@
"code": "Code",
"quote": "Quote",
"unorderedList": "Unordered List",
"orderedList": "Ordered List",
"orderedList ": "Ordered List",
"cleanBlock": "Clean Block",
"link": "Link",
"image": "Image",
@ -566,14 +566,14 @@
"canuse": "You can use date math to filter for relative dates.",
"learnhow": "Check out how it works",
"title": "Date Math",
"intro": "Specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"intro": "Date Math allows you to specify relative dates which are resolved on the fly by Vikunja when applying the filter.",
"expression": "Each Date Math expression starts with an anchor date, which can either be {0}, or a date string ending with {1}. This anchor date can optionally be followed by one or more maths expressions.",
"similar": "These expressions are similar to the ones provided by {0} and {1}.",
"add1Day": "Add one day",
"minus1Day": "Subtract one day",
"roundDay": "Round down to the nearest day",
"supportedUnits": "Supported time units",
"someExamples": "Examples of time expressions",
"supportedUnits": "Supported time units are:",
"someExamples": "Some examples of time expressions:",
"units": {
"seconds": "Seconds",
"minutes": "Minutes",
@ -894,10 +894,7 @@
"color": "Change the color of this task",
"move": "Move this task to another project",
"reminder": "Manage reminders of this task",
"description": "Toggle editing of the task description",
"delete": "Delete this task",
"priority": "Change the priority of this task",
"favorite": "Mark this task as favorite / unfavorite"
"description": "Toggle editing of the task description"
},
"project": {
"title": "Project Views",
@ -1056,4 +1053,4 @@
"frontendVersion": "Frontend Version: {version}",
"apiVersion": "API Version: {version}"
}
}
}

View File

@ -5,7 +5,7 @@ import type { IUser } from '@/modelTypes/IUser'
import type { IFile } from '@/modelTypes/IFile'
import type { IAttachment } from '@/modelTypes/IAttachment'
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg','.jpeg', '.png', '.bmp', '.gif']
export const SUPPORTED_IMAGE_SUFFIX = ['.jpg', '.png', '.bmp', '.gif']
export default class AttachmentModel extends AbstractModel<IAttachment> implements IAttachment {
id = 0

View File

@ -438,50 +438,41 @@ describe('Parse Task Text', () => {
now.setFullYear(2021, 5, 24)
const cases = {
'06/08/2021': '2021-6-8',
'6/7/21': '2021-6-7',
'27/07/2021,': null,
'2021/07/06,': '2021-7-6',
'2021-07-06': '2021-7-6',
'27 jan': '2022-1-27',
'27/1': '2022-1-27',
'27/01': '2022-1-27',
'16/12': '2021-12-16',
'01/27': '2022-1-27',
'1/27': '2022-1-27',
'Jan 27': '2022-1-27',
'jan 27': '2022-1-27',
'feb 21': '2022-2-21',
'mar 21': '2022-3-21',
'apr 21': '2022-4-21',
'may 21': '2022-5-21',
'jun 21': '2022-6-21',
'jul 21': '2021-7-21',
'aug 21': '2021-8-21',
'sep 21': '2021-9-21',
'oct 21': '2021-10-21',
'nov 21': '2021-11-21',
'dec 21': '2021-12-21',
'Lorem Ipsum 06/08/2021 ad': '2021-6-8',
'Lorem Ipsum 6/7/21 ad': '2021-6-7',
'dolor sit amet 27/07/2021,': null,
'dolor sit amet 2021/07/06,': '2021-7-6',
'dolor sit amet 2021-07-06': '2021-7-6',
'dolor sit amet 27 jan': '2022-1-27',
'dolor sit amet 27/1': '2022-1-27',
'dolor sit amet 27/01': '2022-1-27',
'dolor sit amet 16/12': '2021-12-16',
'dolor sit amet 01/27': '2022-1-27',
'dolor sit amet 1/27': '2022-1-27',
'dolor sit amet Jan 27': '2022-1-27',
'dolor sit amet jan 27': '2022-1-27',
'dolor sit amet feb 21': '2022-2-21',
'dolor sit amet mar 21': '2022-3-21',
'dolor sit amet apr 21': '2022-4-21',
'dolor sit amet may 21': '2022-5-21',
'dolor sit amet jun 21': '2022-6-21',
'dolor sit amet jul 21': '2021-7-21',
'dolor sit amet aug 21': '2021-8-21',
'dolor sit amet sep 21': '2021-9-21',
'dolor sit amet oct 21': '2021-10-21',
'dolor sit amet nov 21': '2021-11-21',
'dolor sit amet dec 21': '2021-12-21',
} as Record<string, string | null>
for (const c in cases) {
it(`should parse '${c}' as '${cases[c]}' with the date at the end`, () => {
const {date} = getDateFromText(`Lorem Ipsum ${c}`, now)
it(`should parse '${c}' as '${cases[c]}'`, () => {
const {date} = getDateFromText(c, now)
if (date === null && cases[c] === null) {
expect(date).toBeNull()
return
}
expect(`${date?.getFullYear()}-${date?.getMonth() + 1}-${date?.getDate()}`).toBe(cases[c])
})
it(`should parse '${c}' as '${cases[c]}' with the date at the beginning`, () => {
const {date} = getDateFromText(`${c} Lorem Ipsum`, now)
if (date === null && cases[c] === null) {
expect(date).toBeNull()
return
}
expect(`${date?.getFullYear()}-${date?.getMonth() + 1}-${date?.getDate()}`).toBe(cases[c])
expect(`${date?.getFullYear()}-${date.getMonth() + 1}-${date?.getDate()}`).toBe(cases[c])
})
}
})

View File

@ -6,6 +6,7 @@ import {saveProjectView, getProjectView} from '@/helpers/projectView'
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
import {getNextWeekDate} from '@/helpers/time/getNextWeekDate'
import {setTitle} from '@/helpers/setTitle'
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
import {useProjectStore} from '@/stores/projects'
import {useAuthStore} from '@/stores/auth'
@ -89,7 +90,7 @@ const router = createRouter({
}
// Scroll to anchor should still work
if (to.hash) {
if (to.hash && !to.hash.startsWith(LINK_SHARE_HASH_PREFIX)) {
return {el: to.hash}
}
@ -485,8 +486,7 @@ const router = createRouter({
],
})
export async function getAuthForRoute(route: RouteLocation) {
const authStore = useAuthStore()
export async function getAuthForRoute(to: RouteLocation, authStore) {
if (authStore.authUser || authStore.authLinkShare) {
return
}
@ -507,26 +507,52 @@ export async function getAuthForRoute(route: RouteLocation) {
'user.register',
'link-share.auth',
'openid.auth',
].includes(route.name as string) &&
].includes(to.name as string) &&
localStorage.getItem('passwordResetToken') === null &&
localStorage.getItem('emailConfirmToken') === null &&
!(route.name === 'home' && (typeof route.query.userPasswordReset !== 'undefined' || typeof route.query.userEmailConfirm !== 'undefined'))
!(to.name === 'home' && (typeof to.query.userPasswordReset !== 'undefined' || typeof to.query.userEmailConfirm !== 'undefined'))
) {
saveLastVisited(route.name as string, route.params, route.query)
saveLastVisited(to.name as string, to.params, to.query)
return {name: 'user.login'}
}
if(localStorage.getItem('passwordResetToken') !== null && route.name !== 'user.password-reset.reset') {
if(localStorage.getItem('passwordResetToken') !== null && to.name !== 'user.password-reset.reset') {
return {name: 'user.password-reset.reset'}
}
if(localStorage.getItem('emailConfirmToken') !== null && route.name !== 'user.login') {
if(localStorage.getItem('emailConfirmToken') !== null && to.name !== 'user.login') {
return {name: 'user.login'}
}
}
router.beforeEach(async (to) => {
return getAuthForRoute(to)
router.beforeEach(async (to, from) => {
const authStore = useAuthStore()
if(from.hash && from.hash.startsWith(LINK_SHARE_HASH_PREFIX)) {
to.hash = from.hash
}
if (to.hash.startsWith(LINK_SHARE_HASH_PREFIX) && !authStore.authLinkShare) {
saveLastVisited(to.name as string, to.params, to.query)
return {
name: 'link-share.auth',
params: {
share: to.hash.replace(LINK_SHARE_HASH_PREFIX, ''),
},
}
}
const newRoute = await getAuthForRoute(to, authStore)
if(newRoute) {
return {
...newRoute,
hash: to.hash,
}
}
if(!to.fullPath.endsWith(to.hash)) {
return to.fullPath + to.hash
}
})
export default router

View File

@ -40,12 +40,15 @@ import {useTitle} from '@vueuse/core'
import Message from '@/components/misc/message.vue'
import {PROJECT_VIEWS, type ProjectView} from '@/types/ProjectView'
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth'
import {useRedirectToLastVisited} from '@/composables/useRedirectToLastVisited'
const {t} = useI18n({useScope: 'global'})
useTitle(t('sharing.authenticating'))
const {getLastVisitedRoute} = useRedirectToLastVisited()
function useAuth() {
const baseStore = useBaseStore()
@ -87,7 +90,21 @@ function useAuth() {
? route.query.view
: 'list'
router.push({name: `project.${view}`, params: {projectId}})
const hash = LINK_SHARE_HASH_PREFIX + route.params.share
const last = getLastVisitedRoute()
if (last) {
return router.push({
...last,
hash,
})
}
return router.push({
name: `project.${view}`,
params: {projectId},
hash,
})
} catch (e: any) {
if (e.response?.data?.code === 13001) {
authenticateWithPassword.value = true

View File

@ -322,7 +322,6 @@
@click="setFieldActive('priority')"
variant="secondary"
icon="exclamation"
v-shortcut="'p'"
>
{{ $t('task.detail.actions.priority') }}
</x-button>
@ -407,7 +406,6 @@
@click="toggleFavorite"
variant="secondary"
:icon="task.isFavorite ? 'star' : ['far', 'star']"
v-shortcut="'s'"
>
{{
task.isFavorite ? $t('task.detail.actions.unfavorite') : $t('task.detail.actions.favorite')
@ -418,7 +416,6 @@
icon="trash-alt"
:shadow="false"
class="is-danger is-outlined has-no-border"
v-shortcut="'Shift+Delete'"
>
{{ $t('task.detail.actions.delete') }}
</x-button>

View File

@ -73,11 +73,7 @@
:search-results="foundUsers"
label="username"
v-model="newMember"
>
<template #searchResult="{option: user}">
<User :avatar-size="24" :user="user" class="m-0"/>
</template>
</multiselect>
/>
</div>
<div class="control">
<x-button @click="addUser" icon="plus">
@ -92,9 +88,7 @@
<table class="table has-actions is-striped is-hoverable is-fullwidth">
<tbody>
<tr :key="m.id" v-for="m in team?.members">
<td>
<User :avatar-size="24" :user="m" class="m-0"/>
</td>
<td>{{ getDisplayName(m) }}</td>
<td>
<template v-if="m.id === userInfo.id">
<b class="is-success">You</b>
@ -191,7 +185,6 @@ import {useRoute, useRouter} from 'vue-router'
import Editor from '@/components/input/AsyncEditor'
import Multiselect from '@/components/input/multiselect.vue'
import User from '@/components/misc/user.vue'
import TeamService from '@/services/team'
import TeamMemberService from '@/services/teamMember'
@ -201,6 +194,7 @@ import {RIGHTS as Rights} from '@/constants/rights'
import {useTitle} from '@/composables/useTitle'
import {success} from '@/message'
import {getDisplayName} from '@/models/user'
import {useAuthStore} from '@/stores/auth'
import type {ITeam} from '@/modelTypes/ITeam'

View File

@ -11,17 +11,17 @@
{{ $t('user.auth.login') }}
</x-button>
</div>
<form @submit.prevent="resetPassword" id="form" v-if="!successMessage">
<form @submit.prevent="submit" id="form" v-if="!successMessage">
<div class="field">
<label class="label" for="password">{{ $t('user.auth.password') }}</label>
<Password @submit="resetPassword" @update:modelValue="v => credentials.password = v"/>
<Password @submit="submit" @update:modelValue="v => credentials.password = v"/>
</div>
<div class="field is-grouped">
<div class="control">
<x-button
:loading="passwordResetService.loading"
@click="resetPassword"
@click="submit"
>
{{ $t('user.auth.resetPassword') }}
</x-button>
@ -47,7 +47,7 @@ const passwordResetService = reactive(new PasswordResetService())
const errorMsg = ref('')
const successMessage = ref('')
async function resetPassword() {
async function submit() {
errorMsg.value = ''
if(credentials.password === '') {

View File

@ -11,7 +11,7 @@
{{ $t('user.auth.login') }}
</x-button>
</div>
<form @submit.prevent="requestPasswordReset" v-if="!isSuccess">
<form @submit.prevent="submit" v-if="!isSuccess">
<div class="field">
<label class="label" for="email">{{ $t('user.auth.email') }}</label>
<div class="control">
@ -30,7 +30,7 @@
<div class="field is-grouped">
<div class="control">
<x-button
type="submit"
@click="submit"
:loading="passwordResetService.loading"
>
{{ $t('user.auth.resetPasswordAction') }}
@ -45,18 +45,19 @@
</template>
<script setup lang="ts">
import {ref, shallowReactive} from 'vue'
import {ref, reactive} from 'vue'
import PasswordResetModel from '@/models/passwordReset'
import PasswordResetService from '@/services/passwordReset'
import Message from '@/components/misc/message.vue'
const passwordResetService = shallowReactive(new PasswordResetService())
// Not sure if this instance needs a shalloRef at all
const passwordResetService = reactive(new PasswordResetService())
const passwordReset = ref(new PasswordResetModel())
const errorMsg = ref('')
const isSuccess = ref(false)
async function requestPasswordReset() {
async function submit() {
errorMsg.value = ''
try {
await passwordResetService.requestResetPassword(passwordReset.value)

View File

@ -1,5 +1,5 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"extends": "@vue/tsconfig/tsconfig.web.json",
"include": ["env.d.ts", "src/**/*.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.json"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {

View File

@ -1,8 +1,5 @@
{
"extends": [
"@tsconfig/node18/tsconfig.json",
"@vue/tsconfig/tsconfig.json"
],
"extends": "@vue/tsconfig/tsconfig.node.json",
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "env.config.d.ts"],
"compilerOptions": {
"composite": true,

View File

@ -60,7 +60,6 @@ export default defineConfig(({mode}) => {
// https://vitest.dev/config/
test: {
environment: 'happy-dom',
'vitest.commandLine': 'pnpm test:unit',
},
css: {
preprocessorOptions: {