Compare commits
41 Commits
553bfae534
...
248d2fe563
Author | SHA1 | Date |
---|---|---|
kolaente | 248d2fe563 | |
renovate | 0b36d28301 | |
renovate | da8cee0ba5 | |
renovate | 352381f377 | |
renovate | 61455b8795 | |
treysullivent | aceaccbf11 | |
kolaente | 392ce66edb | |
kolaente | ecbefdb921 | |
kolaente | d8ca1a2de1 | |
kolaente | 2d084c091e | |
kolaente | 5a84d37fca | |
kolaente | fd520dab0a | |
kolaente | 144a6e4140 | |
kolaente | a7aa74227a | |
kolaente | d2adbc53c6 | |
kolaente | 422e4371f8 | |
kolaente | 6e5b31f1e0 | |
kolaente | 5756da412b | |
kolaente | 4e05b8e97c | |
kolaente | 5177f516c4 | |
kolaente | 637c8f6ba5 | |
kolaente | 1460d212ee | |
kolaente | e9de7d8a24 | |
kolaente | ce1d7778c7 | |
kolaente | 9a16f6f817 | |
kolaente | 7d755fcb89 | |
kolaente | 77e95642a9 | |
kolaente | a5d02380a3 | |
kolaente | 3519b8b2fe | |
kolaente | cb648e5ad8 | |
kolaente | 75f830457b | |
kolaente | 6e2b540394 | |
kolaente | bf3c8ac9da | |
kolaente | 3e7225ebee | |
kolaente | 9eb19e0362 | |
kolaente | 73bf119409 | |
kolaente | 500b761fe6 | |
kolaente | 0bc9a670d7 | |
renovate | a3e5e98c64 | |
Elscrux | a3a4d05e89 | |
renovate | 72c3e1a03f |
|
@ -1400,6 +1400,6 @@ steps:
|
|||
- failure
|
||||
---
|
||||
kind: signature
|
||||
hmac: 2c9cb0483fb346988188515f6423929f46eefb9e14eb26b0f312a0b694d5fe8c
|
||||
hmac: f2753482faf9e2a3d34a9111587a75dfb4519cb77002cc64a51266540fd2478e
|
||||
|
||||
...
|
||||
|
|
|
@ -104,3 +104,7 @@ issues:
|
|||
text: "parameter 'tx' seems to be unused, consider removing or renaming it as"
|
||||
linters:
|
||||
- revive
|
||||
- path: pkg/models/typesense.go
|
||||
text: 'structtag: struct field Position repeats json tag "position" also at'
|
||||
linters:
|
||||
- govet
|
||||
|
|
|
@ -29,7 +29,7 @@ If you find any security-related issues you don't want to disclose publicly, ple
|
|||
|
||||
## Features
|
||||
|
||||
See [the features page](https://vikunja.io/features/) on our website for a more exaustive list or
|
||||
See [the features page](https://vikunja.io/features/) on our website for a more exhaustive list or
|
||||
try it on [try.vikunja.io](https://try.vikunja.io)!
|
||||
|
||||
## Docs
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "29.2.0",
|
||||
"electron": "29.3.0",
|
||||
"electron-builder": "24.13.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -769,10 +769,10 @@ electron-publish@24.13.1:
|
|||
lazy-val "^1.0.5"
|
||||
mime "^2.5.2"
|
||||
|
||||
electron@29.2.0:
|
||||
version "29.2.0"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-29.2.0.tgz#98e9d45dcebda124fb0bd1ff20fc509ec692101c"
|
||||
integrity sha512-ALKrCN52RG4g9prx4DriXSPnY5WoiyRUCNp7zEVQuoiNOpHTNqMMpRidQAHzntV4hajF1LMWHVoBkwqIs1jHhg==
|
||||
electron@29.3.0:
|
||||
version "29.3.0"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-29.3.0.tgz#8e65cb08e9c0952c66d3196e1b5c811c43b8c5b0"
|
||||
integrity sha512-ZxFKm0/v48GSoBuO3DdnMlCYXefEUKUHLMsKxyXY4nZGgzbBKpF/X8haZa2paNj23CLfsCKBOtfc2vsEQiOOsA==
|
||||
dependencies:
|
||||
"@electron/get" "^2.0.0"
|
||||
"@types/node" "^20.9.0"
|
||||
|
|
|
@ -18,6 +18,7 @@ To fully build Vikunja from source files, you need to build the api and frontend
|
|||
|
||||
1. Make sure you have git installed
|
||||
2. Clone the repo with `git clone https://code.vikunja.io/vikunja` and switch into the directory.
|
||||
3. Check out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use. If you don't do this, you'll build the [latest unstable build]({{< ref "versions.md">}}), which might contain bugs.
|
||||
|
||||
## Frontend
|
||||
|
||||
|
|
|
@ -225,10 +225,13 @@ go install github.com/magefile/mage
|
|||
```
|
||||
mkdir /mnt/GO/code.vikunja.io
|
||||
cd /mnt/GO/code.vikunja.io
|
||||
git clone https://code.vikunja.io/api
|
||||
cd /mnt/GO/code.vikunja.io/api
|
||||
git clone https://code.vikunja.io/vikunja
|
||||
cd vikunja
|
||||
```
|
||||
|
||||
**Note:** Ceck out the version you want to build with `git checkout VERSION` - replace `VERSION` with the version want to use.
|
||||
If you don't do this, you'll build the [latest unstable build]({{< ref "versions.md">}}), which might contain bugs.
|
||||
|
||||
### Compile binaries
|
||||
|
||||
```
|
||||
|
|
|
@ -13,6 +13,7 @@ import {BucketFactory} from '../../factories/bucket'
|
|||
import {TaskAttachmentFactory} from '../../factories/task_attachments'
|
||||
import {TaskReminderFactory} from '../../factories/task_reminders'
|
||||
import {createDefaultViews} from "../project/prepareProjects";
|
||||
import { TaskBucketFactory } from '../../factories/task_buckets'
|
||||
|
||||
function addLabelToTaskAndVerify(labelTitle: string) {
|
||||
cy.get('.task-view .action-buttons .button')
|
||||
|
@ -48,7 +49,7 @@ function uploadAttachmentAndVerify(taskId: number) {
|
|||
describe('Task', () => {
|
||||
createFakeUserAndLogin()
|
||||
|
||||
let projects
|
||||
let projects: {}[]
|
||||
let buckets
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -470,6 +471,10 @@ describe('Task', () => {
|
|||
})
|
||||
const labels = LabelFactory.create(1)
|
||||
LabelTaskFactory.truncate()
|
||||
TaskBucketFactory.create(1, {
|
||||
task_id: tasks[0].id,
|
||||
bucket_id: buckets[0].id,
|
||||
})
|
||||
|
||||
cy.visit(`/projects/${projects[0].id}/4`)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"homepage": "https://vikunja.io/",
|
||||
"funding": "https://opencollective.com/vikunja",
|
||||
"packageManager": "pnpm@8.15.6",
|
||||
"packageManager": "pnpm@8.15.7",
|
||||
"keywords": [
|
||||
"todo",
|
||||
"productivity",
|
||||
|
@ -58,8 +58,8 @@
|
|||
"@infectoone/vue-ganttastic": "2.3.2",
|
||||
"@intlify/unplugin-vue-i18n": "3.0.1",
|
||||
"@kyvg/vue3-notification": "3.2.1",
|
||||
"@sentry/tracing": "7.109.0",
|
||||
"@sentry/vue": "7.109.0",
|
||||
"@sentry/tracing": "7.110.1",
|
||||
"@sentry/vue": "7.110.1",
|
||||
"@tiptap/core": "2.3.0",
|
||||
"@tiptap/extension-blockquote": "2.3.0",
|
||||
"@tiptap/extension-bold": "2.3.0",
|
||||
|
@ -118,7 +118,7 @@
|
|||
"sortablejs": "1.15.2",
|
||||
"tippy.js": "6.3.7",
|
||||
"ufo": "1.5.3",
|
||||
"vue": "3.4.21",
|
||||
"vue": "3.4.23",
|
||||
"vue-advanced-cropper": "2.8.8",
|
||||
"vue-flatpickr-component": "11.0.5",
|
||||
"vue-i18n": "9.11.1",
|
||||
|
@ -134,7 +134,7 @@
|
|||
"@faker-js/faker": "8.4.1",
|
||||
"@histoire/plugin-screenshot": "0.17.17",
|
||||
"@histoire/plugin-vue": "0.17.17",
|
||||
"@rushstack/eslint-patch": "1.10.1",
|
||||
"@rushstack/eslint-patch": "1.10.2",
|
||||
"@tsconfig/node18": "18.2.4",
|
||||
"@types/codemirror": "5.60.15",
|
||||
"@types/dompurify": "3.0.5",
|
||||
|
|
|
@ -24,25 +24,25 @@ dependencies:
|
|||
version: 6.5.2
|
||||
'@fortawesome/vue-fontawesome':
|
||||
specifier: 3.0.6
|
||||
version: 3.0.6(@fortawesome/fontawesome-svg-core@6.5.2)(vue@3.4.21)
|
||||
version: 3.0.6(@fortawesome/fontawesome-svg-core@6.5.2)(vue@3.4.23)
|
||||
'@github/hotkey':
|
||||
specifier: 3.1.0
|
||||
version: 3.1.0(patch_hash=c67tdk7qpd5grxd2zj6lsxfbou)
|
||||
'@infectoone/vue-ganttastic':
|
||||
specifier: 2.3.2
|
||||
version: 2.3.2(dayjs@1.11.10)(vue@3.4.21)
|
||||
version: 2.3.2(dayjs@1.11.10)(vue@3.4.23)
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: 3.0.1
|
||||
version: 3.0.1(rollup@4.14.1)(vue-i18n@9.11.1)
|
||||
'@kyvg/vue3-notification':
|
||||
specifier: 3.2.1
|
||||
version: 3.2.1(vue@3.4.21)
|
||||
version: 3.2.1(vue@3.4.23)
|
||||
'@sentry/tracing':
|
||||
specifier: 7.109.0
|
||||
version: 7.109.0
|
||||
specifier: 7.110.1
|
||||
version: 7.110.1
|
||||
'@sentry/vue':
|
||||
specifier: 7.109.0
|
||||
version: 7.109.0(vue@3.4.21)
|
||||
specifier: 7.110.1
|
||||
version: 7.110.1(vue@3.4.23)
|
||||
'@tiptap/core':
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/pm@2.3.0)
|
||||
|
@ -141,7 +141,7 @@ dependencies:
|
|||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/vue-3':
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.21)
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.23)
|
||||
'@types/is-touch-device':
|
||||
specifier: 1.0.2
|
||||
version: 1.0.2
|
||||
|
@ -150,10 +150,10 @@ dependencies:
|
|||
version: 4.5.9
|
||||
'@vueuse/core':
|
||||
specifier: 10.9.0
|
||||
version: 10.9.0(vue@3.4.21)
|
||||
version: 10.9.0(vue@3.4.23)
|
||||
'@vueuse/router':
|
||||
specifier: 10.9.0
|
||||
version: 10.9.0(vue-router@4.3.0)(vue@3.4.21)
|
||||
version: 10.9.0(vue-router@4.3.0)(vue@3.4.23)
|
||||
axios:
|
||||
specifier: 1.6.8
|
||||
version: 1.6.8(debug@4.3.4)
|
||||
|
@ -186,7 +186,7 @@ dependencies:
|
|||
version: 0.7.31(patch_hash=bfn3sngfuhktmdj7jgl3ejl35y)
|
||||
floating-vue:
|
||||
specifier: 5.2.2
|
||||
version: 5.2.2(vue@3.4.21)
|
||||
version: 5.2.2(vue@3.4.23)
|
||||
is-touch-device:
|
||||
specifier: 1.0.1
|
||||
version: 1.0.1
|
||||
|
@ -201,7 +201,7 @@ dependencies:
|
|||
version: 2.9.0
|
||||
pinia:
|
||||
specifier: 2.1.7
|
||||
version: 2.1.7(typescript@5.4.5)(vue@3.4.21)
|
||||
version: 2.1.7(typescript@5.4.5)(vue@3.4.23)
|
||||
register-service-worker:
|
||||
specifier: 1.7.2
|
||||
version: 1.7.2
|
||||
|
@ -218,29 +218,29 @@ dependencies:
|
|||
specifier: 1.5.3
|
||||
version: 1.5.3
|
||||
vue:
|
||||
specifier: 3.4.21
|
||||
version: 3.4.21(typescript@5.4.5)
|
||||
specifier: 3.4.23
|
||||
version: 3.4.23(typescript@5.4.5)
|
||||
vue-advanced-cropper:
|
||||
specifier: 2.8.8
|
||||
version: 2.8.8(vue@3.4.21)
|
||||
version: 2.8.8(vue@3.4.23)
|
||||
vue-flatpickr-component:
|
||||
specifier: 11.0.5
|
||||
version: 11.0.5(vue@3.4.21)
|
||||
version: 11.0.5(vue@3.4.23)
|
||||
vue-i18n:
|
||||
specifier: 9.11.1
|
||||
version: 9.11.1(vue@3.4.21)
|
||||
version: 9.11.1(vue@3.4.23)
|
||||
vue-router:
|
||||
specifier: 4.3.0
|
||||
version: 4.3.0(vue@3.4.21)
|
||||
version: 4.3.0(vue@3.4.23)
|
||||
vuemoji-picker:
|
||||
specifier: 0.2.1
|
||||
version: 0.2.1(vue@3.4.21)
|
||||
version: 0.2.1(vue@3.4.23)
|
||||
workbox-precaching:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0
|
||||
zhyswan-vuedraggable:
|
||||
specifier: 4.1.3
|
||||
version: 4.1.3(vue@3.4.21)
|
||||
version: 4.1.3(vue@3.4.23)
|
||||
|
||||
devDependencies:
|
||||
'@4tw/cypress-drag-drop':
|
||||
|
@ -251,7 +251,7 @@ devDependencies:
|
|||
version: 5.0.7
|
||||
'@cypress/vue':
|
||||
specifier: 6.0.0
|
||||
version: 6.0.0(cypress@13.7.2)(vue@3.4.21)
|
||||
version: 6.0.0(cypress@13.7.2)(vue@3.4.23)
|
||||
'@faker-js/faker':
|
||||
specifier: 8.4.1
|
||||
version: 8.4.1
|
||||
|
@ -260,10 +260,10 @@ devDependencies:
|
|||
version: 0.17.17(histoire@0.17.17)
|
||||
'@histoire/plugin-vue':
|
||||
specifier: 0.17.17
|
||||
version: 0.17.17(histoire@0.17.17)(vite@5.2.8)(vue@3.4.21)
|
||||
version: 0.17.17(histoire@0.17.17)(vite@5.2.8)(vue@3.4.23)
|
||||
'@rushstack/eslint-patch':
|
||||
specifier: 1.10.1
|
||||
version: 1.10.1
|
||||
specifier: 1.10.2
|
||||
version: 1.10.2
|
||||
'@tsconfig/node18':
|
||||
specifier: 18.2.4
|
||||
version: 18.2.4
|
||||
|
@ -302,7 +302,7 @@ devDependencies:
|
|||
version: 5.3.2(terser@5.24.0)(vite@5.2.8)
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: 5.0.4
|
||||
version: 5.0.4(vite@5.2.8)(vue@3.4.21)
|
||||
version: 5.0.4(vite@5.2.8)(vue@3.4.23)
|
||||
'@vue/eslint-config-typescript':
|
||||
specifier: 13.0.0
|
||||
version: 13.0.0(eslint-plugin-vue@9.24.1)(eslint@8.57.0)(typescript@5.4.5)
|
||||
|
@ -389,7 +389,7 @@ devDependencies:
|
|||
version: 1.4.0(vite@5.2.8)
|
||||
vite-svg-loader:
|
||||
specifier: 5.1.0
|
||||
version: 5.1.0(vue@3.4.21)
|
||||
version: 5.1.0(vue@3.4.23)
|
||||
vitest:
|
||||
specifier: 1.4.0
|
||||
version: 1.4.0(@types/node@20.12.7)(happy-dom@14.7.1)(sass@1.74.1)(terser@5.24.0)
|
||||
|
@ -713,6 +713,13 @@ packages:
|
|||
dependencies:
|
||||
'@babel/types': 7.23.9
|
||||
|
||||
/@babel/parser@7.24.4:
|
||||
resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/types': 7.23.9
|
||||
|
||||
/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.23.9):
|
||||
resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
@ -2154,7 +2161,7 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@cypress/vue@6.0.0(cypress@13.7.2)(vue@3.4.21):
|
||||
/@cypress/vue@6.0.0(cypress@13.7.2)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-KMfRw8y/kXn/RJqaDdFnYnW7YLk47313UE3Yip+sLDjILJ2kA0WEiEa6MYKe58v8TNRtwcRpUH5xAYVNs1N6/A==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
|
@ -2166,7 +2173,7 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
cypress: 13.7.2
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: true
|
||||
|
||||
/@cypress/xvfb@1.2.4(supports-color@8.1.1):
|
||||
|
@ -2472,14 +2479,14 @@ packages:
|
|||
'@fortawesome/fontawesome-common-types': 6.5.2
|
||||
dev: false
|
||||
|
||||
/@fortawesome/vue-fontawesome@3.0.6(@fortawesome/fontawesome-svg-core@6.5.2)(vue@3.4.21):
|
||||
/@fortawesome/vue-fontawesome@3.0.6(@fortawesome/fontawesome-svg-core@6.5.2)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-akrL7lTroyNpPkoHtvK2UpsMzJr6jXdHaQ0YdcwqDsB8jdwlpNHZYijpOUd9KJsARr+VB3WXY4EyObepqJ4ytQ==}
|
||||
peerDependencies:
|
||||
'@fortawesome/fontawesome-svg-core': ~1 || ~6
|
||||
vue: '>= 3.0.0 < 4'
|
||||
dependencies:
|
||||
'@fortawesome/fontawesome-svg-core': 6.5.2
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/@github/hotkey@3.1.0(patch_hash=c67tdk7qpd5grxd2zj6lsxfbou):
|
||||
|
@ -2543,7 +2550,7 @@ packages:
|
|||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/@histoire/plugin-vue@0.17.17(histoire@0.17.17)(vite@5.2.8)(vue@3.4.21):
|
||||
/@histoire/plugin-vue@0.17.17(histoire@0.17.17)(vite@5.2.8)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-O5h/Ww6IT2CygVVT4onN27IZt11Z2qE8XeHeXJCEese3dxnnVWRhjMpsaWAU5XqgfjKNAiALJk86b49/6NQaRg==}
|
||||
peerDependencies:
|
||||
histoire: ^0.17.17
|
||||
|
@ -2557,7 +2564,7 @@ packages:
|
|||
histoire: 0.17.17(@types/node@20.12.7)(sass@1.74.1)(terser@5.24.0)(vite@5.2.8)
|
||||
launch-editor: 2.6.1
|
||||
pathe: 1.1.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- vite
|
||||
dev: true
|
||||
|
@ -2600,15 +2607,15 @@ packages:
|
|||
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
|
||||
dev: true
|
||||
|
||||
/@infectoone/vue-ganttastic@2.3.2(dayjs@1.11.10)(vue@3.4.21):
|
||||
/@infectoone/vue-ganttastic@2.3.2(dayjs@1.11.10)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-krxHdlZvo4cdS4axQ99qb756RzwieI7LcyY2vAIehJ5Sxd/jz5Pu/vTplTC0Rxqj8T4v1knYPK9uvTMkQYWYng==}
|
||||
peerDependencies:
|
||||
dayjs: ^1.11.5
|
||||
vue: ^3.2.40
|
||||
dependencies:
|
||||
'@vueuse/core': 9.13.0(vue@3.4.21)
|
||||
'@vueuse/core': 9.13.0(vue@3.4.23)
|
||||
dayjs: 1.11.10
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
dev: false
|
||||
|
@ -2634,7 +2641,7 @@ packages:
|
|||
magic-string: 0.30.7
|
||||
mlly: 1.4.2
|
||||
source-map-js: 1.2.0
|
||||
vue-i18n: 9.11.1(vue@3.4.21)
|
||||
vue-i18n: 9.11.1(vue@3.4.23)
|
||||
yaml-eslint-parser: 1.2.2
|
||||
dev: false
|
||||
|
||||
|
@ -2704,7 +2711,7 @@ packages:
|
|||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
unplugin: 1.1.0
|
||||
vue-i18n: 9.11.1(vue@3.4.21)
|
||||
vue-i18n: 9.11.1(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
@ -2761,12 +2768,12 @@ packages:
|
|||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
dev: true
|
||||
|
||||
/@kyvg/vue3-notification@3.2.1(vue@3.4.21):
|
||||
/@kyvg/vue3-notification@3.2.1(vue@3.4.23):
|
||||
resolution: {integrity: sha512-qn4bCBBCxW0Ya+RmHXu2SYBVwGXWsAGdlDKqCqyLryaZTbtFXi32iSSLnuKjSUVxFqQRToFc6g1zp1XLTyHrvw==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/@lezer/common@1.1.1:
|
||||
|
@ -3053,49 +3060,49 @@ packages:
|
|||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@rushstack/eslint-patch@1.10.1:
|
||||
resolution: {integrity: sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==}
|
||||
/@rushstack/eslint-patch@1.10.2:
|
||||
resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==}
|
||||
dev: true
|
||||
|
||||
/@sentry-internal/feedback@7.109.0:
|
||||
resolution: {integrity: sha512-EL7N++poxvJP9rYvh6vSu24tsKkOveNCcCj4IM7+irWPjsuD2GLYYlhp/A/Mtt9l7iqO4plvtiQU5HGk7smcTQ==}
|
||||
/@sentry-internal/feedback@7.110.1:
|
||||
resolution: {integrity: sha512-0aR3wuEW+SZKOVNamuy0pTQyPmqDjWPPLrB2GAXGT3ZjrVxjEzzVPqk6DVBYxSV2MuJaD507SZnvfoSPNgoBmw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry-internal/replay-canvas@7.109.0:
|
||||
resolution: {integrity: sha512-Lh/K60kmloR6lkPUcQP0iamw7B/MdEUEx/ImAx4tUSMrLj+IoUEcq/ECgnnVyQkJq59+8nPEKrVLt7x6PUPEjw==}
|
||||
/@sentry-internal/replay-canvas@7.110.1:
|
||||
resolution: {integrity: sha512-zdcCmWFXM4DHOau/BCZVb6jf9zozdbAiJ1MzQ6azuZEuysOl00YfktoWZBbZjjjpWT6025s+wrmFz54t0O+enw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/replay': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/replay': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry-internal/tracing@7.109.0:
|
||||
resolution: {integrity: sha512-PzK/joC5tCuh2R/PRh+7dp+uuZl7pTsBIjPhVZHMTtb9+ls65WkdZJ1/uKXPouyz8NOo9Xok7aEvEo9seongyw==}
|
||||
/@sentry-internal/tracing@7.110.1:
|
||||
resolution: {integrity: sha512-4kTd6EM0OP1SVWl2yLn3KIwlCpld1lyhNDeR8G1aKLm1PN+kVsR6YB/jy9KPPp4Q3lN3W9EkTSES3qhP4jVffQ==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/browser@7.109.0:
|
||||
resolution: {integrity: sha512-yx+OFG+Ab9qUDDgV9ZDv8M9O9Mqr0fjKta/LMlWALYLjzkMvxsPlRPFj7oMBlHqOTVLDeg7lFYmsA8wyWQ8Z8g==}
|
||||
/@sentry/browser@7.110.1:
|
||||
resolution: {integrity: sha512-H3TZlbdsgxuoVxhotMtBDemvAofx3UPNcS+UjQ40Bd+hKX01IIbEN3i+9RQ0jmcbU6xjf+yhjwp+Ejpm4FmYMw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@sentry-internal/feedback': 7.109.0
|
||||
'@sentry-internal/replay-canvas': 7.109.0
|
||||
'@sentry-internal/tracing': 7.109.0
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/replay': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry-internal/feedback': 7.110.1
|
||||
'@sentry-internal/replay-canvas': 7.110.1
|
||||
'@sentry-internal/tracing': 7.110.1
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/replay': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/cli@2.19.1:
|
||||
|
@ -3114,54 +3121,54 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@sentry/core@7.109.0:
|
||||
resolution: {integrity: sha512-xwD4U0IlvvlE/x/g/W1I8b4Cfb16SsCMmiEuBf6XxvAa3OfWBxKoqLifb3GyrbxMC4LbIIZCN/SvLlnGJPgszA==}
|
||||
/@sentry/core@7.110.1:
|
||||
resolution: {integrity: sha512-yC1yeUFQlmHj9u/KxKmwOMVanBmgfX+4MZnZU31QPqN95adyZTwpaYFZl4fH5kDVnz7wXJI0qRP8SxuMePtqhw==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/replay@7.109.0:
|
||||
resolution: {integrity: sha512-hCDjbTNO7ErW/XsaBXlyHFsUhneyBUdTec1Swf98TFEfVqNsTs6q338aUcaR8dGRLbLrJ9YU9D1qKq++v5h2CA==}
|
||||
/@sentry/replay@7.110.1:
|
||||
resolution: {integrity: sha512-R49fGOuKYsJ97EujPTzMjs3ZSuSkLTFFQmVBbsu/o6beRp4kK9l8H7r2BfLEcWJOXdWO5EU4KpRWgIxHaDK2aw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@sentry-internal/tracing': 7.109.0
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
'@sentry-internal/tracing': 7.110.1
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/tracing@7.109.0:
|
||||
resolution: {integrity: sha512-lgveekdd/XLgQ6oZLvcRGUWBIOAZ7QwbjLHEd8zzeKubHbIwFzMkhIejskqLi2z2OwzrYl5q+Zo1jS1z9f62YQ==}
|
||||
/@sentry/tracing@7.110.1:
|
||||
resolution: {integrity: sha512-y9tFHCV/8PeuV9TBOyMJ9w1vVOhkzoHy9d78eO5N3Q1lC+wImJSEBxb6aPcZ+RkuFBKSMm7fZTF3OFA32dHHLA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@sentry-internal/tracing': 7.109.0
|
||||
'@sentry-internal/tracing': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/types@7.109.0:
|
||||
resolution: {integrity: sha512-egCBnDv3YpVFoNzRLdP0soVrxVLCQ+rovREKJ1sw3rA2/MFH9WJ+DZZexsX89yeAFzy1IFsCp7/dEqudusml6g==}
|
||||
/@sentry/types@7.110.1:
|
||||
resolution: {integrity: sha512-sZxOpM5gfyxvJeWVvNpHnxERTnlqcozjqNcIv29SZ6wonlkekmxDyJ3uCuPv85VO54WLyA4uzskPKnNFHacI8A==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/@sentry/utils@7.109.0:
|
||||
resolution: {integrity: sha512-3RjxMOLMBwZ5VSiH84+o/3NY2An4Zldjz0EbfEQNRY9yffRiCPJSQiCJID8EoylCFOh/PAhPimBhqbtWJxX6iw==}
|
||||
/@sentry/utils@7.110.1:
|
||||
resolution: {integrity: sha512-eibLo2m1a7sHkOHxYYmRujr3D7ek2l9sv26F1SLoQBVDF7Afw5AKyzPmtA1D+4M9P/ux1okj7cGj3SaBrVpxXA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/types': 7.110.1
|
||||
dev: false
|
||||
|
||||
/@sentry/vue@7.109.0(vue@3.4.21):
|
||||
resolution: {integrity: sha512-aATuLXJB7YJaezedwP71sGeVabt9moyvxlZZdTU+LdgTizdMZk3zvWF/Uen6HGCgvKerDYt52zSHWSQvDHCvLw==}
|
||||
/@sentry/vue@7.110.1(vue@3.4.23):
|
||||
resolution: {integrity: sha512-+dS5gfr360wiWgdRMPgJHl+mF/44U1/H5CYwTL/a1X7psRY4NEQSo7oltAGeZc723hmlJubxmwJYU4xBWgaasw==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
vue: 2.x || 3.x
|
||||
dependencies:
|
||||
'@sentry/browser': 7.109.0
|
||||
'@sentry/core': 7.109.0
|
||||
'@sentry/types': 7.109.0
|
||||
'@sentry/utils': 7.109.0
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
'@sentry/browser': 7.110.1
|
||||
'@sentry/core': 7.110.1
|
||||
'@sentry/types': 7.110.1
|
||||
'@sentry/utils': 7.110.1
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/@sideway/address@4.1.3:
|
||||
|
@ -3529,7 +3536,7 @@ packages:
|
|||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/vue-3@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.21):
|
||||
/@tiptap/vue-3@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-Jgsoouq7gD6SkUf7McOJnKOHqVTVDJkPqhXZUZyJbJ22wD+7drxlauWwWexEymbs95ByhKblreLwcumvbOztgg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
|
@ -3540,7 +3547,7 @@ packages:
|
|||
'@tiptap/extension-bubble-menu': 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-floating-menu': 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/@tootallnate/once@2.0.0:
|
||||
|
@ -3913,7 +3920,7 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@vitejs/plugin-vue@5.0.4(vite@5.2.8)(vue@3.4.21):
|
||||
/@vitejs/plugin-vue@5.0.4(vite@5.2.8)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
|
@ -3921,7 +3928,7 @@ packages:
|
|||
vue: ^3.2.25
|
||||
dependencies:
|
||||
vite: 5.2.8(@types/node@20.12.7)(sass@1.74.1)(terser@5.24.0)
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: true
|
||||
|
||||
/@vitest/expect@1.4.0:
|
||||
|
@ -3991,12 +3998,27 @@ packages:
|
|||
estree-walker: 2.0.2
|
||||
source-map-js: 1.0.2
|
||||
|
||||
/@vue/compiler-core@3.4.23:
|
||||
resolution: {integrity: sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.24.4
|
||||
'@vue/shared': 3.4.23
|
||||
entities: 4.5.0
|
||||
estree-walker: 2.0.2
|
||||
source-map-js: 1.2.0
|
||||
|
||||
/@vue/compiler-dom@3.4.21:
|
||||
resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
|
||||
/@vue/compiler-dom@3.4.23:
|
||||
resolution: {integrity: sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw==}
|
||||
dependencies:
|
||||
'@vue/compiler-core': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
|
||||
/@vue/compiler-sfc@3.4.21:
|
||||
resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
|
||||
dependencies:
|
||||
|
@ -4009,12 +4031,33 @@ packages:
|
|||
magic-string: 0.30.7
|
||||
postcss: 8.4.38
|
||||
source-map-js: 1.2.0
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-sfc@3.4.23:
|
||||
resolution: {integrity: sha512-fSDTKTfzaRX1kNAUiaj8JB4AokikzStWgHooMhaxyjZerw624L+IAP/fvI4ZwMpwIh8f08PVzEnu4rg8/Npssw==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.24.4
|
||||
'@vue/compiler-core': 3.4.23
|
||||
'@vue/compiler-dom': 3.4.23
|
||||
'@vue/compiler-ssr': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.9
|
||||
postcss: 8.4.38
|
||||
source-map-js: 1.2.0
|
||||
|
||||
/@vue/compiler-ssr@3.4.21:
|
||||
resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
dev: false
|
||||
|
||||
/@vue/compiler-ssr@3.4.23:
|
||||
resolution: {integrity: sha512-hb6Uj2cYs+tfqz71Wj6h3E5t6OKvb4MVcM2Nl5i/z1nv1gjEhw+zYaNOV+Xwn+SSN/VZM0DgANw5TuJfxfezPg==}
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
|
||||
/@vue/devtools-api@6.5.0:
|
||||
resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==}
|
||||
|
@ -4063,36 +4106,39 @@ packages:
|
|||
vue-template-compiler: 2.7.14
|
||||
dev: true
|
||||
|
||||
/@vue/reactivity@3.4.21:
|
||||
resolution: {integrity: sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==}
|
||||
/@vue/reactivity@3.4.23:
|
||||
resolution: {integrity: sha512-GlXR9PL+23fQ3IqnbSQ8OQKLodjqCyoCrmdLKZk3BP7jN6prWheAfU7a3mrltewTkoBm+N7qMEb372VHIkQRMQ==}
|
||||
dependencies:
|
||||
'@vue/shared': 3.4.21
|
||||
'@vue/shared': 3.4.23
|
||||
|
||||
/@vue/runtime-core@3.4.21:
|
||||
resolution: {integrity: sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==}
|
||||
/@vue/runtime-core@3.4.23:
|
||||
resolution: {integrity: sha512-FeQ9MZEXoFzFkFiw9MQQ/FWs3srvrP+SjDKSeRIiQHIhtkzoj0X4rWQlRNHbGuSwLra6pMyjAttwixNMjc/xLw==}
|
||||
dependencies:
|
||||
'@vue/reactivity': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
'@vue/reactivity': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
|
||||
/@vue/runtime-dom@3.4.21:
|
||||
resolution: {integrity: sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==}
|
||||
/@vue/runtime-dom@3.4.23:
|
||||
resolution: {integrity: sha512-RXJFwwykZWBkMiTPSLEWU3kgVLNAfActBfWFlZd0y79FTUxexogd0PLG4HH2LfOktjRxV47Nulygh0JFXe5f9A==}
|
||||
dependencies:
|
||||
'@vue/runtime-core': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
'@vue/runtime-core': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
csstype: 3.1.3
|
||||
|
||||
/@vue/server-renderer@3.4.21(vue@3.4.21):
|
||||
resolution: {integrity: sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==}
|
||||
/@vue/server-renderer@3.4.23(vue@3.4.23):
|
||||
resolution: {integrity: sha512-LDwGHtnIzvKFNS8dPJ1SSU5Gvm36p2ck8wCZc52fc3k/IfjKcwCyrWEf0Yag/2wTFUBXrqizfhK9c/mC367dXQ==}
|
||||
peerDependencies:
|
||||
vue: 3.4.21
|
||||
vue: 3.4.23
|
||||
dependencies:
|
||||
'@vue/compiler-ssr': 3.4.21
|
||||
'@vue/shared': 3.4.21
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
'@vue/compiler-ssr': 3.4.23
|
||||
'@vue/shared': 3.4.23
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
|
||||
/@vue/shared@3.4.21:
|
||||
resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==}
|
||||
|
||||
/@vue/shared@3.4.23:
|
||||
resolution: {integrity: sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg==}
|
||||
|
||||
/@vue/test-utils@2.4.5:
|
||||
resolution: {integrity: sha512-oo2u7vktOyKUked36R93NB7mg2B+N7Plr8lxp2JBGwr18ch6EggFjixSCdIVVLkT6Qr0z359Xvnafc9dcKyDUg==}
|
||||
dependencies:
|
||||
|
@ -4104,25 +4150,25 @@ packages:
|
|||
resolution: {integrity: sha512-VcZK7MvpjuTPx2w6blwnwZAu5/LgBUtejFOi3pPGQFXQN5Ela03FUtd2Qtg4yWGGissVL0dr6Ro1LfOFh+PCuQ==}
|
||||
dev: true
|
||||
|
||||
/@vueuse/core@10.9.0(vue@3.4.21):
|
||||
/@vueuse/core@10.9.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==}
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.20
|
||||
'@vueuse/metadata': 10.9.0
|
||||
'@vueuse/shared': 10.9.0(vue@3.4.21)
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
'@vueuse/shared': 10.9.0(vue@3.4.23)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/core@9.13.0(vue@3.4.21):
|
||||
/@vueuse/core@9.13.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.16
|
||||
'@vueuse/metadata': 9.13.0
|
||||
'@vueuse/shared': 9.13.0(vue@3.4.21)
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
'@vueuse/shared': 9.13.0(vue@3.4.23)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
@ -4136,32 +4182,32 @@ packages:
|
|||
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/router@10.9.0(vue-router@4.3.0)(vue@3.4.21):
|
||||
/@vueuse/router@10.9.0(vue-router@4.3.0)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-MOmrCMQlRuPS4PExE1hy8T0XbZUXaNbEuh7CAG5mC8kdvdgANQMkdvJ7vIEOP27n5mXK/4YjvXJOZSsur4E0QQ==}
|
||||
peerDependencies:
|
||||
vue-router: '>=4.0.0-rc.1'
|
||||
dependencies:
|
||||
'@vueuse/shared': 10.9.0(vue@3.4.21)
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
vue-router: 4.3.0(vue@3.4.21)
|
||||
'@vueuse/shared': 10.9.0(vue@3.4.23)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
vue-router: 4.3.0(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@10.9.0(vue@3.4.21):
|
||||
/@vueuse/shared@10.9.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@9.13.0(vue@3.4.21):
|
||||
/@vueuse/shared@9.13.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
|
||||
dependencies:
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
- vue
|
||||
|
@ -5931,7 +5977,7 @@ packages:
|
|||
dev: false
|
||||
patched: true
|
||||
|
||||
/floating-vue@5.2.2(vue@3.4.21):
|
||||
/floating-vue@5.2.2(vue@3.4.23):
|
||||
resolution: {integrity: sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==}
|
||||
peerDependencies:
|
||||
'@nuxt/kit': ^3.2.0
|
||||
|
@ -5941,8 +5987,8 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.1.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue-resize: 2.0.0-alpha.1(vue@3.4.21)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
vue-resize: 2.0.0-alpha.1(vue@3.4.23)
|
||||
dev: false
|
||||
|
||||
/follow-redirects@1.15.6(debug@4.3.4):
|
||||
|
@ -7180,6 +7226,12 @@ packages:
|
|||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/magic-string@0.30.9:
|
||||
resolution: {integrity: sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/make-dir@3.1.0:
|
||||
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -7848,7 +7900,7 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/pinia@2.1.7(typescript@5.4.5)(vue@3.4.21):
|
||||
/pinia@2.1.7(typescript@5.4.5)(vue@3.4.23):
|
||||
resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==}
|
||||
peerDependencies:
|
||||
'@vue/composition-api': ^1.4.0
|
||||
|
@ -7862,8 +7914,8 @@ packages:
|
|||
dependencies:
|
||||
'@vue/devtools-api': 6.5.0
|
||||
typescript: 5.4.5
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue-demi: 0.14.6(vue@3.4.21)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
vue-demi: 0.14.6(vue@3.4.23)
|
||||
dev: false
|
||||
|
||||
/pkg-dir@4.2.0:
|
||||
|
@ -9834,13 +9886,13 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vite-svg-loader@5.1.0(vue@3.4.21):
|
||||
/vite-svg-loader@5.1.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==}
|
||||
peerDependencies:
|
||||
vue: '>=3.2.13'
|
||||
dependencies:
|
||||
svgo: 3.0.2
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: true
|
||||
|
||||
/vite@5.2.8(@types/node@20.12.7)(sass@1.74.1)(terser@5.24.0):
|
||||
|
@ -9938,7 +9990,7 @@ packages:
|
|||
- terser
|
||||
dev: true
|
||||
|
||||
/vue-advanced-cropper@2.8.8(vue@3.4.21):
|
||||
/vue-advanced-cropper@2.8.8(vue@3.4.23):
|
||||
resolution: {integrity: sha512-yDM7Jb/gnxcs//JdbOogBUoHr1bhCQSto7/ohgETKAe4wvRpmqIkKSppMm1huVQr+GP1YoVlX/fkjKxvYzwwDQ==}
|
||||
engines: {node: '>=8', npm: '>=5'}
|
||||
peerDependencies:
|
||||
|
@ -9947,14 +9999,14 @@ packages:
|
|||
classnames: 2.3.1
|
||||
debounce: 1.2.1
|
||||
easy-bem: 1.1.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-component-type-helpers@2.0.6:
|
||||
resolution: {integrity: sha512-qdGXCtoBrwqk1BT6r2+1Wcvl583ZVkuSZ3or7Y1O2w5AvWtlvvxwjGhmz5DdPJS9xqRdDlgTJ/38ehWnEi0tFA==}
|
||||
dev: true
|
||||
|
||||
/vue-demi@0.14.6(vue@3.4.21):
|
||||
/vue-demi@0.14.6(vue@3.4.23):
|
||||
resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
@ -9966,10 +10018,10 @@ packages:
|
|||
'@vue/composition-api':
|
||||
optional: true
|
||||
dependencies:
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-demi@0.14.7(vue@3.4.21):
|
||||
/vue-demi@0.14.7(vue@3.4.23):
|
||||
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
@ -9981,7 +10033,7 @@ packages:
|
|||
'@vue/composition-api':
|
||||
optional: true
|
||||
dependencies:
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-eslint-parser@9.4.2(eslint@8.57.0):
|
||||
|
@ -10002,17 +10054,17 @@ packages:
|
|||
- supports-color
|
||||
dev: true
|
||||
|
||||
/vue-flatpickr-component@11.0.5(vue@3.4.21):
|
||||
/vue-flatpickr-component@11.0.5(vue@3.4.23):
|
||||
resolution: {integrity: sha512-Vfwg5uVU+sanKkkLzUGC5BUlWd5wlqAMq/UpQ6lI2BCZq0DDrXhOMX7hrevt8bEgglIq2QUv0K2Nl84Me/VnlA==}
|
||||
engines: {node: '>=14.13.0'}
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
dependencies:
|
||||
flatpickr: 4.6.13
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-i18n@9.11.1(vue@3.4.21):
|
||||
/vue-i18n@9.11.1(vue@3.4.23):
|
||||
resolution: {integrity: sha512-S7Xi8DkLQG4xnnbxkxzipJK6CdfLdZkmApn95st89HFGp8LTmTH0Tv+Zw6puhOCZJCFrH73PHo3Ylwd2+Bmdxg==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
|
@ -10021,24 +10073,24 @@ packages:
|
|||
'@intlify/core-base': 9.11.1
|
||||
'@intlify/shared': 9.11.1
|
||||
'@vue/devtools-api': 6.6.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-resize@2.0.0-alpha.1(vue@3.4.21):
|
||||
/vue-resize@2.0.0-alpha.1(vue@3.4.23):
|
||||
resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-router@4.3.0(vue@3.4.21):
|
||||
/vue-router@4.3.0(vue@3.4.23):
|
||||
resolution: {integrity: sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.2.0
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-template-compiler@2.7.14:
|
||||
|
@ -10060,22 +10112,22 @@ packages:
|
|||
typescript: 5.4.5
|
||||
dev: true
|
||||
|
||||
/vue@3.4.21(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==}
|
||||
/vue@3.4.23(typescript@5.4.5):
|
||||
resolution: {integrity: sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.4.21
|
||||
'@vue/compiler-sfc': 3.4.21
|
||||
'@vue/runtime-dom': 3.4.21
|
||||
'@vue/server-renderer': 3.4.21(vue@3.4.21)
|
||||
'@vue/shared': 3.4.21
|
||||
'@vue/compiler-dom': 3.4.23
|
||||
'@vue/compiler-sfc': 3.4.23
|
||||
'@vue/runtime-dom': 3.4.23
|
||||
'@vue/server-renderer': 3.4.23(vue@3.4.23)
|
||||
'@vue/shared': 3.4.23
|
||||
typescript: 5.4.5
|
||||
|
||||
/vuemoji-picker@0.2.1(vue@3.4.21):
|
||||
/vuemoji-picker@0.2.1(vue@3.4.23):
|
||||
resolution: {integrity: sha512-wKRZBZclTdnQIT4jPzmkJ5Ci9ObzMFPjkuYb+/+/9h+mAZIUwdcPqYbEJCohbxJPoOvkuPVDeuOdTKR8hqqVLA==}
|
||||
peerDependencies:
|
||||
'@vue/composition-api': ^1.7.0
|
||||
|
@ -10085,8 +10137,8 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
emoji-picker-element: 1.21.1
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue-demi: 0.14.7(vue@3.4.21)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
vue-demi: 0.14.7(vue@3.4.23)
|
||||
dev: false
|
||||
|
||||
/w3c-keyname@2.2.6:
|
||||
|
@ -10526,11 +10578,11 @@ packages:
|
|||
engines: {node: '>=12.20'}
|
||||
dev: true
|
||||
|
||||
/zhyswan-vuedraggable@4.1.3(vue@3.4.21):
|
||||
/zhyswan-vuedraggable@4.1.3(vue@3.4.23):
|
||||
resolution: {integrity: sha512-q4Mp52tQIvTAWG0CKxLCVLyG/3RnIskDxoJvfjDZ2kM8yTcMkY80VTc8rd3q9KwqJ0UVtjEGLufb23sjDp0peQ==}
|
||||
peerDependencies:
|
||||
vue: ^3.0.1
|
||||
dependencies:
|
||||
sortablejs: 1.14.0
|
||||
vue: 3.4.21(typescript@5.4.5)
|
||||
vue: 3.4.23(typescript@5.4.5)
|
||||
dev: false
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 313 KiB After Width: | Height: | Size: 218 KiB |
|
@ -162,7 +162,7 @@ projectStore.loadAllProjects()
|
|||
.app-content {
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
padding: 1.5rem 0.5rem 1rem;
|
||||
padding: 1.5rem 0.5rem 0;
|
||||
// TODO refactor: DRY `transition-timing-function` with `./navigation.vue`.
|
||||
transition: margin-left $transition-duration;
|
||||
|
||||
|
@ -172,7 +172,7 @@ projectStore.loadAllProjects()
|
|||
}
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
padding: $navbar-height + 1.5rem 1.5rem 1rem 1.5rem;
|
||||
padding: $navbar-height + 1.5rem 1.5rem 0 1.5rem;
|
||||
}
|
||||
|
||||
&.is-menu-enabled {
|
||||
|
|
|
@ -338,10 +338,12 @@ const editor = useEditor({
|
|||
HardBreak.extend({
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
'Shift-Enter': () => this.editor.commands.setHardBreak(),
|
||||
'Mod-Enter': () => {
|
||||
if (contentHasChanged.value) {
|
||||
bubbleSave()
|
||||
}
|
||||
return true
|
||||
},
|
||||
}
|
||||
},
|
||||
|
@ -891,8 +893,14 @@ ul[data-type='taskList'] {
|
|||
padding: 0;
|
||||
margin-left: 0;
|
||||
|
||||
li[data-checked='true'] {
|
||||
color: var(--grey-500);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
margin-top: 0.25rem;
|
||||
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
|
|
|
@ -88,7 +88,7 @@ const currentProject = computed<IProject>(() => {
|
|||
})
|
||||
useTitle(() => currentProject.value?.id ? getProjectTitle(currentProject.value) : '')
|
||||
|
||||
const views = computed(() => currentProject.value?.views)
|
||||
const views = computed(() => projectStore.projects[projectId]?.views)
|
||||
|
||||
// watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before.
|
||||
// This resulted in loading and setting the project multiple times, even when navigating away from it.
|
||||
|
@ -161,6 +161,7 @@ function getViewTitle(view: IProjectView) {
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
justify-content: center;
|
||||
|
|
|
@ -30,45 +30,27 @@ import {computed, ref, watch} from 'vue'
|
|||
|
||||
import Filters from '@/components/project/partials/filters.vue'
|
||||
|
||||
import {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection'
|
||||
import {useRouteQuery} from '@vueuse/router'
|
||||
import {type TaskFilterParams} from '@/services/taskCollection'
|
||||
|
||||
const modelValue = defineModel<TaskFilterParams>({})
|
||||
const props = defineProps(['modelValue'])
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const value = ref<TaskFilterParams>({})
|
||||
const filter = useRouteQuery('filter')
|
||||
|
||||
watch(
|
||||
() => modelValue.value,
|
||||
() => props.modelValue,
|
||||
(modelValue: TaskFilterParams) => {
|
||||
value.value = modelValue
|
||||
if (value.value.filter !== '' && value.value.filter !== getDefaultTaskFilterParams().filter) {
|
||||
filter.value = value.value.filter
|
||||
}
|
||||
},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => filter.value,
|
||||
val => {
|
||||
if (modelValue.value?.filter === val || typeof val === 'undefined') {
|
||||
return
|
||||
}
|
||||
|
||||
modelValue.value.filter = val
|
||||
},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
function emitChanges(newValue: TaskFilterParams) {
|
||||
filter.value = newValue.filter
|
||||
if (modelValue.value?.filter === newValue.filter && modelValue.value?.s === newValue.s) {
|
||||
return
|
||||
}
|
||||
|
||||
modelValue.value.filter = newValue.filter
|
||||
modelValue.value.s = newValue.s
|
||||
emit('update:modelValue', {
|
||||
...value.value,
|
||||
filter: newValue.filter,
|
||||
s: newValue.s,
|
||||
})
|
||||
}
|
||||
|
||||
const hasFilters = computed(() => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
role="search"
|
||||
>
|
||||
<FilterInput
|
||||
v-model="params.filter"
|
||||
v-model="filterQuery"
|
||||
:project-id="projectId"
|
||||
@blur="change()"
|
||||
/>
|
||||
|
@ -28,7 +28,7 @@
|
|||
<x-button
|
||||
variant="secondary"
|
||||
class="mr-2"
|
||||
:disabled="params.filter === ''"
|
||||
:disabled="filterQuery === ''"
|
||||
@click.prevent.stop="clearFiltersAndEmit"
|
||||
>
|
||||
{{ $t('filters.clear') }}
|
||||
|
@ -87,6 +87,16 @@ const params = ref<TaskFilterParams>({
|
|||
s: '',
|
||||
})
|
||||
|
||||
const filterQuery = ref('')
|
||||
watch(
|
||||
() => [params.value.filter, params.value.s],
|
||||
() => {
|
||||
const filter = params.value.filter || ''
|
||||
const s = params.value.s || ''
|
||||
filterQuery.value = filter || s
|
||||
},
|
||||
)
|
||||
|
||||
// Using watchDebounced to prevent the filter re-triggering itself.
|
||||
watch(
|
||||
() => modelValue,
|
||||
|
@ -107,7 +117,7 @@ const projectStore = useProjectStore()
|
|||
|
||||
function change() {
|
||||
const filter = transformFilterStringForApi(
|
||||
params.value.filter,
|
||||
filterQuery.value,
|
||||
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
|
||||
projectTitle => {
|
||||
const found = projectStore.findProjectByExactname(projectTitle)
|
||||
|
@ -142,7 +152,7 @@ function changeAndEmitButton() {
|
|||
}
|
||||
|
||||
function clearFiltersAndEmit() {
|
||||
params.value.filter = ''
|
||||
filterQuery.value = ''
|
||||
changeAndEmitButton()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -773,11 +773,6 @@ $crazy-height-calculation: '100vh - 4.5rem - 1.5rem - 1rem - 1.5rem - 11px';
|
|||
$crazy-height-calculation-tasks: '#{$crazy-height-calculation} - 1rem - 2.5rem - 2rem - #{$button-height} - 1rem';
|
||||
$filter-container-height: '1rem - #{$switch-view-height}';
|
||||
|
||||
// FIXME:
|
||||
.app-content.project\.kanban, .app-content.task\.detail {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.kanban {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
@ -785,6 +780,10 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||
margin: 0 -1.5rem;
|
||||
padding: 0 1.5rem;
|
||||
|
||||
&:focus, .bucket .tasks:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
height: calc(#{$crazy-height-calculation} - #{$filter-container-height});
|
||||
scroll-snap-type: x mandatory;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {ref, shallowReactive, watch, computed, type ComputedGetter} from 'vue'
|
||||
import {useRoute} from 'vue-router'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {useRouteQuery} from '@vueuse/router'
|
||||
|
||||
import TaskCollectionService, {getDefaultTaskFilterParams, type TaskFilterParams} from '@/services/taskCollection'
|
||||
|
@ -66,7 +66,6 @@ export function useTaskList(
|
|||
|
||||
const params = ref<TaskFilterParams>({...getDefaultTaskFilterParams()})
|
||||
|
||||
const search = ref('')
|
||||
const page = useRouteQuery('page', '1', { transform: Number })
|
||||
|
||||
const sortBy = ref({ ...sortByDefault })
|
||||
|
@ -74,10 +73,6 @@ export function useTaskList(
|
|||
const allParams = computed(() => {
|
||||
const loadParams = {...params.value}
|
||||
|
||||
if (search.value !== '') {
|
||||
loadParams.s = search.value
|
||||
}
|
||||
|
||||
return formatSortOrder(sortBy.value, loadParams)
|
||||
})
|
||||
|
||||
|
@ -122,16 +117,38 @@ export function useTaskList(
|
|||
|
||||
const route = useRoute()
|
||||
watch(() => route.query, (query) => {
|
||||
const { page: pageQueryValue, search: searchQuery } = query
|
||||
if (searchQuery !== undefined) {
|
||||
search.value = searchQuery as string
|
||||
const {
|
||||
page: pageQueryValue,
|
||||
s,
|
||||
filter,
|
||||
} = query
|
||||
if (s !== undefined) {
|
||||
params.value.s = s as string
|
||||
}
|
||||
if (pageQueryValue !== undefined) {
|
||||
page.value = Number(pageQueryValue)
|
||||
}
|
||||
|
||||
if (filter !== undefined) {
|
||||
params.value.filter = filter
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const router = useRouter()
|
||||
watch(
|
||||
() => [page.value, params.value.filter, params.value.s],
|
||||
() => {
|
||||
router.replace({
|
||||
name: route.name,
|
||||
params: route.params,
|
||||
query: {
|
||||
page: page.value,
|
||||
filter: params.value.filter || undefined,
|
||||
s: params.value.s || undefined,
|
||||
},
|
||||
})
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
// Only listen for query path changes
|
||||
watch(() => JSON.stringify(getAllTasksParams.value), (newParams, oldParams) => {
|
||||
|
@ -148,7 +165,6 @@ export function useTaskList(
|
|||
totalPages,
|
||||
currentPage: page,
|
||||
loadTasks,
|
||||
searchTerm: search,
|
||||
params,
|
||||
sortByParam: sortBy,
|
||||
}
|
||||
|
|
|
@ -19,6 +19,13 @@ export function secondsToPeriod(seconds: number): { unit: PeriodUnit, amount: nu
|
|||
}
|
||||
}
|
||||
|
||||
if (seconds % SECONDS_A_MINUTE === 0) {
|
||||
return {
|
||||
unit: 'minutes',
|
||||
amount: seconds / SECONDS_A_MINUTE,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
unit: 'hours',
|
||||
amount: seconds / SECONDS_A_HOUR,
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router'
|
|||
import type { RouteLocation } from 'vue-router'
|
||||
import {saveLastVisited} from '@/helpers/saveLastVisited'
|
||||
|
||||
import {saveProjectView, getProjectViewId} from '@/helpers/projectView'
|
||||
import {getProjectViewId} from '@/helpers/projectView'
|
||||
import {parseDateOrString} from '@/helpers/time/parseDateOrString'
|
||||
import {getNextWeekDate} from '@/helpers/time/getNextWeekDate'
|
||||
import {LINK_SHARE_HASH_PREFIX} from '@/constants/linkShareHash'
|
||||
|
@ -366,7 +366,6 @@ const router = createRouter({
|
|||
path: '/projects/:projectId/:viewId',
|
||||
name: 'project.view',
|
||||
component: ProjectView,
|
||||
beforeEnter: (to) => saveProjectView(parseInt(to.params.projectId as string), parseInt(to.params.viewId as string)),
|
||||
props: route => ({
|
||||
projectId: parseInt(route.params.projectId as string),
|
||||
viewId: route.params.viewId ? parseInt(route.params.viewId as string): undefined,
|
||||
|
|
|
@ -207,13 +207,17 @@ export const useProjectStore = defineStore('project', () => {
|
|||
}
|
||||
|
||||
function getAncestors(project: IProject): IProject[] {
|
||||
if (typeof project === 'undefined') {
|
||||
return []
|
||||
}
|
||||
|
||||
if (!project?.parentProjectId) {
|
||||
return [project]
|
||||
}
|
||||
|
||||
const parentProject = projects.value[project.parentProjectId]
|
||||
return [
|
||||
...getAncestors(parentProject),
|
||||
...(parentProject ? getAncestors(parentProject) : []),
|
||||
project,
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import {computed, watch} from 'vue'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {saveProjectView} from '@/helpers/projectView'
|
||||
|
||||
import ProjectList from '@/components/project/views/ProjectList.vue'
|
||||
import ProjectGantt from '@/components/project/views/ProjectGantt.vue'
|
||||
|
@ -53,6 +54,13 @@ watch(
|
|||
redirectToFirstViewIfNecessary,
|
||||
)
|
||||
|
||||
// using a watcher instead of beforeEnter because beforeEnter is not called when only the viewId changes
|
||||
watch(
|
||||
() => [projectId, viewId],
|
||||
() => saveProjectView(projectId, viewId),
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
||||
|
|
|
@ -17,11 +17,11 @@ import postcssEasings from 'postcss-easings'
|
|||
import postcssEasingGradients from 'postcss-easing-gradients'
|
||||
|
||||
|
||||
const pathSrc = fileURLToPath(new URL('./src', import.meta.url))
|
||||
const pathSrc = fileURLToPath(new URL('./src', import.meta.url)).replaceAll('\\', '/')
|
||||
|
||||
// the @use rules have to be the first in the compiled stylesheets
|
||||
const PREFIXED_SCSS_STYLES = `@use "sass:math";
|
||||
@import "${pathSrc}/styles/common-imports";`
|
||||
@import "${pathSrc}/styles/common-imports.scss";`
|
||||
|
||||
const isModernBuild = Boolean(process.env.BUILD_MODERN_ONLY)
|
||||
const legacy = isModernBuild
|
||||
|
|
6
go.mod
6
go.mod
|
@ -20,8 +20,8 @@ require (
|
|||
code.vikunja.io/web v0.0.0-20210706160506-d85def955bd3
|
||||
dario.cat/mergo v1.0.0
|
||||
github.com/ThreeDotsLabs/watermill v1.3.5
|
||||
github.com/adlio/trello v1.11.0
|
||||
github.com/arran4/golang-ical v0.2.7
|
||||
github.com/adlio/trello v1.12.0
|
||||
github.com/arran4/golang-ical v0.2.8
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||
github.com/bbrks/go-blurhash v1.1.1
|
||||
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
|
||||
|
@ -190,8 +190,6 @@ require (
|
|||
|
||||
replace github.com/samedi/caldav-go => github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible // Branch: feature/dynamic-supported-components, PR: https://github.com/samedi/caldav-go/pull/6 and https://github.com/samedi/caldav-go/pull/7
|
||||
|
||||
replace github.com/adlio/trello v1.11.0 => github.com/kolaente/trello v1.8.1-0.20240410214605-9314fa638eab // https://github.com/adlio/trello/pull/95
|
||||
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.2
|
||||
|
|
8
go.sum
8
go.sum
|
@ -24,13 +24,15 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
|
|||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/ThreeDotsLabs/watermill v1.3.5 h1:50JEPEhMGZQMh08ct0tfO1PsgMOAOhV3zxK2WofkbXg=
|
||||
github.com/ThreeDotsLabs/watermill v1.3.5/go.mod h1:O/u/Ptyrk5MPTxSeWM5vzTtZcZfxXfO9PK9eXTYiFZY=
|
||||
github.com/adlio/trello v1.12.0 h1:JqOE2GFHQ9YtEviRRRSnicSxPbt4WFOxhqXzjMOw8lw=
|
||||
github.com/adlio/trello v1.12.0/go.mod h1:I4Lti4jf2KxjTNgTqs5W3lLuE78QZZdYbbPnQQGwjOo=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/arran4/golang-ical v0.2.7 h1:VO7YlVaGupZE15aj6NhUhte/MIfZuoIzkoI71VsG6Gg=
|
||||
github.com/arran4/golang-ical v0.2.7/go.mod h1:RqMuPGmwRRwjkb07hmm+JBqcWa1vF1LvVmPtSZN2OhQ=
|
||||
github.com/arran4/golang-ical v0.2.8 h1:8lsFcfQqzg0gBpIxq7fWr4RV+8SVENLMXpSic5xsFUs=
|
||||
github.com/arran4/golang-ical v0.2.8/go.mod h1:RqMuPGmwRRwjkb07hmm+JBqcWa1vF1LvVmPtSZN2OhQ=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
|
@ -303,8 +305,6 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY
|
|||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible h1:q7DbyV+sFjEoTuuUdRDNl2nlyfztkZgxVVCV7JhzIkY=
|
||||
github.com/kolaente/caldav-go v3.0.1-0.20190610114120-2a4eb8b5dcc9+incompatible/go.mod h1:y1UhTNI4g0hVymJrI6yJ5/ohy09hNBeU8iJEZjgdDOw=
|
||||
github.com/kolaente/trello v1.8.1-0.20240410214605-9314fa638eab h1:KAEuOtvjNohQzONw0NpOlR4TlWgsPawY/PLyOiMHlFw=
|
||||
github.com/kolaente/trello v1.8.1-0.20240410214605-9314fa638eab/go.mod h1:I4Lti4jf2KxjTNgTqs5W3lLuE78QZZdYbbPnQQGwjOo=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
|
|
@ -32,9 +32,9 @@ The to-do app to organize your life.
|
|||
Also one of the two wild South American camelids which live in the high
|
||||
alpine areas of the Andes and a relative of the llama.
|
||||
|
||||
Vikunja is a self-hosted To-Do list application with a web app and mobile apps for all platforms. It is licensed under the GPLv3.
|
||||
Vikunja is a self-hosted To-Do list application with a web app and mobile apps for all platforms. It is licensed under the AGPLv3.
|
||||
|
||||
Find more info at vikunja.io.`,
|
||||
Find out more at vikunja.io.`,
|
||||
PreRun: webCmd.PreRun,
|
||||
Run: webCmd.Run,
|
||||
}
|
||||
|
|
|
@ -82,7 +82,6 @@ func init() {
|
|||
|
||||
if config.DatabaseType.GetString() == "sqlite" {
|
||||
_, err = tx.Exec(`
|
||||
|
||||
create table buckets_dg_tmp
|
||||
(
|
||||
id INTEGER not null
|
||||
|
@ -107,7 +106,7 @@ drop table buckets;
|
|||
alter table buckets_dg_tmp
|
||||
rename to buckets;
|
||||
|
||||
create unique index UQE_buckets_id
|
||||
create unique index if not exists UQE_buckets_id
|
||||
on buckets (id);
|
||||
`)
|
||||
return err
|
||||
|
|
|
@ -155,6 +155,21 @@ func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (task
|
|||
projectIDs = append(projectIDs, p.ID)
|
||||
}
|
||||
|
||||
views := map[int64]*ProjectView{}
|
||||
err = s.In("project_id", projectIDs).Find(&views)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
viewIDs := []int64{}
|
||||
for _, v := range views {
|
||||
if projectsMap[v.ProjectID].Views == nil {
|
||||
projectsMap[v.ProjectID].Views = []*ProjectView{}
|
||||
}
|
||||
projectsMap[v.ProjectID].Views = append(projectsMap[v.ProjectID].Views, v)
|
||||
viewIDs = append(viewIDs, v.ID)
|
||||
}
|
||||
|
||||
tasks, _, _, err := getTasksForProjects(s, rawProjects, u, &taskSearchOptions{
|
||||
page: 0,
|
||||
perPage: -1,
|
||||
|
@ -194,17 +209,75 @@ func exportProjectsAndTasks(s *xorm.Session, u *user.User, wr *zip.Writer) (task
|
|||
}
|
||||
|
||||
buckets := []*Bucket{}
|
||||
err = s.In("project_id", projectIDs).Find(&buckets)
|
||||
err = s.In("project_view_id", viewIDs).Find(&buckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bucketIDs := []int64{}
|
||||
for _, b := range buckets {
|
||||
if _, exists := projectsMap[b.ProjectID]; !exists {
|
||||
log.Debugf("[User Data Export] Project %d does not exist for bucket %d, omitting", b.ProjectID, b.ID)
|
||||
view, exists := views[b.ProjectViewID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project view %d does not exist for bucket %d, omitting", b.ProjectViewID, b.ID)
|
||||
continue
|
||||
}
|
||||
projectsMap[b.ProjectID].Buckets = append(projectsMap[b.ProjectID].Buckets, b)
|
||||
_, exists = projectsMap[view.ProjectID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project %d does not exist for bucket %d, omitting", view.ProjectID, b.ID)
|
||||
continue
|
||||
}
|
||||
projectsMap[view.ProjectID].Buckets = append(projectsMap[view.ProjectID].Buckets, b)
|
||||
bucketIDs = append(bucketIDs, b.ID)
|
||||
}
|
||||
|
||||
taskBuckets := []*TaskBucket{}
|
||||
err = s.In("bucket_id", bucketIDs).Find(&taskBuckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, tb := range taskBuckets {
|
||||
view, exists := views[tb.ProjectViewID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project view %d does not exist, omitting", tb.ProjectViewID)
|
||||
continue
|
||||
}
|
||||
_, exists = projectsMap[view.ProjectID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project %d does not exist, omitting", view.ProjectID)
|
||||
continue
|
||||
}
|
||||
|
||||
if projectsMap[view.ProjectID].TaskBuckets == nil {
|
||||
projectsMap[view.ProjectID].TaskBuckets = []*TaskBucket{}
|
||||
}
|
||||
|
||||
projectsMap[view.ProjectID].TaskBuckets = append(projectsMap[view.ProjectID].TaskBuckets, tb)
|
||||
}
|
||||
|
||||
taskPositions := []*TaskPosition{}
|
||||
err = s.In("project_view_id", viewIDs).Find(&taskPositions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, p := range taskPositions {
|
||||
view, exists := views[p.ProjectViewID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project view %d does not exist, omitting", p.ProjectViewID)
|
||||
continue
|
||||
}
|
||||
_, exists = projectsMap[view.ProjectID]
|
||||
if !exists {
|
||||
log.Debugf("[User Data Export] Project %d does not exist, omitting", view.ProjectID)
|
||||
continue
|
||||
}
|
||||
|
||||
if projectsMap[view.ProjectID].Positions == nil {
|
||||
projectsMap[view.ProjectID].Positions = []*TaskPosition{}
|
||||
}
|
||||
|
||||
projectsMap[view.ProjectID].Positions = append(projectsMap[view.ProjectID].Positions, p)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(projects)
|
||||
|
|
|
@ -529,7 +529,18 @@ func (l *AddTaskToTypesense) Handle(msg *message.Message) (err error) {
|
|||
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
ttask, err := getTypesenseTaskForTask(s, event.Task, nil)
|
||||
|
||||
positionsMap, err := getPositionsForTask(s, event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bucketsMap, err := getBucketsForTask(s, event)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ttask, err := getTypesenseTaskForTask(s, event.Task, nil, positionsMap, bucketsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -540,6 +551,36 @@ func (l *AddTaskToTypesense) Handle(msg *message.Message) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getPositionsForTask(s *xorm.Session, event *TaskCreatedEvent) (positionsMap map[int64][]*TaskPositionWithView, err error) {
|
||||
positions := []*TaskPositionWithView{}
|
||||
err = s.
|
||||
Table("project_views").
|
||||
Where("project_views.project_id = ?", event.Task.ProjectID).
|
||||
Join("LEFT", "task_positions", "project_views.id = task_positions.project_view_id AND task_positions.task_id = ?", event.Task.ID).
|
||||
Find(&positions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
positionsMap = make(map[int64][]*TaskPositionWithView, 1)
|
||||
positionsMap[event.Task.ID] = positions
|
||||
return
|
||||
}
|
||||
|
||||
func getBucketsForTask(s *xorm.Session, event *TaskCreatedEvent) (bucketsMap map[int64][]*TaskBucket, err error) {
|
||||
buckets := []*TaskBucket{}
|
||||
err = s.
|
||||
Where("task_id = ?", event.Task.ID).
|
||||
Find(&buckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
bucketsMap = make(map[int64][]*TaskBucket, 1)
|
||||
bucketsMap[event.Task.ID] = buckets
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateTaskInTypesense represents a listener
|
||||
type UpdateTaskInTypesense struct {
|
||||
}
|
||||
|
|
|
@ -94,6 +94,8 @@ type ProjectWithTasksAndBuckets struct {
|
|||
Tasks []*TaskWithComments `xorm:"-" json:"tasks"`
|
||||
// Only used for migration.
|
||||
Buckets []*Bucket `xorm:"-" json:"buckets"`
|
||||
TaskBuckets []*TaskBucket `xorm:"-" json:"task_buckets"`
|
||||
Positions []*TaskPosition `xorm:"-" json:"positions"`
|
||||
BackgroundFileID int64 `xorm:"null" json:"background_file_id"`
|
||||
}
|
||||
|
||||
|
@ -110,13 +112,41 @@ type ProjectBackgroundType struct {
|
|||
// ProjectBackgroundUpload represents the project upload background type
|
||||
const ProjectBackgroundUpload string = "upload"
|
||||
|
||||
const FavoritesPseudoProjectID = -1
|
||||
|
||||
// FavoritesPseudoProject holds all tasks marked as favorites
|
||||
var FavoritesPseudoProject = Project{
|
||||
ID: -1,
|
||||
ID: FavoritesPseudoProjectID,
|
||||
Title: "Favorites",
|
||||
Description: "This project has all tasks marked as favorites.",
|
||||
IsFavorite: true,
|
||||
Position: -1,
|
||||
|
||||
Views: []*ProjectView{
|
||||
{
|
||||
ID: -1,
|
||||
ProjectID: FavoritesPseudoProjectID,
|
||||
Title: "List",
|
||||
ViewKind: ProjectViewKindList,
|
||||
Position: 100,
|
||||
Filter: "done = false",
|
||||
},
|
||||
{
|
||||
ID: -2,
|
||||
ProjectID: FavoritesPseudoProjectID,
|
||||
Title: "Gantt",
|
||||
ViewKind: ProjectViewKindGantt,
|
||||
Position: 200,
|
||||
},
|
||||
{
|
||||
ID: -3,
|
||||
ProjectID: FavoritesPseudoProjectID,
|
||||
Title: "Table",
|
||||
ViewKind: ProjectViewKindTable,
|
||||
Position: 300,
|
||||
},
|
||||
},
|
||||
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
}
|
||||
|
@ -146,6 +176,9 @@ func (p *Project) ReadAll(s *xorm.Session, a web.Auth, search string, page int,
|
|||
}
|
||||
projects := []*Project{project}
|
||||
err = addProjectDetails(s, projects, a)
|
||||
if err == nil && len(projects) > 0 {
|
||||
projects[0].ParentProjectID = 0
|
||||
}
|
||||
return projects, 0, 0, err
|
||||
}
|
||||
|
||||
|
@ -207,6 +240,7 @@ func (p *Project) ReadAll(s *xorm.Session, a web.Auth, search string, page int,
|
|||
func (p *Project) ReadOne(s *xorm.Session, a web.Auth) (err error) {
|
||||
|
||||
if p.ID == FavoritesPseudoProject.ID {
|
||||
p.Views = FavoritesPseudoProject.Views
|
||||
// Already "built" the project in CanRead
|
||||
return nil
|
||||
}
|
||||
|
@ -226,6 +260,11 @@ func (p *Project) ReadOne(s *xorm.Session, a web.Auth) (err error) {
|
|||
p.OwnerID = sf.OwnerID
|
||||
}
|
||||
|
||||
_, isShareAuth := a.(*LinkSharing)
|
||||
if isShareAuth {
|
||||
p.ParentProjectID = 0
|
||||
}
|
||||
|
||||
// Get project owner
|
||||
p.Owner, err = user.GetUserByID(s, p.OwnerID)
|
||||
if err != nil {
|
||||
|
@ -1073,6 +1112,46 @@ func (p *Project) Delete(s *xorm.Session, a web.Auth) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
// Delete related project entities
|
||||
views, err := getViewsForProject(s, p.ID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
viewIDs := []int64{}
|
||||
for _, v := range views {
|
||||
viewIDs = append(viewIDs, v.ID)
|
||||
}
|
||||
|
||||
_, err = s.In("project_view_id", viewIDs).Delete(&Bucket{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.In("id", viewIDs).Delete(&ProjectView{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = removeFromFavorite(s, p.ID, a, FavoriteKindProject)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Where("project_id = ?", p.ID).Delete(&LinkSharing{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Where("project_id = ?", p.ID).Delete(&ProjectUser{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.Where("project_id = ?", p.ID).Delete(&TeamProject{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete the project
|
||||
_, err = s.ID(p.ID).Delete(&Project{})
|
||||
if err != nil {
|
||||
|
|
|
@ -159,6 +159,7 @@ func (pd *ProjectDuplicate) Create(s *xorm.Session, doer web.Auth) (err error) {
|
|||
|
||||
log.Debugf("Duplicated all link shares from project %d into %d", pd.ProjectID, pd.Project.ID)
|
||||
|
||||
err = pd.Project.ReadOne(s, doer)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -226,10 +227,12 @@ func duplicateViews(s *xorm.Session, pd *ProjectDuplicate, doer web.Auth, taskMa
|
|||
})
|
||||
}
|
||||
|
||||
if len(taskBuckets) > 0 {
|
||||
_, err = s.Insert(&taskBuckets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
oldTaskPositions := []*TaskPosition{}
|
||||
err = s.In("project_view_id", oldViewIDs).Find(&oldTaskPositions)
|
||||
|
@ -246,7 +249,9 @@ func duplicateViews(s *xorm.Session, pd *ProjectDuplicate, doer web.Auth, taskMa
|
|||
})
|
||||
}
|
||||
|
||||
if len(taskPositions) > 0 {
|
||||
_, err = s.Insert(&taskPositions)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -347,10 +347,22 @@ func (p *ProjectView) Update(s *xorm.Session, _ web.Auth) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func GetProjectViewByIDAndProject(s *xorm.Session, id, projectID int64) (view *ProjectView, err error) {
|
||||
func GetProjectViewByIDAndProject(s *xorm.Session, viewID, projectID int64) (view *ProjectView, err error) {
|
||||
if projectID == FavoritesPseudoProjectID && viewID < 0 {
|
||||
for _, v := range FavoritesPseudoProject.Views {
|
||||
if v.ID == viewID {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, &ErrProjectViewDoesNotExist{
|
||||
ProjectViewID: viewID,
|
||||
}
|
||||
}
|
||||
|
||||
view = &ProjectView{}
|
||||
exists, err := s.
|
||||
Where("id = ? AND project_id = ?", id, projectID).
|
||||
Where("id = ? AND project_id = ?", viewID, projectID).
|
||||
NoAutoCondition().
|
||||
Get(view)
|
||||
if err != nil {
|
||||
|
@ -359,7 +371,7 @@ func GetProjectViewByIDAndProject(s *xorm.Session, id, projectID int64) (view *P
|
|||
|
||||
if !exists {
|
||||
return nil, &ErrProjectViewDoesNotExist{
|
||||
ProjectViewID: id,
|
||||
ProjectViewID: viewID,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,6 +100,10 @@ func getTaskFilterOptsFromCollection(tf *TaskCollection, projectView *ProjectVie
|
|||
param.orderBy = getSortOrderFromString(tf.OrderBy[i])
|
||||
}
|
||||
|
||||
if s == taskPropertyPosition && projectView != nil && projectView.ID < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if s == taskPropertyPosition && projectView != nil {
|
||||
param.projectViewID = projectView.ID
|
||||
}
|
||||
|
@ -249,12 +253,21 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa
|
|||
opts.perPage = perPage
|
||||
|
||||
if view != nil {
|
||||
var hasOrderByPosition bool
|
||||
for _, param := range opts.sortby {
|
||||
if param.sortBy == taskPropertyPosition {
|
||||
hasOrderByPosition = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasOrderByPosition {
|
||||
opts.sortby = append(opts.sortby, &sortParam{
|
||||
projectViewID: view.ID,
|
||||
sortBy: taskPropertyPosition,
|
||||
orderBy: orderAscending,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
shareAuth, is := a.(*LinkSharing)
|
||||
if is {
|
||||
|
|
|
@ -65,6 +65,14 @@ func (tc *TaskComment) TableName() string {
|
|||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{taskID}/comments [put]
|
||||
func (tc *TaskComment) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
|
||||
tc.Created = time.Time{}
|
||||
tc.Updated = time.Time{}
|
||||
|
||||
return tc.CreateWithTimestamps(s, a)
|
||||
}
|
||||
|
||||
func (tc *TaskComment) CreateWithTimestamps(s *xorm.Session, a web.Auth) (err error) {
|
||||
// Check if the task exists
|
||||
task, err := GetTaskSimple(s, &Task{ID: tc.TaskID})
|
||||
if err != nil {
|
||||
|
@ -77,10 +85,17 @@ func (tc *TaskComment) Create(s *xorm.Session, a web.Auth) (err error) {
|
|||
}
|
||||
tc.AuthorID = tc.Author.ID
|
||||
|
||||
if !tc.Created.IsZero() && !tc.Updated.IsZero() {
|
||||
_, err = s.NoAutoTime().Insert(tc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err = s.Insert(tc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return events.Dispatch(&TaskCommentCreatedEvent{
|
||||
Task: &task,
|
||||
|
@ -255,7 +270,7 @@ func (tc *TaskComment) ReadAll(s *xorm.Session, auth web.Auth, search string, pa
|
|||
query := s.
|
||||
Where(builder.And(where...)).
|
||||
Join("LEFT", "users", "users.id = task_comments.author_id").
|
||||
OrderBy("task_comments.id asc")
|
||||
OrderBy("task_comments.created asc")
|
||||
if limit > 0 {
|
||||
query = query.Limit(limit, start)
|
||||
}
|
||||
|
|
|
@ -297,6 +297,7 @@ func (d *dbTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task, totalCo
|
|||
queryCount = queryCount.Join("LEFT", "task_buckets", "task_buckets.task_id = tasks.id")
|
||||
}
|
||||
totalCount, err = queryCount.
|
||||
Select("count(DISTINCT tasks.id)").
|
||||
Count(&Task{})
|
||||
return
|
||||
}
|
||||
|
@ -379,6 +380,10 @@ func convertParsedFilterToTypesense(rawFilters []*taskFilter) (filterBy string,
|
|||
f.field = "project_id"
|
||||
}
|
||||
|
||||
if f.field == "bucket_id" {
|
||||
f.field = "buckets"
|
||||
}
|
||||
|
||||
filter := f.field
|
||||
|
||||
switch f.comparator {
|
||||
|
@ -450,6 +455,7 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
|
|||
"(" + filter + ")",
|
||||
}
|
||||
|
||||
var projectViewIDForPosition int64
|
||||
var sortbyFields []string
|
||||
for i, param := range opts.sortby {
|
||||
// Validate the params
|
||||
|
@ -457,17 +463,19 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
|
|||
return nil, totalCount, err
|
||||
}
|
||||
|
||||
sortBy := param.sortBy
|
||||
|
||||
// Typesense does not allow sorting by ID, so we sort by created timestamp instead
|
||||
if param.sortBy == taskPropertyID {
|
||||
param.sortBy = taskPropertyCreated
|
||||
sortBy = taskPropertyCreated
|
||||
}
|
||||
|
||||
if param.sortBy == taskPropertyPosition {
|
||||
param.sortBy = "positions.view_" + strconv.FormatInt(param.projectViewID, 10)
|
||||
continue
|
||||
sortBy = "positions.view_" + strconv.FormatInt(param.projectViewID, 10)
|
||||
projectViewIDForPosition = param.projectViewID
|
||||
}
|
||||
|
||||
sortbyFields = append(sortbyFields, param.sortBy+"(missing_values:last):"+param.orderBy.String())
|
||||
sortbyFields = append(sortbyFields, sortBy+"(missing_values:last):"+param.orderBy.String())
|
||||
|
||||
if i == 2 {
|
||||
// Typesense supports up to 3 sorting parameters
|
||||
|
@ -525,9 +533,14 @@ func (t *typesenseTaskSearcher) Search(opts *taskSearchOptions) (tasks []*Task,
|
|||
return nil, 0, err
|
||||
}
|
||||
|
||||
err = t.s.
|
||||
query := t.s.
|
||||
In("id", taskIDs).
|
||||
OrderBy(orderby).
|
||||
Find(&tasks)
|
||||
OrderBy(orderby)
|
||||
|
||||
if projectViewIDForPosition != 0 {
|
||||
query = query.Join("LEFT", "task_positions", "task_positions.task_id = tasks.id AND task_positions.project_view_id = ?", projectViewIDForPosition)
|
||||
}
|
||||
|
||||
err = query.Find(&tasks)
|
||||
return tasks, int64(*result.Found), err
|
||||
}
|
||||
|
|
|
@ -1486,6 +1486,18 @@ func (t *Task) Delete(s *xorm.Session, a web.Auth) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Delete all positions
|
||||
_, err = s.Where("task_id = ?", t.ID).Delete(&TaskPosition{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete all bucket relations
|
||||
_, err = s.Where("task_id = ?", t.ID).Delete(&TaskBucket{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Actually delete the task
|
||||
_, err = s.ID(t.ID).Delete(Task{})
|
||||
if err != nil {
|
||||
|
|
|
@ -146,22 +146,10 @@ func CreateTypesenseCollections() error {
|
|||
Name: "updated",
|
||||
Type: "int64", // unix timestamp
|
||||
},
|
||||
{
|
||||
Name: "bucket_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "position",
|
||||
Type: "float",
|
||||
},
|
||||
{
|
||||
Name: "created_by_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "project_view_id",
|
||||
Type: "int64",
|
||||
},
|
||||
{
|
||||
Name: "reminders",
|
||||
Type: "object[]", // TODO
|
||||
|
@ -192,6 +180,14 @@ func CreateTypesenseCollections() error {
|
|||
Type: "object[]", // TODO
|
||||
Optional: pointer.True(),
|
||||
},
|
||||
{
|
||||
Name: "positions",
|
||||
Type: "object",
|
||||
},
|
||||
{
|
||||
Name: "buckets",
|
||||
Type: "int64[]",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -248,14 +244,8 @@ func ReindexAllTasks() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func getTypesenseTaskForTask(s *xorm.Session, task *Task, projectsCache map[int64]*Project) (ttask *typesenseTask, err error) {
|
||||
positions := []*TaskPosition{}
|
||||
err = s.Where("task_id = ?", task.ID).Find(&positions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ttask = convertTaskToTypesenseTask(task, positions)
|
||||
func getTypesenseTaskForTask(s *xorm.Session, task *Task, projectsCache map[int64]*Project, taskPositionCache map[int64][]*TaskPositionWithView, taskBucketCache map[int64][]*TaskBucket) (ttask *typesenseTask, err error) {
|
||||
ttask = convertTaskToTypesenseTask(task, taskPositionCache[task.ID], taskBucketCache[task.ID])
|
||||
|
||||
var p *Project
|
||||
if projectsCache == nil {
|
||||
|
@ -299,9 +289,19 @@ func reindexTasksInTypesense(s *xorm.Session, tasks map[int64]*Task) (err error)
|
|||
projects := make(map[int64]*Project)
|
||||
typesenseTasks := []interface{}{}
|
||||
|
||||
positionsByTask, err := getPositionsByTask(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bucketsByTask, err := getBucketsByTask(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, task := range tasks {
|
||||
|
||||
ttask, err := getTypesenseTaskForTask(s, task, projects)
|
||||
ttask, err := getTypesenseTaskForTask(s, task, projects, positionsByTask, bucketsByTask)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -320,11 +320,55 @@ func reindexTasksInTypesense(s *xorm.Session, tasks map[int64]*Task) (err error)
|
|||
return err
|
||||
}
|
||||
|
||||
log.Debugf("Indexed tasks %v into Typesense", tasks)
|
||||
log.Debugf("Indexed %d tasks into Typesense", len(tasks))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type TaskPositionWithView struct {
|
||||
ProjectView `xorm:"extends"`
|
||||
TaskPosition `xorm:"extends"`
|
||||
}
|
||||
|
||||
func getPositionsByTask(s *xorm.Session) (positionsByTask map[int64][]*TaskPositionWithView, err error) {
|
||||
rawPositions := []*TaskPositionWithView{}
|
||||
err = s.
|
||||
Table("project_views").
|
||||
Join("LEFT", "task_positions", "project_views.id = task_positions.project_view_id").
|
||||
Find(&rawPositions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
positionsByTask = make(map[int64][]*TaskPositionWithView, len(rawPositions))
|
||||
for _, p := range rawPositions {
|
||||
_, has := positionsByTask[p.TaskID]
|
||||
if !has {
|
||||
positionsByTask[p.TaskID] = []*TaskPositionWithView{}
|
||||
}
|
||||
positionsByTask[p.TaskID] = append(positionsByTask[p.TaskID], p)
|
||||
}
|
||||
return positionsByTask, nil
|
||||
}
|
||||
|
||||
func getBucketsByTask(s *xorm.Session) (positionsByTask map[int64][]*TaskBucket, err error) {
|
||||
rawBuckets := []*TaskBucket{}
|
||||
err = s.Find(&rawBuckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
positionsByTask = make(map[int64][]*TaskBucket, len(rawBuckets))
|
||||
for _, p := range rawBuckets {
|
||||
_, has := positionsByTask[p.TaskID]
|
||||
if !has {
|
||||
positionsByTask[p.TaskID] = []*TaskBucket{}
|
||||
}
|
||||
positionsByTask[p.TaskID] = append(positionsByTask[p.TaskID], p)
|
||||
}
|
||||
return positionsByTask, nil
|
||||
}
|
||||
|
||||
func indexDummyTask() (err error) {
|
||||
// The initial sync should contain one dummy task with all related fields populated so that typesense
|
||||
// creates the indexes properly. A little hacky, but gets the job done.
|
||||
|
@ -386,6 +430,13 @@ func indexDummyTask() (err error) {
|
|||
},
|
||||
},
|
||||
},
|
||||
Positions: map[string]float64{
|
||||
"view_1": 10,
|
||||
"view_2": 30,
|
||||
"view_3": 5450,
|
||||
"view_4": 42,
|
||||
},
|
||||
Buckets: []int64{42},
|
||||
}
|
||||
|
||||
_, err = typesenseClient.Collection("tasks").
|
||||
|
@ -430,9 +481,10 @@ type typesenseTask struct {
|
|||
Attachments interface{} `json:"attachments"`
|
||||
Comments interface{} `json:"comments"`
|
||||
Positions map[string]float64 `json:"positions"`
|
||||
Buckets []int64 `json:"buckets"`
|
||||
}
|
||||
|
||||
func convertTaskToTypesenseTask(task *Task, positions []*TaskPosition) *typesenseTask {
|
||||
func convertTaskToTypesenseTask(task *Task, positions []*TaskPositionWithView, buckets []*TaskBucket) *typesenseTask {
|
||||
|
||||
tt := &typesenseTask{
|
||||
ID: fmt.Sprintf("%d", task.ID),
|
||||
|
@ -461,6 +513,8 @@ func convertTaskToTypesenseTask(task *Task, positions []*TaskPosition) *typesens
|
|||
Labels: task.Labels,
|
||||
//RelatedTasks: task.RelatedTasks,
|
||||
Attachments: task.Attachments,
|
||||
Positions: make(map[string]float64, len(positions)),
|
||||
Buckets: make([]int64, 0, len(buckets)),
|
||||
}
|
||||
|
||||
if task.DoneAt.IsZero() {
|
||||
|
@ -477,7 +531,15 @@ func convertTaskToTypesenseTask(task *Task, positions []*TaskPosition) *typesens
|
|||
}
|
||||
|
||||
for _, position := range positions {
|
||||
tt.Positions["view_"+strconv.FormatInt(position.ProjectViewID, 10)] = position.Position
|
||||
pos := position.TaskPosition.Position
|
||||
if pos == 0 {
|
||||
pos = float64(task.ID)
|
||||
}
|
||||
tt.Positions["view_"+strconv.FormatInt(position.ProjectView.ID, 10)] = pos
|
||||
}
|
||||
|
||||
for _, bucket := range buckets {
|
||||
tt.Buckets = append(tt.Buckets, bucket.BucketID)
|
||||
}
|
||||
|
||||
return tt
|
||||
|
|
|
@ -64,6 +64,11 @@ func insertFromStructure(s *xorm.Session, str []*models.ProjectWithTasksAndBucke
|
|||
}
|
||||
|
||||
p.ID = 0
|
||||
|
||||
for _, view := range p.Views {
|
||||
view.ProjectID = 0
|
||||
}
|
||||
|
||||
err = createProject(s, p, &archivedProjects, labels, user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -167,7 +172,7 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
}
|
||||
|
||||
// Create all buckets
|
||||
buckets := make(map[int64]*models.Bucket) // old bucket id is the key
|
||||
bucketsByOldID := make(map[int64]*models.Bucket) // old bucket id is the key
|
||||
if len(project.Buckets) > 0 {
|
||||
log.Debugf("[creating structure] Creating %d buckets", len(project.Buckets))
|
||||
}
|
||||
|
@ -179,40 +184,45 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
buckets[oldID] = bucket
|
||||
bucketsByOldID[oldID] = bucket
|
||||
log.Debugf("[creating structure] Created bucket %d, old ID was %d", bucket.ID, oldID)
|
||||
}
|
||||
|
||||
// Create all views, create default views if we don't have any
|
||||
viewsByOldIDs := make(map[int64]*models.ProjectView, len(oldViews))
|
||||
if len(oldViews) > 0 {
|
||||
for _, view := range oldViews {
|
||||
oldID := view.ID
|
||||
view.ID = 0
|
||||
|
||||
if view.DefaultBucketID != 0 {
|
||||
bucket, has := buckets[view.DefaultBucketID]
|
||||
bucket, has := bucketsByOldID[view.DefaultBucketID]
|
||||
if has {
|
||||
view.DefaultBucketID = bucket.ID
|
||||
}
|
||||
}
|
||||
|
||||
if view.DoneBucketID != 0 {
|
||||
bucket, has := buckets[view.DoneBucketID]
|
||||
bucket, has := bucketsByOldID[view.DoneBucketID]
|
||||
if has {
|
||||
view.DoneBucketID = bucket.ID
|
||||
}
|
||||
}
|
||||
|
||||
view.ProjectID = project.ID
|
||||
|
||||
err = view.Create(s, user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
viewsByOldIDs[oldID] = view
|
||||
}
|
||||
} else {
|
||||
// Only using the default views
|
||||
// Add all buckets to the default kanban view
|
||||
for _, view := range project.Views {
|
||||
if view.ViewKind == models.ProjectViewKindKanban {
|
||||
for _, b := range buckets {
|
||||
for _, b := range bucketsByOldID {
|
||||
b.ProjectViewID = view.ID
|
||||
err = b.Update(s, user)
|
||||
if err != nil {
|
||||
|
@ -227,7 +237,7 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
log.Debugf("[creating structure] Creating %d tasks", len(tasks))
|
||||
|
||||
setBucketOrDefault := func(task *models.Task) {
|
||||
bucket, exists := buckets[task.BucketID]
|
||||
bucket, exists := bucketsByOldID[task.BucketID]
|
||||
if exists {
|
||||
task.BucketID = bucket.ID
|
||||
} else if task.BucketID > 0 {
|
||||
|
@ -240,6 +250,7 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
}
|
||||
|
||||
tasksByOldID := make(map[int64]*models.TaskWithComments, len(tasks))
|
||||
newTaskIDs := []int64{}
|
||||
// Create all tasks
|
||||
for i, t := range tasks {
|
||||
setBucketOrDefault(&tasks[i].Task)
|
||||
|
@ -251,6 +262,8 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
continue
|
||||
}
|
||||
|
||||
newTaskIDs = append(newTaskIDs, t.ID)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -359,10 +372,11 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
log.Debugf("[creating structure] Associated task %d with label %d", t.ID, lb.ID)
|
||||
}
|
||||
|
||||
// Comments
|
||||
for _, comment := range t.Comments {
|
||||
comment.TaskID = t.ID
|
||||
comment.ID = 0
|
||||
err = comment.Create(s, user)
|
||||
err = comment.CreateWithTimestamps(s, user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -400,6 +414,58 @@ func createProjectWithEverything(s *xorm.Session, project *models.ProjectWithTas
|
|||
}
|
||||
}
|
||||
|
||||
if len(viewsByOldIDs) > 0 {
|
||||
newPositions := []*models.TaskPosition{}
|
||||
for _, pos := range project.Positions {
|
||||
_, hasTask := tasksByOldID[pos.TaskID]
|
||||
_, hasView := viewsByOldIDs[pos.ProjectViewID]
|
||||
if !hasTask || !hasView {
|
||||
continue
|
||||
}
|
||||
newPositions = append(newPositions, &models.TaskPosition{
|
||||
TaskID: tasksByOldID[pos.TaskID].ID,
|
||||
ProjectViewID: viewsByOldIDs[pos.ProjectViewID].ID,
|
||||
Position: pos.Position,
|
||||
})
|
||||
}
|
||||
|
||||
if len(newPositions) > 0 {
|
||||
_, err = s.In("task_id", newTaskIDs).Delete(&models.TaskPosition{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = s.Insert(newPositions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
newTaskBuckets := make([]*models.TaskBucket, 0, len(project.TaskBuckets))
|
||||
for _, tb := range project.TaskBuckets {
|
||||
_, hasTask := tasksByOldID[tb.TaskID]
|
||||
_, hasBucket := bucketsByOldID[tb.BucketID]
|
||||
if !hasTask || !hasBucket {
|
||||
continue
|
||||
}
|
||||
newTaskBuckets = append(newTaskBuckets, &models.TaskBucket{
|
||||
TaskID: tasksByOldID[tb.TaskID].ID,
|
||||
BucketID: bucketsByOldID[tb.BucketID].ID,
|
||||
ProjectViewID: bucketsByOldID[tb.BucketID].ProjectViewID,
|
||||
})
|
||||
}
|
||||
|
||||
if len(newTaskBuckets) > 0 {
|
||||
_, err = s.In("task_id", newTaskIDs).Delete(&models.TaskBucket{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = s.Insert(newTaskBuckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.Tasks = tasks
|
||||
project.Buckets = originalBuckets
|
||||
|
||||
|
|
|
@ -156,10 +156,18 @@ func setupSentry(e *echo.Echo) {
|
|||
if hub != nil {
|
||||
hub.WithScope(func(scope *sentry.Scope) {
|
||||
scope.SetExtra("url", c.Request().URL)
|
||||
if herr.Internal == nil {
|
||||
hub.CaptureException(err)
|
||||
} else {
|
||||
hub.CaptureException(herr.Internal)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if herr.Internal == nil {
|
||||
sentry.CaptureException(err)
|
||||
} else {
|
||||
sentry.CaptureException(herr.Internal)
|
||||
}
|
||||
log.Debugf("Could not add context for sending error '%s' to sentry", err.Error())
|
||||
}
|
||||
log.Debugf("Error '%s' sent to sentry", err.Error())
|
||||
|
|
Loading…
Reference in New Issue