Compare commits
42 Commits
dbfbfbf20f
...
a9a0bd5d25
Author | SHA1 | Date |
---|---|---|
renovate | a9a0bd5d25 | |
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 | |
Elscrux | 61ee0bd5e2 | |
kolaente | 423558f58a | |
kolaente | 75fd17c750 | |
kolaente | 4e49ec9e16 | |
renovate | 58e0ec3d35 | |
kolaente | ed4be389ab | |
renovate | cb2c2eeae8 |
|
@ -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
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "29.2.0",
|
||||
"electron": "30.0.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@30.0.0:
|
||||
version "30.0.0"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-30.0.0.tgz#6b72a27dcc46759fac5f12e147ef64554e596391"
|
||||
integrity sha512-GRwKphq/TUhSlb44OwSckXKl50f5OR/pm9MvF3rBLyqcxwfu7L11xejrZ0hDea1eKyCkzGd4B+cIqaQiDguPEA==
|
||||
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
|
||||
|
||||
```
|
||||
|
|
|
@ -103,7 +103,7 @@ auth:
|
|||
|
||||
## Automatically assign users to teams
|
||||
|
||||
Vikunja is capable of automatically adding users to a team based on OIDC claims added by the identity provider.
|
||||
Starting with version 0.24.0, Vikunja is capable of automatically adding users to a team based on OIDC claims added by the identity provider.
|
||||
If configured, Vikunja will sync teams, automatically create new ones and make sure the members are part of the configured teams.
|
||||
Teams which exist only because they were created from oidc attributes are not editable in Vikunja.
|
||||
|
||||
|
|
|
@ -28,13 +28,21 @@ All commands use the same standard [config file]({{< ref "../setup/config.md">}}
|
|||
|
||||
## Using the cli in docker
|
||||
|
||||
When running Vikunja in docker, you'll need to execute all commands in the `api` container.
|
||||
When running Vikunja in docker, you'll need to execute all commands in the `vikunja` container.
|
||||
Instead of running the `vikunja` binary directly, run it like this:
|
||||
|
||||
```sh
|
||||
docker exec <name of the vikunja api container> /app/vikunja/vikunja <subcommand>
|
||||
docker exec <name of the vikunja container> /app/vikunja/vikunja <subcommand>
|
||||
```
|
||||
|
||||
If you need to run a bunch of Vikunja commands, you can also create a shell alias for it:
|
||||
|
||||
```sh
|
||||
alias vikunja-docker='docker exec <name of the vikunja container> /app/vikunja/vikunja'
|
||||
```
|
||||
|
||||
Then use it as `vikunja-docker <subcommand>`.
|
||||
|
||||
### `dump`
|
||||
|
||||
Creates a zip file with all vikunja-related files.
|
||||
|
|
|
@ -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`)
|
||||
|
||||
|
|
|
@ -60,39 +60,39 @@
|
|||
"@kyvg/vue3-notification": "3.2.1",
|
||||
"@sentry/tracing": "7.109.0",
|
||||
"@sentry/vue": "7.109.0",
|
||||
"@tiptap/core": "2.2.6",
|
||||
"@tiptap/extension-blockquote": "2.2.6",
|
||||
"@tiptap/extension-bold": "2.2.6",
|
||||
"@tiptap/extension-bullet-list": "2.2.6",
|
||||
"@tiptap/extension-code": "2.2.6",
|
||||
"@tiptap/extension-code-block-lowlight": "2.2.6",
|
||||
"@tiptap/extension-document": "2.2.6",
|
||||
"@tiptap/extension-dropcursor": "2.2.6",
|
||||
"@tiptap/extension-gapcursor": "2.2.6",
|
||||
"@tiptap/extension-hard-break": "2.2.6",
|
||||
"@tiptap/extension-heading": "2.2.6",
|
||||
"@tiptap/extension-history": "2.2.6",
|
||||
"@tiptap/extension-horizontal-rule": "2.2.6",
|
||||
"@tiptap/extension-image": "2.2.6",
|
||||
"@tiptap/extension-italic": "2.2.6",
|
||||
"@tiptap/extension-link": "2.2.6",
|
||||
"@tiptap/extension-list-item": "2.2.6",
|
||||
"@tiptap/extension-ordered-list": "2.2.6",
|
||||
"@tiptap/extension-paragraph": "2.2.6",
|
||||
"@tiptap/extension-placeholder": "2.2.6",
|
||||
"@tiptap/extension-strike": "2.2.6",
|
||||
"@tiptap/extension-table": "2.2.6",
|
||||
"@tiptap/extension-table-cell": "2.2.6",
|
||||
"@tiptap/extension-table-header": "2.2.6",
|
||||
"@tiptap/extension-table-row": "2.2.6",
|
||||
"@tiptap/extension-task-item": "2.2.6",
|
||||
"@tiptap/extension-task-list": "2.2.6",
|
||||
"@tiptap/extension-text": "2.2.6",
|
||||
"@tiptap/extension-typography": "2.2.6",
|
||||
"@tiptap/extension-underline": "2.2.6",
|
||||
"@tiptap/pm": "2.2.6",
|
||||
"@tiptap/suggestion": "2.2.6",
|
||||
"@tiptap/vue-3": "2.2.6",
|
||||
"@tiptap/core": "2.3.0",
|
||||
"@tiptap/extension-blockquote": "2.3.0",
|
||||
"@tiptap/extension-bold": "2.3.0",
|
||||
"@tiptap/extension-bullet-list": "2.3.0",
|
||||
"@tiptap/extension-code": "2.3.0",
|
||||
"@tiptap/extension-code-block-lowlight": "2.3.0",
|
||||
"@tiptap/extension-document": "2.3.0",
|
||||
"@tiptap/extension-dropcursor": "2.3.0",
|
||||
"@tiptap/extension-gapcursor": "2.3.0",
|
||||
"@tiptap/extension-hard-break": "2.3.0",
|
||||
"@tiptap/extension-heading": "2.3.0",
|
||||
"@tiptap/extension-history": "2.3.0",
|
||||
"@tiptap/extension-horizontal-rule": "2.3.0",
|
||||
"@tiptap/extension-image": "2.3.0",
|
||||
"@tiptap/extension-italic": "2.3.0",
|
||||
"@tiptap/extension-link": "2.3.0",
|
||||
"@tiptap/extension-list-item": "2.3.0",
|
||||
"@tiptap/extension-ordered-list": "2.3.0",
|
||||
"@tiptap/extension-paragraph": "2.3.0",
|
||||
"@tiptap/extension-placeholder": "2.3.0",
|
||||
"@tiptap/extension-strike": "2.3.0",
|
||||
"@tiptap/extension-table": "2.3.0",
|
||||
"@tiptap/extension-table-cell": "2.3.0",
|
||||
"@tiptap/extension-table-header": "2.3.0",
|
||||
"@tiptap/extension-table-row": "2.3.0",
|
||||
"@tiptap/extension-task-item": "2.3.0",
|
||||
"@tiptap/extension-task-list": "2.3.0",
|
||||
"@tiptap/extension-text": "2.3.0",
|
||||
"@tiptap/extension-typography": "2.3.0",
|
||||
"@tiptap/extension-underline": "2.3.0",
|
||||
"@tiptap/pm": "2.3.0",
|
||||
"@tiptap/suggestion": "2.3.0",
|
||||
"@tiptap/vue-3": "2.3.0",
|
||||
"@types/is-touch-device": "1.0.2",
|
||||
"@types/lodash.clonedeep": "4.5.9",
|
||||
"@vueuse/core": "10.9.0",
|
||||
|
@ -121,7 +121,7 @@
|
|||
"vue": "3.4.21",
|
||||
"vue-advanced-cropper": "2.8.8",
|
||||
"vue-flatpickr-component": "11.0.5",
|
||||
"vue-i18n": "9.11.0",
|
||||
"vue-i18n": "9.11.1",
|
||||
"vue-router": "4.3.0",
|
||||
"vuemoji-picker": "0.2.1",
|
||||
"workbox-precaching": "7.0.0",
|
||||
|
@ -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",
|
||||
|
|
|
@ -33,7 +33,7 @@ dependencies:
|
|||
version: 2.3.2(dayjs@1.11.10)(vue@3.4.21)
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: 3.0.1
|
||||
version: 3.0.1(rollup@4.14.1)(vue-i18n@9.11.0)
|
||||
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)
|
||||
|
@ -44,104 +44,104 @@ dependencies:
|
|||
specifier: 7.109.0
|
||||
version: 7.109.0(vue@3.4.21)
|
||||
'@tiptap/core':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-blockquote':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-bold':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-bullet-list':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-code':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-code-block-lowlight':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/extension-code-block@2.1.12)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/extension-code-block@2.1.12)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-document':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-dropcursor':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-gapcursor':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-hard-break':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-heading':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-history':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-horizontal-rule':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-image':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-italic':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-link':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-list-item':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-ordered-list':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-paragraph':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-placeholder':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-strike':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-table':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-table-cell':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-table-header':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-table-row':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-task-item':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-task-list':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-text':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-typography':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/extension-underline':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)
|
||||
'@tiptap/pm':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0
|
||||
'@tiptap/suggestion':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/vue-3':
|
||||
specifier: 2.2.6
|
||||
version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)(vue@3.4.21)
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.21)
|
||||
'@types/is-touch-device':
|
||||
specifier: 1.0.2
|
||||
version: 1.0.2
|
||||
|
@ -227,8 +227,8 @@ dependencies:
|
|||
specifier: 11.0.5
|
||||
version: 11.0.5(vue@3.4.21)
|
||||
vue-i18n:
|
||||
specifier: 9.11.0
|
||||
version: 9.11.0(vue@3.4.21)
|
||||
specifier: 9.11.1
|
||||
version: 9.11.1(vue@3.4.21)
|
||||
vue-router:
|
||||
specifier: 4.3.0
|
||||
version: 4.3.0(vue@3.4.21)
|
||||
|
@ -262,8 +262,8 @@ devDependencies:
|
|||
specifier: 0.17.17
|
||||
version: 0.17.17(histoire@0.17.17)(vite@5.2.8)(vue@3.4.21)
|
||||
'@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
|
||||
|
@ -2608,7 +2608,7 @@ packages:
|
|||
- '@vue/composition-api'
|
||||
dev: false
|
||||
|
||||
/@intlify/bundle-utils@7.4.0(vue-i18n@9.11.0):
|
||||
/@intlify/bundle-utils@7.4.0(vue-i18n@9.11.1):
|
||||
resolution: {integrity: sha512-AQfjBe2HUxzyN8ignIk3WhhSuVcSuirgzOzkd17nb337rCbI4Gv/t1R60UUyIqFoFdviLb/wLcDUzTD/xXjv9w==}
|
||||
engines: {node: '>= 14.16'}
|
||||
peerDependencies:
|
||||
|
@ -2621,7 +2621,7 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 9.10.1
|
||||
'@intlify/shared': 9.10.1
|
||||
'@intlify/shared': 9.11.0
|
||||
acorn: 8.11.2
|
||||
escodegen: 2.0.0
|
||||
estree-walker: 2.0.2
|
||||
|
@ -2629,16 +2629,16 @@ packages:
|
|||
magic-string: 0.30.7
|
||||
mlly: 1.4.2
|
||||
source-map-js: 1.2.0
|
||||
vue-i18n: 9.11.0(vue@3.4.21)
|
||||
vue-i18n: 9.11.1(vue@3.4.21)
|
||||
yaml-eslint-parser: 1.2.2
|
||||
dev: false
|
||||
|
||||
/@intlify/core-base@9.11.0:
|
||||
resolution: {integrity: sha512-cveOqAstjLZIiyatcP/HrzrQ87cZI8ScPQna3yvoM8zjcjcIRK1MRvmxUNlPdg0rTNJMZw7rixPVM58O5aHVPA==}
|
||||
/@intlify/core-base@9.11.1:
|
||||
resolution: {integrity: sha512-qWXBBlEA+DC0CsHkfJiQK9ELm11c9I6lDpodY4FoOf99eMas1R6JR4woPhrfAcrtxFHp1UmXWdrQNKDegSW9IA==}
|
||||
engines: {node: '>= 16'}
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 9.11.0
|
||||
'@intlify/shared': 9.11.0
|
||||
'@intlify/message-compiler': 9.11.1
|
||||
'@intlify/shared': 9.11.1
|
||||
dev: false
|
||||
|
||||
/@intlify/message-compiler@9.10.1:
|
||||
|
@ -2649,11 +2649,11 @@ packages:
|
|||
source-map-js: 1.2.0
|
||||
dev: false
|
||||
|
||||
/@intlify/message-compiler@9.11.0:
|
||||
resolution: {integrity: sha512-x31Gl7cscnoI4UUY1yaIy8e7vVMVW1VVlTXZz4SIHKqoSEUkfmgqK8NAx1e7RcoHEbICR7uyCbud0ZL1s4OGXQ==}
|
||||
/@intlify/message-compiler@9.11.1:
|
||||
resolution: {integrity: sha512-y/aWx7DkaTKK2qWUw0hVbJpon8+urWXngeqh15DuIXZh6n/V/oPQiO/Ho1hUKbwap6MVMuz0OcnAJvqh3p9YPg==}
|
||||
engines: {node: '>= 16'}
|
||||
dependencies:
|
||||
'@intlify/shared': 9.11.0
|
||||
'@intlify/shared': 9.11.1
|
||||
source-map-js: 1.2.0
|
||||
dev: false
|
||||
|
||||
|
@ -2667,7 +2667,12 @@ packages:
|
|||
engines: {node: '>= 16'}
|
||||
dev: false
|
||||
|
||||
/@intlify/unplugin-vue-i18n@3.0.1(rollup@4.14.1)(vue-i18n@9.11.0):
|
||||
/@intlify/shared@9.11.1:
|
||||
resolution: {integrity: sha512-yuDG82vjgId2oasNRgZ0PKJrF65zlL33MNyITP5itbLcP4AYOR/NcIuD+/DiI+GHXdxASMKJU0ZiITLc6RC+qw==}
|
||||
engines: {node: '>= 16'}
|
||||
dev: false
|
||||
|
||||
/@intlify/unplugin-vue-i18n@3.0.1(rollup@4.14.1)(vue-i18n@9.11.1):
|
||||
resolution: {integrity: sha512-q1zJhA/WpoLBzAAuKA5/AEp0e+bMOM10ll/HxT4g1VAw/9JhC4TTobP9KobKH90JMZ4U2daLFlYQfKNd29lpqw==}
|
||||
engines: {node: '>= 14.16'}
|
||||
peerDependencies:
|
||||
|
@ -2682,7 +2687,7 @@ packages:
|
|||
vue-i18n-bridge:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@intlify/bundle-utils': 7.4.0(vue-i18n@9.11.0)
|
||||
'@intlify/bundle-utils': 7.4.0(vue-i18n@9.11.1)
|
||||
'@intlify/shared': 9.10.1
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.14.1)
|
||||
'@vue/compiler-sfc': 3.4.21
|
||||
|
@ -2694,7 +2699,7 @@ packages:
|
|||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
unplugin: 1.1.0
|
||||
vue-i18n: 9.11.0(vue@3.4.21)
|
||||
vue-i18n: 9.11.1(vue@3.4.21)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
@ -3043,8 +3048,8 @@ 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:
|
||||
|
@ -3193,301 +3198,301 @@ packages:
|
|||
defer-to-connect: 1.1.3
|
||||
dev: true
|
||||
|
||||
/@tiptap/core@2.2.6(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-v7S7RhQhTXQo9KSk2jM/jJlTd3clU2FsJA3Omjz7GbgYtPSy67qSiaTbH/tWq12GzDHbKymx+oQnKmyx+yPucA==}
|
||||
/@tiptap/core@2.3.0(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-Gk2JN3i5CMkYGmsbyFI7cBUftWa+F7QYmeCLTWfbuy+hCM2OBsnYVKxhggFPGXRL5KLBEgBWeCeWMHfIw3B2MA==}
|
||||
peerDependencies:
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-blockquote@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-Qoq4Tl4wyEGfuBrMFth5hWP1SroJtgDYPnyzAZeLiGzF3Yxtu7FFqjGtD1/Bos9ftnFVCAj+nIXnuKsM1YUaGg==}
|
||||
/@tiptap/extension-blockquote@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-Cztt77t7f+f0fuPy+FWUL8rKTIpcdsVT0z0zYQFFafvGaom0ZALQSOdTR/q+Kle9I4DaCMO3/Q0mwax/D4k4+A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bold@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-PI/jNH7rmi6hBvWy/z+3KUTYqeaDXBUjidM74gWP6OLV28HTJ5SkIPCriYe4u2j2Wc/nk3gPxs4/hPOAu/YiXA==}
|
||||
/@tiptap/extension-bold@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-SzkbJibHXFNU7TRaAebTtwbXUEhGZ8+MhlBn12aQ4QhdjNtFpQwKXQPyYeDyZGcyiOFgtFTb+WIfCGm8ZX0Fpw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bubble-menu@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-nRWxbgkInhdGUL+e6iISgALcWh8A1PxeVB66w7yYZHS/WoZO0DXdXYT/BWb/XmEJ8r6B4c9SDZRklCiXT8dSXw==}
|
||||
/@tiptap/extension-bubble-menu@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-dqyfQ8idTlhapvt0fxCGvkyjw92pBEwPqmkJ01h3EE8wTh53j0ytOHyMSf1KBuzardxpd8Yya3zlrAcR0Z3DlQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
tippy.js: 6.3.7
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-bullet-list@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-bSrmYlWfj/bXXoBMVB+gCTlsficVVzWi1jcAjAn+qNAENkhampmlFIUG4DiKGYtn18ZoTbyLgQGDMCO3SBdeDQ==}
|
||||
/@tiptap/extension-bullet-list@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-4nU4vJ5FjRDLqHm085vYAkuo68UK84Wl6CDSjm7sPVcu0FvQX02Okqt65azoSYQeS1SSSd5qq9YZuGWcYdp4Cw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-code-block-lowlight@2.2.6(@tiptap/core@2.2.6)(@tiptap/extension-code-block@2.1.12)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-W/8C5nIwgGLvxjc+PfnCcWkfrUuJsIKjyZGXmq1hVXTTVA9eVGbS7m1YB/fsYTEg1ccwoM2JjKO9yuKCeR2xiQ==}
|
||||
/@tiptap/extension-code-block-lowlight@2.3.0(@tiptap/core@2.3.0)(@tiptap/extension-code-block@2.1.12)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-xMxWr/Fvv0hnN+u+6SW0OI3RVan+C6nJDU8xKh2Tx2DlBXJ0yODmq5v8WJJpW38AbaLkFuJuY/OA3AZ6n9pNbg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/extension-code-block': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/extension-code-block': 2.1.12(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/extension-code-block': 2.1.12(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-code-block@2.1.12(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
/@tiptap/extension-code-block@2.1.12(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-RXtSYCVsnk8D+K80uNZShClfZjvv1EgO42JlXLVGWQdIgaNyuOv/6I/Jdf+ZzhnpsBnHufW+6TJjwP5vJPSPHA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-code@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-UGsSFvVWrWWWQFU4atk+b/qeewTLadOZG/BHZXQDloyP5eJ1SkgUVy9nv3y2cT8QWRbvF6sxkV+SdFoWnvaG3Q==}
|
||||
/@tiptap/extension-code@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-O2FZmosiIRoVbW82fZy8xW4h4gb2xAzxWzHEcsHPlwCbE3vYvcBMmbkQ5p+33eRtuRQInzl3Q/cwupv9ctIepQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-document@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-yT9m5Oo9U/xAypcylaLiDE8qmVd3SCZSc8s5lqyC1OW+psb1oC0d14+TgKetO2s8K2wAbW2DxYG3yoxWffGYsQ==}
|
||||
/@tiptap/extension-document@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-WC55SMrtlsNOnHXpzbXDzJOp7eKmZV0rXooKmvCDqoiLO/DKpyQXyF+0UHfcRPmUAi2GWFPaer7+p1H9xzcjXg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-dropcursor@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-mCeIbbfe4rl8CuxVQvT7iYSKGVX/ls1LOwALwlHJz5Uw5l3VknAJdjEmHt6hNFdHu162JivL02Il0QYQ8BZwvA==}
|
||||
/@tiptap/extension-dropcursor@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-WWxxGQPWdbzxyYP6jtBYSq4wMRhINhI0wBC8pgkxTVwCIWftMuYj++FP4LLIpuWgj78PWApuoM0QQxk4Lj7FOw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-floating-menu@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-6ONKC6Dx8zCc5YffXpnQ9FxGRoUp5Jm9mOO3losgiDFhdJqaO7SCk1ziOiD7enoWqIc2shZh8ADnqttCfnFVFQ==}
|
||||
/@tiptap/extension-floating-menu@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-bNY43/yU/+wGfmk2eDV7EPDAN/akbC+YnSKTA5VPJADzscvlrL2HlQrxbd/STIdlwKqdPU5MokcvCChhfZ4f6w==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
tippy.js: 6.3.7
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-gapcursor@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-HDYu+FmL9V+khsiT5904Dy2qG6KrAvnXEjZk1+vVul0TabnQvl2rqHjTxmev3P1rOYTgePmaWXazxAWFIvbMBQ==}
|
||||
/@tiptap/extension-gapcursor@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-OxcXcfD0uzNcXdXu2ZpXFAtXIsgK2MBHvFUs0t0gxtcL/t43pTOQBLy+29Ei30BxpwLghtX8jQ6IDzMiybq/sA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-hard-break@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-gwavC76sn26XQLyDaDtf28KIcbhMYPP+C5pkbRvAhVSckQB3Ebz3GRttVbm/jp+Uifp3bmoQEzISGCONEdKQoQ==}
|
||||
/@tiptap/extension-hard-break@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-9pXi69SzLabbjY5KZ54UKzu7HAHTla9aYZKH56VatOAiJOPKJppFbU2/NfJwGzDrEtfOiDqr3dYbUDF3RuCFoQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-heading@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-XOmY+uezm42xSO1ero2bRBMdQxWytpxLJS+2shK0QogZ3sDplnfWfP5KV9Z2juXjTdPgPWG0ZaHzIIaLquEcfA==}
|
||||
/@tiptap/extension-heading@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-YcZoUYfqb0nohoPgem4f8mjn5OqDomFrbJiC9VRHUOCIuEu+aJEYwp8mmdkLnS3f+LRCZ6G76cJJ50lkzSAZRw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-history@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-c2Aeozc+pHcpqghLjXRX/tGU/C+Gp6hApUWPXdhZw5Y/ARj6ZRwx2/ym2K8MOrJ36/W7gc7Xyxd9ZbG7m7pcjA==}
|
||||
/@tiptap/extension-history@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-EF5Oq9fe/VBzU1Lsow2ubOlx1e1r4OQT1WUPGsRnL7pr94GH1Skpk7/hs9COJ9K6kP3Ebt42XjP0JEQodR58YA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-horizontal-rule@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-zyLU+Xlk8y3yBCblE8pFwqAP2Rju1csyAu45hi3NCJ6HDGQGdjy8oh+Xa8y2kTPxRNMZARxqB+vCiEoW3YZn2A==}
|
||||
/@tiptap/extension-horizontal-rule@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-4DB8GU3uuDzzyqUmONIb3CHXcQ6Nuy4mHHkFSmUyEjg1i5eMQU5H7S6mNvZbltcJB2ImgCSwSMlj1kVN3MLIPg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-image@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-MoDVjvi0AgYYSY9QR3ff2TOKk9IVVfh+BInmLCrwejSE2q8N3p/vSI+N1GKLEfW9mqn1zdI95ev17Z12Avwv7A==}
|
||||
/@tiptap/extension-image@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-v1fLEEzrfXWavsLFUEkTiYYxwm1WDNrjuUriU5tG2Jv22NL1BL4BLVbZbGdkAk+qHWy8QWszrDJbcgGh2VNCoQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-italic@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-wB+Y6p2gbc1f2hKYeGNXRQ7P2xi3+JzD3PjSyC9Ss/yyujZhxSOtxBF0nzFXdI+7nmN0Qm4inwPDU/DVrIPb+A==}
|
||||
/@tiptap/extension-italic@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-jdFjLjdt5JtPlGMpoS6TEq5rznjbAYVlPwcw5VkYENVIYIGIR1ylIw2JwK1nUEsQ+OgYwVxHLejcUXWG1dCi2g==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-link@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-Jj0oXSfQ8gZlzzwd669B8sEKBkoK8xV31Lu55tRv9PKHSU6p9CUqBuxY8qR+cquCtO28f3u0cdl5o4HzeIUL5A==}
|
||||
/@tiptap/extension-link@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-CnJAlV0ZOdEhKmDfYKuHJVG8g79iCFQ85cX/CROTWyuMfXz9uhj2rLpZ6nfidVbonqxAhQp7NAIr2y+Fj5/53A==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
linkifyjs: 4.1.1
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-list-item@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-3xig1q0jtOyV49TkAbvxBoOJdNypwq6vLYerfblhj6dK+hIIZUM33S+SmGl2+QaB25VwyeSHjiCvrJjB9PKWHQ==}
|
||||
/@tiptap/extension-list-item@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-mHU+IuRa56OT6YCtxf5Z7OSUrbWdKhGCEX7RTrteDVs5oMB6W3oF9j88M5qQmZ1WDcxvQhAOoXctnMt6eX9zcA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-ordered-list@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-h4HOv+TAMnoueh3CzUY2/Pp2n8eCdEQtKSfiMtHSO3NTTSlst0XEvq+3Z4K81F+ni3baXc+JUALP5dRVpI4apQ==}
|
||||
/@tiptap/extension-ordered-list@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-gkf0tltXjlUj0cqyfDV2r7xy9YPKtcVSWwlCPun6OOi0KzKFiAMqQpA9hy2W6gJ+KCp8+KNRMClZOfH4TnnBfg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-paragraph@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-M2rM3pfzziUb7xS9x2dANCokO89okbqg5IqU4VPkZhk0Mfq9czyCatt58TYkAsE3ccsGhdTYtFBTDeKBtsHUqg==}
|
||||
/@tiptap/extension-paragraph@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-peCpA7DFqkd0cHb+cHv4YHNoMsXG8tKFNJlCHpLmsZWl2hWmpKgKmUrXAUfzjcFSvkZxn0xYc5oWbqUgg+2LzA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-placeholder@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-eHPadx48gneDD8bTZeRnG4hOvRvctBPY5JlA03QQIoarrbmqsyv3zZSW8smBsRai9kwbXLhytdEFGruTKV9PjQ==}
|
||||
/@tiptap/extension-placeholder@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-1BOyxVLzyUYf6yOOeJ8CfpP6DSCS4L6HjBZqj6WP1z1NyBV8RAfhf3UuLNcimfSWAETXFR3g0ZbaxxWffI1cEg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-strike@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-0fRh0SwPgqi+ZKD2NpRrmIAHdsgf27ddEUfvlIuFG5b9zqFa6pRZGpXW/6LyBwU0+0bkjW8/Wg3otyaRGjvZGw==}
|
||||
/@tiptap/extension-strike@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-gOW4ALeH8gkJiUGGXVy/AOd5lAPTX0bzoOW1+sCLcTA7t8dluBW7M2ngNYxTEtlKqyv7aLfrgsYSiqucmmfSLw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-cell@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-i/O27W0O2Bp+txeYUz8thZJaIHTb8BvPseYENiYBs9qOjpwiqXgQXVa5wTAm93GtHoK2ifs50a/xp2CIDTYsgw==}
|
||||
/@tiptap/extension-table-cell@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-jsFp5lc+be04AsuMiTGlluLnsmJl/51+sv0DewYHeidh7iyvk3R5y2pyA+Bk1V/txFdaH5GxOQvSH3RonEVMAg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-header@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-1IFGBVV/wJwO7aM8u6gN90OmT35ulJoNFQEssoxrx8g+tj+mZy5vXq2JGPqFg7AVjIpek1DJrzzcXGnbtXS57w==}
|
||||
/@tiptap/extension-table-header@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-wLvJqDBaXc/xs+NBJZoSIfO7fVYqcrIlsdtQRlBec3vTpSG0w0zlrM/JY4mjQKHzWsDk6hb9mvbK2scChOu5TA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table-row@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-sUTpzzR6zR6iFLXszK4qak0/qd8Gjz9/mnj9sdRJhXtVT+VPssU0iVBMyIfn01nnoUzMPpakcO1Vd5dSJNhoVg==}
|
||||
/@tiptap/extension-table-row@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-i2o/S8Mggw1GDxF5N5i8SvDvmOvbHu8MuWpdhFwfOkbrnEdtHlU/GjWIEstPymg4QyrfAEQa/KDffkrX0T7RNw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-table@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-O26Uj/A9AR8QJZvjSaTCI6Jpuc7MD8ul0vjqJ9EKulzMaAJbiOJidcBPr7rhVxAIRrXQz+DQW+zFbZvTj5i5mQ==}
|
||||
/@tiptap/extension-table@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-1cU0C5LFyF7Nm8K2X6sntuunpLDE11XV8gV4ALbXv0FNKx2rG9Wq0tQlGHAjhYZMhWt386T21N7o13aMAov1GA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-task-item@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-8JJI9JBDdU5optPZVmlpCk5eOXv1p8bsFQYgHmIaHmDvsWvNlRph1LBYEAyiImBwVgZp+M8FI4KD5rNdALhelw==}
|
||||
/@tiptap/extension-task-item@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-WvQJiQSskI1dZLPgNH4hmYPW0HFyR/EHwogzVnY7XCn2/5isV0ewyaVuSfqTXvfEA/R5uCi95opwz61NFBc2nQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-task-list@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-4ofrnm0jwk9OC5QH+b5wR4ck+J5wi+uOq7Qm2234GAqohjOzr4ndae68NSIv2XviDk04askCoZc+yZBxNwkhmQ==}
|
||||
/@tiptap/extension-task-list@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-TBgqf4s3DpUV97w7AAj1WZDnZ3rZQ8B645d9bBayo4VfRzHCLefv5cVP/Ye9GA23T4FZoHNR+yIPrM7SfhkmPA==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-text@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-wVpo0I/2tJsBK/2yNZfRXOsThOfHCdTY+FDNO/USx9MCJaJ3LPs3H1AuGO549zNmZgkD+1MqcZqrYt9n4i03cw==}
|
||||
/@tiptap/extension-text@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-zkudl0TyKRy/8vHtyo5dMzjBRD0HEUnsS8YOsjR4xwQq5EYUXleRgM1s6lb6Yms2sLUAZRWdDddoQ686iq4zQg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-typography@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-S8rvwSLq6IW1pEo/1Gcyez2tnXvUbwFBsAGNKPzcX/0HvlgXYWdE+qcjT3yoY/gAHRdvqfAP1Cd4Up7O3f1//A==}
|
||||
/@tiptap/extension-typography@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-bI9t6dVp3wvzp3RVhJYRAV5Gi4pCSnumYith62TJmEk7fI24XuwMAXJu32+RTtBkaWHX/nwSGPh/ol0PRmtzKw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/extension-underline@2.2.6(@tiptap/core@2.2.6):
|
||||
resolution: {integrity: sha512-RaYEWuBHS6VQ2KXk+pP2b3xDN4vxmTb7+CF84mumR+CJUK4uAx01IDBUof+h/a4Sa58suNLQ6eHY33NmxPppnQ==}
|
||||
/@tiptap/extension-underline@2.3.0(@tiptap/core@2.3.0):
|
||||
resolution: {integrity: sha512-vmmcwCPmWqGKYHZevz50+bxrpHyiu5y6YZweAE476hn8Mud6vYg7RpkXgW8bjkCOky6UA51uelslSc0XrLE6uw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
dev: false
|
||||
|
||||
/@tiptap/pm@2.2.6:
|
||||
resolution: {integrity: sha512-gSKJtsaMLiYNwcAdwgnlTVM9zHiHy6/WgJvXFmIoOnUgvMN10Bbr+KO5hoffwgLCCSpIWw6qJoVKMpHBexLm0w==}
|
||||
/@tiptap/pm@2.3.0:
|
||||
resolution: {integrity: sha512-4WYqShZBwDyReKvapC0nmeYdOtZbZ31y4MjolpKQaSD4I7kg/oZspC+byUGdvIRsNpRN7i2X0IyvdISKk8gw5Q==}
|
||||
dependencies:
|
||||
prosemirror-changeset: 2.2.1
|
||||
prosemirror-collab: 1.3.1
|
||||
|
@ -3509,27 +3514,27 @@ packages:
|
|||
prosemirror-view: 1.32.7
|
||||
dev: false
|
||||
|
||||
/@tiptap/suggestion@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6):
|
||||
resolution: {integrity: sha512-/pooAwvUkUB1gKxe4AHAvaNpAvL3FsZrIBJKYR0PF6BNROOHiu4IZY0Zy27ea4vmj72pYrMVlTmeYtSGPzrICg==}
|
||||
/@tiptap/suggestion@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0):
|
||||
resolution: {integrity: sha512-QngwR9ahodVfwqp/kXxJvuL3zNb6XZu+vCuWy8RJrGP8DA7SCI9t8t7iB6NfG4kSsRGxM+3DuLi+2xOZQUaEVQ==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@tiptap/pm': 2.3.0
|
||||
dev: false
|
||||
|
||||
/@tiptap/vue-3@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-F8hC133AF/48cvZReJun5TV35NtRcoH8LVEGsuHGNkH7BvJjXAciomvEO4HlSfqz1YT8M/hzRGNg1/R6ixv3bw==}
|
||||
/@tiptap/vue-3@2.3.0(@tiptap/core@2.3.0)(@tiptap/pm@2.3.0)(vue@3.4.21):
|
||||
resolution: {integrity: sha512-Jgsoouq7gD6SkUf7McOJnKOHqVTVDJkPqhXZUZyJbJ22wD+7drxlauWwWexEymbs95ByhKblreLwcumvbOztgg==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.0.0
|
||||
'@tiptap/pm': ^2.0.0
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
'@tiptap/core': 2.2.6(@tiptap/pm@2.2.6)
|
||||
'@tiptap/extension-bubble-menu': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
'@tiptap/extension-floating-menu': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.6)
|
||||
'@tiptap/pm': 2.2.6
|
||||
'@tiptap/core': 2.3.0(@tiptap/pm@2.3.0)
|
||||
'@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)
|
||||
dev: false
|
||||
|
||||
|
@ -10031,14 +10036,14 @@ packages:
|
|||
vue: 3.4.21(typescript@5.4.5)
|
||||
dev: false
|
||||
|
||||
/vue-i18n@9.11.0(vue@3.4.21):
|
||||
resolution: {integrity: sha512-vU4gY6lu8Pdfs9BgKGiDAJmFDf88cceR47KcSB0VW4xJzUrXR/7qwqM7A8dQ2nedhoIDxoOm5Ro4pFd2KvJqbA==}
|
||||
/vue-i18n@9.11.1(vue@3.4.21):
|
||||
resolution: {integrity: sha512-S7Xi8DkLQG4xnnbxkxzipJK6CdfLdZkmApn95st89HFGp8LTmTH0Tv+Zw6puhOCZJCFrH73PHo3Ylwd2+Bmdxg==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.11.0
|
||||
'@intlify/shared': 9.11.0
|
||||
'@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)
|
||||
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 {
|
||||
|
|
|
@ -156,6 +156,7 @@ const savedFilterProjects = computed(() => projectStore.savedFilterProjects)
|
|||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
width: $navbar-width;
|
||||
overflow-y: auto;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
top: 0;
|
||||
|
|
|
@ -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
|
||||
|
|
5
go.mod
5
go.mod
|
@ -21,7 +21,7 @@ require (
|
|||
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/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
|
||||
|
@ -110,7 +110,6 @@ require (
|
|||
github.com/go-chi/chi/v5 v5.0.10 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.6.1 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.20.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.3 // indirect
|
||||
|
@ -191,6 +190,8 @@ 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
|
||||
|
|
36
go.sum
36
go.sum
|
@ -24,8 +24,6 @@ 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.11.0 h1:PGpwpRZcRiVhsG7VEHb2GWKw4R2ZxB9nc6cMI/7mLD8=
|
||||
github.com/adlio/trello v1.11.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=
|
||||
|
@ -33,6 +31,8 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D
|
|||
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=
|
||||
|
@ -70,8 +70,6 @@ github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4M
|
|||
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
|
||||
github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo=
|
||||
github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4=
|
||||
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
|
||||
github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
|
@ -129,8 +127,6 @@ github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
|||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
|
||||
github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
|
||||
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
|
@ -158,8 +154,6 @@ github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2r
|
|||
github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4=
|
||||
github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
|
@ -311,6 +305,8 @@ 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=
|
||||
|
@ -537,8 +533,6 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7Jul
|
|||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA=
|
||||
github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
|
@ -580,9 +574,6 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
|||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
|
@ -596,7 +587,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -618,9 +608,6 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||
|
@ -631,7 +618,6 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -662,20 +648,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -686,7 +664,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
@ -707,7 +684,6 @@ golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4f
|
|||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
@ -802,8 +778,6 @@ nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYm
|
|||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
src.techknowlogick.com/xgo v1.7.1-0.20240305180710-770b8eae9cec h1:ICDp83UjJvLcOFWHAxr7vmziKIHJkE4jsIF1mbT9Bwk=
|
||||
src.techknowlogick.com/xgo v1.7.1-0.20240305180710-770b8eae9cec/go.mod h1:31CE1YKtDOrKTk9PSnjTpe6YbO6W/0LTYZ1VskL09oU=
|
||||
src.techknowlogick.com/xgo v1.7.1-0.20240403232151-e01c4fbef884 h1:Ttvt8FCpUXfC8r3+LgSPrBUIr/JkHmYQtvmOwEET8qE=
|
||||
src.techknowlogick.com/xgo v1.7.1-0.20240403232151-e01c4fbef884/go.mod h1:31CE1YKtDOrKTk9PSnjTpe6YbO6W/0LTYZ1VskL09oU=
|
||||
src.techknowlogick.com/xormigrate v1.7.1 h1:RKGLLUAqJ+zO8iZ7eOc7oLH7f0cs2gfXSZSvBRBHnlY=
|
||||
|
@ -814,7 +788,5 @@ xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
|||
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/xorm v1.0.5/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
|
||||
xorm.io/xorm v1.3.3/go.mod h1:qFJGFoVYbbIdnz2vaL5OxSQ2raleMpyRRalnq3n9OJo=
|
||||
xorm.io/xorm v1.3.8 h1:CJmplmWqfSRpLWSPMmqz+so8toBp3m7ehuRehIWedZo=
|
||||
xorm.io/xorm v1.3.8/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
||||
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
|
||||
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -93,8 +93,10 @@ type ProjectWithTasksAndBuckets struct {
|
|||
// An array of tasks which belong to the project.
|
||||
Tasks []*TaskWithComments `xorm:"-" json:"tasks"`
|
||||
// Only used for migration.
|
||||
Buckets []*Bucket `xorm:"-" json:"buckets"`
|
||||
BackgroundFileID int64 `xorm:"null" json:"background_file_id"`
|
||||
Buckets []*Bucket `xorm:"-" json:"buckets"`
|
||||
TaskBuckets []*TaskBucket `xorm:"-" json:"task_buckets"`
|
||||
Positions []*TaskPosition `xorm:"-" json:"positions"`
|
||||
BackgroundFileID int64 `xorm:"null" json:"background_file_id"`
|
||||
}
|
||||
|
||||
// TableName returns a better name for the projects table
|
||||
|
@ -110,15 +112,43 @@ 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,
|
||||
Created: time.Now(),
|
||||
Updated: time.Now(),
|
||||
|
||||
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(),
|
||||
}
|
||||
|
||||
// ReadAll gets all projects a user has access to
|
||||
|
@ -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,9 +227,11 @@ func duplicateViews(s *xorm.Session, pd *ProjectDuplicate, doer web.Auth, taskMa
|
|||
})
|
||||
}
|
||||
|
||||
_, err = s.Insert(&taskBuckets)
|
||||
if err != nil {
|
||||
return err
|
||||
if len(taskBuckets) > 0 {
|
||||
_, err = s.Insert(&taskBuckets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
oldTaskPositions := []*TaskPosition{}
|
||||
|
@ -246,7 +249,9 @@ func duplicateViews(s *xorm.Session, pd *ProjectDuplicate, doer web.Auth, taskMa
|
|||
})
|
||||
}
|
||||
|
||||
_, err = s.Insert(&taskPositions)
|
||||
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,11 +253,20 @@ func (tf *TaskCollection) ReadAll(s *xorm.Session, a web.Auth, search string, pa
|
|||
opts.perPage = perPage
|
||||
|
||||
if view != nil {
|
||||
opts.sortby = append(opts.sortby, &sortParam{
|
||||
projectViewID: view.ID,
|
||||
sortBy: taskPropertyPosition,
|
||||
orderBy: orderAscending,
|
||||
})
|
||||
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)
|
||||
|
|
|
@ -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,9 +85,16 @@ func (tc *TaskComment) Create(s *xorm.Session, a web.Auth) (err error) {
|
|||
}
|
||||
tc.AuthorID = tc.Author.ID
|
||||
|
||||
_, err = s.Insert(tc)
|
||||
if err != nil {
|
||||
return
|
||||
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{
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -336,37 +336,39 @@ func convertTrelloDataToVikunja(organizationName string, trelloData []*trello.Bo
|
|||
log.Debugf("[Trello Migration] Downloading %d card attachments from card %s", len(card.Attachments), card.ID)
|
||||
}
|
||||
for _, attachment := range card.Attachments {
|
||||
if !attachment.IsUpload { // There are other types of attachments which are not files. We can only handle files.
|
||||
log.Debugf("[Trello Migration] Attachment %s does not have a mime type, not downloading", attachment.ID)
|
||||
if attachment.IsUpload {
|
||||
// Download file and add it as attachment
|
||||
log.Debugf("[Trello Migration] Downloading card attachment %s", attachment.ID)
|
||||
|
||||
buf, err := migration.DownloadFileWithHeaders(attachment.URL, map[string][]string{
|
||||
"Authorization": {`OAuth oauth_consumer_key="` + config.MigrationTrelloKey.GetString() + `", oauth_token="` + token + `"`},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vikunjaAttachment := &models.TaskAttachment{
|
||||
File: &files.File{
|
||||
Name: attachment.Name,
|
||||
Mime: attachment.MimeType,
|
||||
Size: uint64(buf.Len()),
|
||||
FileContent: buf.Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
if card.IDAttachmentCover != "" && card.IDAttachmentCover == attachment.ID {
|
||||
vikunjaAttachment.ID = 42
|
||||
task.CoverImageAttachmentID = 42
|
||||
}
|
||||
|
||||
task.Attachments = append(task.Attachments, vikunjaAttachment)
|
||||
|
||||
log.Debugf("[Trello Migration] Downloaded card attachment %s", attachment.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("[Trello Migration] Downloading card attachment %s", attachment.ID)
|
||||
|
||||
buf, err := migration.DownloadFileWithHeaders(attachment.URL, map[string][]string{
|
||||
"Authorization": {`OAuth oauth_consumer_key="` + config.MigrationTrelloKey.GetString() + `", oauth_token="` + token + `"`},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vikunjaAttachment := &models.TaskAttachment{
|
||||
File: &files.File{
|
||||
Name: attachment.Name,
|
||||
Mime: attachment.MimeType,
|
||||
Size: uint64(buf.Len()),
|
||||
FileContent: buf.Bytes(),
|
||||
},
|
||||
}
|
||||
|
||||
if card.IDAttachmentCover != "" && card.IDAttachmentCover == attachment.ID {
|
||||
vikunjaAttachment.ID = 42
|
||||
task.CoverImageAttachmentID = 42
|
||||
}
|
||||
|
||||
task.Attachments = append(task.Attachments, vikunjaAttachment)
|
||||
|
||||
log.Debugf("[Trello Migration] Downloaded card attachment %s", attachment.ID)
|
||||
// Other links are not attachments in Vikunja, but we can add them to the description
|
||||
task.Description += `<p><a href="` + attachment.URL + `">` + attachment.Name + "</a></p>\n"
|
||||
}
|
||||
|
||||
// When the cover image was set manually, we need to add it as an attachment
|
||||
|
|
|
@ -78,6 +78,13 @@ func getTestBoard(t *testing.T) ([]*trello.Board, time.Time) {
|
|||
MimeType: "image/jpg",
|
||||
URL: "https://vikunja.io/testimage.jpg",
|
||||
},
|
||||
{
|
||||
ID: "7cc71b16f0c7a57bed3c94e9",
|
||||
Name: "Website",
|
||||
IsUpload: false,
|
||||
MimeType: "",
|
||||
URL: "https://vikunja.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -265,10 +272,11 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
|||
Tasks: []*models.TaskWithComments{
|
||||
{
|
||||
Task: models.Task{
|
||||
Title: "Test Card 1",
|
||||
Description: "<p>Card Description <strong>bold</strong></p>\n",
|
||||
BucketID: 1,
|
||||
DueDate: time1,
|
||||
Title: "Test Card 1",
|
||||
Description: "<p>Card Description <strong>bold</strong></p>\n" +
|
||||
"<p><a href=\"https://vikunja.io\">Website</a></p>\n",
|
||||
BucketID: 1,
|
||||
DueDate: time1,
|
||||
Labels: []*models.Label{
|
||||
{
|
||||
Title: "Label 1",
|
||||
|
@ -481,6 +489,6 @@ func TestCreateOrganizationMap(t *testing.T) {
|
|||
},
|
||||
}
|
||||
if diff, equal := messagediff.PrettyDiff(organizationMap, expectedMap); !equal {
|
||||
t.Errorf("converted trello data = %v,\nwant %v,\ndiff: %v", organizationMap, expectedMap, diff)
|
||||
t.Errorf("converted organization map = %v,\nwant %v,\ndiff: %v", organizationMap, expectedMap, diff)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,10 +156,18 @@ func setupSentry(e *echo.Echo) {
|
|||
if hub != nil {
|
||||
hub.WithScope(func(scope *sentry.Scope) {
|
||||
scope.SetExtra("url", c.Request().URL)
|
||||
hub.CaptureException(herr.Internal)
|
||||
if herr.Internal == nil {
|
||||
hub.CaptureException(err)
|
||||
} else {
|
||||
hub.CaptureException(herr.Internal)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
sentry.CaptureException(herr.Internal)
|
||||
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