Merge branch 'main' into feature/ganttastic
Some checks failed
continuous-integration/drone/pr Build is failing

# Conflicts:
#	pnpm-lock.yaml
This commit is contained in:
Dominik Pschenitschni 2022-09-28 18:00:32 +02:00
commit a1e280e47b
Signed by: dpschen
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 PNPM_CACHE_FOLDER: .cache/pnpm
CYPRESS_CACHE_FOLDER: .cache/cypress CYPRESS_CACHE_FOLDER: .cache/cypress
commands: 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 install --fetch-timeout 100000
# depends_on: # depends_on:
# - restore-cache # - restore-cache
@ -57,7 +57,7 @@ steps:
environment: environment:
PNPM_CACHE_FOLDER: .cache/pnpm PNPM_CACHE_FOLDER: .cache/pnpm
commands: 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 - pnpm run lint
depends_on: depends_on:
- dependencies - dependencies
@ -68,7 +68,7 @@ steps:
environment: environment:
PNPM_CACHE_FOLDER: .cache/pnpm PNPM_CACHE_FOLDER: .cache/pnpm
commands: 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 - pnpm run build
depends_on: depends_on:
- dependencies - dependencies
@ -77,7 +77,7 @@ steps:
image: node:18-alpine image: node:18-alpine
pull: true pull: true
commands: 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 - pnpm run test:unit
depends_on: depends_on:
- dependencies - dependencies
@ -89,7 +89,7 @@ steps:
environment: environment:
PNPM_CACHE_FOLDER: .cache/pnpm PNPM_CACHE_FOLDER: .cache/pnpm
commands: 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 - pnpm run typecheck
depends_on: depends_on:
- dependencies - dependencies
@ -107,7 +107,7 @@ steps:
from_secret: cypress_project_key from_secret: cypress_project_key
commands: commands:
- sed -i 's/localhost/api/g' dist/index.html - sed -i 's/localhost/api/g' dist/index.html
- 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 cypress install
- pnpm run serve:dist & npx wait-on http://localhost:4173 - pnpm run serve:dist & npx wait-on http://localhost:4173
- pnpm run test:frontend --browser chrome --record - pnpm run test:frontend --browser chrome --record
@ -202,7 +202,7 @@ steps:
environment: environment:
PNPM_CACHE_FOLDER: .cache/pnpm PNPM_CACHE_FOLDER: .cache/pnpm
commands: 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 install --fetch-timeout 100000
- pnpm run lint - pnpm run lint
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json" - "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: environment:
PNPM_CACHE_FOLDER: .cache/pnpm PNPM_CACHE_FOLDER: .cache/pnpm
commands: 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 install --fetch-timeout 100000
- pnpm run lint - pnpm run lint
- "echo '{\"VERSION\": \"'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'\"}' > src/version.json" - "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 from_secret: crowdin_key
--- ---
kind: signature kind: signature
hmac: 9eccb4a9999236be0f772c4cbe7ccce2875faa57f32de179bd75cf0df4124d00 hmac: c885a0e50db729842402494aa645dd3ac662828b691108550f6bf302158295ba
... ...

View File

@ -21,16 +21,17 @@ COPY pnpm-lock.yaml ./
RUN \ RUN \
# https://pnpm.io/installation#using-corepack # https://pnpm.io/installation#using-corepack
corepack enable && \ 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 # Build the frontend
pnpm fetch pnpm fetch --prod
ADD . ./ ADD . ./
RUN apk add --no-cache git RUN apk add --no-cache git
RUN \ 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 && \ echo '{"VERSION": "'$(git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')'"}' > src/version.json && \
pnpm run build pnpm run build

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -23,7 +23,7 @@
</div> </div>
</div> </div>
<div class="api-url-info" v-else> <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> <span class="url" v-tooltip="apiUrl"> {{ apiDomain }} </span>
</i18n-t> </i18n-t>
<br/> <br/>

View File

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

View File

@ -92,7 +92,7 @@
</p> </p>
<p class="mb-2"> <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> <strong>{{ s.sharedBy.getDisplayName() }}</strong>
</i18n-t> </i18n-t>
</p> </p>

View File

@ -38,7 +38,7 @@
<div class="filename">{{ a.file.name }}</div> <div class="filename">{{ a.file.name }}</div>
<div class="info"> <div class="info">
<p class="attachment-info-meta"> <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)"> <span v-tooltip="formatDateLong(a.created)">
{{ formatDateSince(a.created) }} {{ formatDateSince(a.created) }}
</span> </span>

View File

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

View File

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

View File

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

View File

@ -10,9 +10,12 @@
class="control is-expanded" class="control is-expanded"
:class="{ 'is-loading': namespaceService.loading }" :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 <input
@keyup.enter="newNamespace()" @keyup.enter="newNamespace()"
@keyup.esc="back()" @keyup.esc="$router.back()"
class="input" class="input"
:placeholder="$t('namespace.attributes.titlePlaceholder')" :placeholder="$t('namespace.attributes.titlePlaceholder')"
type="text" type="text"
@ -40,48 +43,42 @@
</create-edit> </create-edit>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import {defineComponent} from 'vue' import {ref, shallowReactive} from 'vue'
import {useI18n} from 'vue-i18n'
import {useRouter} from 'vue-router'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import NamespaceModel from '../../models/namespace'
import NamespaceService from '../../services/namespace'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
import ColorPicker from '../../components/input/colorPicker.vue' import ColorPicker from '@/components/input/colorPicker.vue'
import { setTitle } from '@/helpers/setTitle'
import {useNamespaceStore} from '@/stores/namespaces'
export default defineComponent({ import NamespaceModel from '@/models/namespace'
name: 'NewNamespace', import NamespaceService from '@/services/namespace'
data() { import {useNamespaceStore} from '@/stores/namespaces'
return { import type {INamespace} from '@/modelTypes/INamespace'
showError: false,
namespace: new NamespaceModel(), import {useTitle} from '@/composables/useTitle'
namespaceService: new NamespaceService(), import {success} from '@/message'
}
}, const showError = ref(false)
components: { const namespace = ref<INamespace>(new NamespaceModel())
Message, const namespaceService = shallowReactive(new NamespaceService())
ColorPicker,
CreateEdit, const {t} = useI18n({useScope: 'global'})
}, const router = useRouter()
mounted() {
setTitle(this.$t('namespace.create.title')) useTitle(() => t('namespace.create.title'))
},
methods: { async function newNamespace() {
async newNamespace() { if (namespace.value.title === '') {
if (this.namespace.title === '') { showError.value = true
this.showError = true
return return
} }
this.showError = false showError.value = false
const namespace = await this.namespaceService.create(this.namespace) const newNamespace = await namespaceService.create(namespace.value)
const namespaceStore = useNamespaceStore() useNamespaceStore().addNamespace(newNamespace)
namespaceStore.addNamespace(namespace) success({message: t('namespace.create.success')})
this.$message.success({message: this.$t('namespace.create.success')}) router.back()
this.$router.back() }
},
},
})
</script> </script>

View File

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