Merge branch 'main' into feature/ganttastic

# Conflicts:
#	pnpm-lock.yaml
This commit is contained in:
Dominik Pschenitschni 2022-09-28 18:00:32 +02:00
commit a1e280e47b
No known key found for this signature in database
GPG key ID: B257AC0149F43A77
15 changed files with 364 additions and 312 deletions

View file

@ -46,7 +46,7 @@ steps:
PNPM_CACHE_FOLDER: .cache/pnpm
CYPRESS_CACHE_FOLDER: .cache/cypress
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm install --fetch-timeout 100000
# depends_on:
# - restore-cache
@ -57,7 +57,7 @@ steps:
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm run lint
depends_on:
- dependencies
@ -68,7 +68,7 @@ steps:
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm run build
depends_on:
- dependencies
@ -77,7 +77,7 @@ steps:
image: node:18-alpine
pull: true
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm run test:unit
depends_on:
- dependencies
@ -89,7 +89,7 @@ steps:
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm run typecheck
depends_on:
- dependencies
@ -107,7 +107,7 @@ steps:
from_secret: cypress_project_key
commands:
- sed -i 's/localhost/api/g' dist/index.html
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm cypress install
- pnpm run serve:dist & npx wait-on http://localhost:4173
- pnpm run test:frontend --browser chrome --record
@ -202,7 +202,7 @@ steps:
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/.pnp
- corepack enable && pnpm config set store-dir .cache/.pnp
- pnpm install --fetch-timeout 100000
- pnpm run lint
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json"
@ -278,7 +278,7 @@ steps:
environment:
PNPM_CACHE_FOLDER: .cache/pnpm
commands:
- corepack enable && corepack prepare pnpm@7.9.3 --activate && pnpm config set store-dir .cache/pnpm
- corepack enable && pnpm config set store-dir .cache/pnpm
- pnpm install --fetch-timeout 100000
- pnpm run lint
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json"
@ -659,6 +659,6 @@ steps:
from_secret: crowdin_key
---
kind: signature
hmac: 9eccb4a9999236be0f772c4cbe7ccce2875faa57f32de179bd75cf0df4124d00
hmac: c885a0e50db729842402494aa645dd3ac662828b691108550f6bf302158295ba
...

View file

@ -21,16 +21,17 @@ COPY pnpm-lock.yaml ./
RUN \
# https://pnpm.io/installation#using-corepack
corepack enable && \
corepack prepare pnpm@7.9.3 --activate && \
# we don't use corepack prepare here by intend since
# we have renovate to keep our dependencies up to date
# Build the frontend
pnpm fetch
pnpm fetch --prod
ADD . ./
RUN apk add --no-cache git
RUN \
pnpm install --offline && \
pnpm install -r --offline --prod && \
echo '{"VERSION": "'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'"}' > src/version.json && \
pnpm run build

View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vikunja</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Vikunja</title>
<meta name="description" content="Vikunja (/vɪˈkuːnjə/) - The to-do app to organize your life.">
<meta name="theme-color" content="#1973ff"/>

View file

@ -25,15 +25,15 @@
"@github/hotkey": "2.0.1",
"@infectoone/vue-ganttastic": "^2.0.4",
"@kyvg/vue3-notification": "2.4.1",
"@sentry/tracing": "7.13.0",
"@sentry/vue": "7.13.0",
"@sentry/tracing": "7.14.0",
"@sentry/vue": "7.14.0",
"@types/is-touch-device": "1.0.0",
"@types/lodash.clonedeep": "4.5.7",
"@types/sortablejs": "1.15.0",
"@vueuse/core": "9.3.0",
"@vueuse/router": "9.3.0",
"axios": "0.27.2",
"blurhash": "2.0.1",
"blurhash": "2.0.2",
"bulma-css-variables": "0.9.33",
"camel-case": "4.1.2",
"codemirror": "5.65.9",
@ -54,7 +54,7 @@
"sortablejs": "1.15.0",
"ufo": "0.8.5",
"v-tooltip": "4.0.0-beta.17",
"vue": "3.2.39",
"vue": "3.2.40",
"vue-advanced-cropper": "2.8.3",
"vue-flatpickr-component": "9.0.6",
"vue-i18n": "9.2.2",
@ -70,6 +70,7 @@
"@faker-js/faker": "7.5.0",
"@types/dompurify": "2.3.4",
"@types/flexsearch": "0.7.3",
"@types/node": "16.11.62",
"@typescript-eslint/eslint-plugin": "5.38.1",
"@typescript-eslint/parser": "5.38.1",
"@vitejs/plugin-legacy": "2.2.0",
@ -80,7 +81,7 @@
"autoprefixer": "10.4.12",
"browserslist": "4.21.4",
"caniuse-lite": "1.0.30001412",
"cypress": "10.8.0",
"cypress": "10.9.0",
"esbuild": "0.15.9",
"eslint": "8.24.0",
"eslint-plugin-vue": "9.5.1",
@ -92,8 +93,8 @@
"rollup": "2.79.1",
"rollup-plugin-visualizer": "5.8.2",
"sass": "1.55.0",
"typescript": "4.8.3",
"vite": "3.1.3",
"typescript": "4.8.4",
"vite": "3.1.4",
"vite-plugin-pwa": "0.13.1",
"vite-svg-loader": "3.6.0",
"vitest": "0.23.4",

File diff suppressed because it is too large Load diff

View file

@ -6,13 +6,13 @@
{{ $t('input.datemathHelp.intro') }}
</p>
<p>
<i18n-t keypath="input.datemathHelp.expression">
<i18n-t keypath="input.datemathHelp.expression" scope="global">
<code>now</code>
<code>||</code>
</i18n-t>
</p>
<p>
<i18n-t keypath="input.datemathHelp.similar">
<i18n-t keypath="input.datemathHelp.similar" scope="global">
<BaseButton
href="https://grafana.com/docs/grafana/latest/dashboards/time-range-controls/"
target="_blank">
@ -99,7 +99,7 @@
<tr>
<td><code>{{ exampleDate }}||+1M/d</code></td>
<td>
<i18n-t keypath="input.datemathHelp.examples.datePlusMonth">
<i18n-t keypath="input.datemathHelp.examples.datePlusMonth" scope="global">
<code>{{ exampleDate }}</code>
</i18n-t>
</td>

View file

@ -23,7 +23,7 @@
</div>
</div>
<div class="api-url-info" v-else>
<i18n-t keypath="apiConfig.use">
<i18n-t keypath="apiConfig.use" scope="global">
<span class="url" v-tooltip="apiUrl"> {{ apiDomain }} </span>
</i18n-t>
<br/>

View file

@ -1,6 +1,6 @@
<template>
<message variant="danger">
<i18n-t keypath="loadingError.failed">
<i18n-t keypath="loadingError.failed" scope="global">
<ButtonLink @click="reload">{{ $t('loadingError.tryAgain') }}</ButtonLink>
<ButtonLink href="https://vikunja.io/contact/">{{ $t('loadingError.contact') }}</ButtonLink>
</i18n-t>

View file

@ -92,7 +92,7 @@
</p>
<p class="mb-2">
<i18n-t keypath="list.share.links.sharedBy">
<i18n-t keypath="list.share.links.sharedBy" scope="global">
<strong>{{ s.sharedBy.getDisplayName() }}</strong>
</i18n-t>
</p>

View file

@ -38,7 +38,7 @@
<div class="filename">{{ a.file.name }}</div>
<div class="info">
<p class="attachment-info-meta">
<i18n-t keypath="task.attachment.createdBy">
<i18n-t keypath="task.attachment.createdBy" scope="global">
<span v-tooltip="formatDateLong(a.created)">
{{ formatDateSince(a.created) }}
</span>

View file

@ -1,7 +1,7 @@
<template>
<p class="created">
<time :datetime="formatISO(task.created)" v-tooltip="formatDateLong(task.created)">
<i18n-t keypath="task.detail.created">
<i18n-t keypath="task.detail.created" scope="global">
<span>{{ formatDateSince(task.created) }}</span>
{{ task.createdBy.getDisplayName() }}
</i18n-t>
@ -10,7 +10,7 @@
<br/>
<!-- Computed properties to show the actual date every time it gets updated -->
<time :datetime="formatISO(task.updated)" v-tooltip="updatedFormatted">
<i18n-t keypath="task.detail.updated">
<i18n-t keypath="task.detail.updated" scope="global">
<span>{{ updatedSince }}</span>
</i18n-t>
</time>
@ -18,7 +18,7 @@
<template v-if="task.done">
<br/>
<time :datetime="formatISO(task.doneAt)" v-tooltip="doneFormatted">
<i18n-t keypath="task.detail.doneAt">
<i18n-t keypath="task.detail.doneAt" scope="global">
<span>{{ doneSince }}</span>
</i18n-t>
</time>

View file

@ -1,6 +1,8 @@
import AbstractService from './abstractService'
import {downloadBlob} from '../helpers/downloadBlob'
const DOWNLOAD_NAME = 'vikunja-export.zip'
export default class DataExportService extends AbstractService {
request(password: string) {
return this.post('/user/export/request', {password})
@ -10,7 +12,7 @@ export default class DataExportService extends AbstractService {
const clear = this.setLoading()
try {
const url = await this.getBlobUrl('/user/export/download', 'POST', {password})
downloadBlob(url, 'vikunja-export.zip')
downloadBlob(url, DOWNLOAD_NAME)
} finally {
clear()
}

View file

@ -34,52 +34,43 @@
</create-edit>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
import {mapState} from 'pinia'
<script setup lang="ts">
import {computed, ref} from 'vue'
import {useI18n} from 'vue-i18n'
import {useRouter} from 'vue-router'
import LabelModel from '../../models/label'
import CreateEdit from '@/components/misc/create-edit.vue'
import ColorPicker from '../../components/input/colorPicker.vue'
import { setTitle } from '@/helpers/setTitle'
import { useLabelStore } from '@/stores/labels'
import ColorPicker from '@/components/input/colorPicker.vue'
export default defineComponent({
name: 'NewLabel',
data() {
return {
label: new LabelModel(),
showError: false,
}
},
components: {
CreateEdit,
ColorPicker,
},
mounted() {
setTitle(this.$t('label.create.title'))
},
computed: {
...mapState(useLabelStore, {
loading: state => state.isLoading,
}),
},
methods: {
async newLabel() {
if (this.label.title === '') {
this.showError = true
import LabelModel from '@/models/label'
import {useLabelStore} from '@/stores/labels'
import {useTitle} from '@/composables/useTitle'
import {success} from '@/message'
const router = useRouter()
const {t} = useI18n({useScope: 'global'})
useTitle(() => t('label.create.title'))
const labelStore = useLabelStore()
const label = ref(new LabelModel())
const showError = ref(false)
const loading = computed(() => labelStore.isLoading)
async function newLabel() {
if (label.value.title === '') {
showError.value = true
return
}
this.showError = false
showError.value = false
const labelStore = useLabelStore()
const label = labelStore.createLabel(this.label)
this.$router.push({
const newLabel = labelStore.createLabel(label.value)
router.push({
name: 'labels.index',
params: {id: label.id},
params: {id: newLabel.id},
})
this.$message.success({message: this.$t('label.create.success')})
},
},
})
success({message: t('label.create.success')})
}
</script>

View file

@ -10,9 +10,12 @@
class="control is-expanded"
:class="{ 'is-loading': namespaceService.loading }"
>
<!-- The user should be able to close the modal by pressing escape - that already works with the default modal.
But with the input modal here since it autofocuses the input that input field catches the focus instead.
Hence we place the listener on the input field directly. -->
<input
@keyup.enter="newNamespace()"
@keyup.esc="back()"
@keyup.esc="$router.back()"
class="input"
:placeholder="$t('namespace.attributes.titlePlaceholder')"
type="text"
@ -40,48 +43,42 @@
</create-edit>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
<script setup lang="ts">
import {ref, shallowReactive} from 'vue'
import {useI18n} from 'vue-i18n'
import {useRouter} from 'vue-router'
import Message from '@/components/misc/message.vue'
import NamespaceModel from '../../models/namespace'
import NamespaceService from '../../services/namespace'
import CreateEdit from '@/components/misc/create-edit.vue'
import ColorPicker from '../../components/input/colorPicker.vue'
import { setTitle } from '@/helpers/setTitle'
import {useNamespaceStore} from '@/stores/namespaces'
import ColorPicker from '@/components/input/colorPicker.vue'
export default defineComponent({
name: 'NewNamespace',
data() {
return {
showError: false,
namespace: new NamespaceModel(),
namespaceService: new NamespaceService(),
}
},
components: {
Message,
ColorPicker,
CreateEdit,
},
mounted() {
setTitle(this.$t('namespace.create.title'))
},
methods: {
async newNamespace() {
if (this.namespace.title === '') {
this.showError = true
import NamespaceModel from '@/models/namespace'
import NamespaceService from '@/services/namespace'
import {useNamespaceStore} from '@/stores/namespaces'
import type {INamespace} from '@/modelTypes/INamespace'
import {useTitle} from '@/composables/useTitle'
import {success} from '@/message'
const showError = ref(false)
const namespace = ref<INamespace>(new NamespaceModel())
const namespaceService = shallowReactive(new NamespaceService())
const {t} = useI18n({useScope: 'global'})
const router = useRouter()
useTitle(() => t('namespace.create.title'))
async function newNamespace() {
if (namespace.value.title === '') {
showError.value = true
return
}
this.showError = false
showError.value = false
const namespace = await this.namespaceService.create(this.namespace)
const namespaceStore = useNamespaceStore()
namespaceStore.addNamespace(namespace)
this.$message.success({message: this.$t('namespace.create.success')})
this.$router.back()
},
},
})
const newNamespace = await namespaceService.create(namespace.value)
useNamespaceStore().addNamespace(newNamespace)
success({message: t('namespace.create.success')})
router.back()
}
</script>

View file

@ -25,7 +25,7 @@
{{ isLocalUser ? $t('user.settings.caldav.tokensHowTo') : $t('user.settings.caldav.mustUseToken') }}
<template v-if="!isLocalUser">
<br/>
<i18n-t keypath="user.settings.caldav.usernameIs">
<i18n-t keypath="user.settings.caldav.usernameIs" scope="global">
<strong>{{ username }}</strong>
</i18n-t>
</template>