feat: port base store to pinia

This commit is contained in:
Dominik Pschenitschni 2022-09-24 15:20:40 +02:00
parent df74f9d80c
commit 7f281fc5e9
No known key found for this signature in database
GPG key ID: B257AC0149F43A77
49 changed files with 450 additions and 541 deletions

View file

@ -59,7 +59,6 @@
"vue-flatpickr-component": "9.0.6", "vue-flatpickr-component": "9.0.6",
"vue-i18n": "9.2.2", "vue-i18n": "9.2.2",
"vue-router": "4.1.5", "vue-router": "4.1.5",
"vuex": "4.0.2",
"workbox-precaching": "6.5.4", "workbox-precaching": "6.5.4",
"zhyswan-vuedraggable": "4.1.3" "zhyswan-vuedraggable": "4.1.3"
}, },

View file

@ -1,4 +1,4 @@
lockfileVersion: 5.3 lockfileVersion: 5.4
specifiers: specifiers:
'@4tw/cypress-drag-drop': 2.2.1 '@4tw/cypress-drag-drop': 2.2.1
@ -77,7 +77,6 @@ specifiers:
vue-i18n: 9.2.2 vue-i18n: 9.2.2
vue-router: 4.1.5 vue-router: 4.1.5
vue-tsc: 0.40.13 vue-tsc: 0.40.13
vuex: 4.0.2
wait-on: 6.0.1 wait-on: 6.0.1
workbox-cli: 6.5.4 workbox-cli: 6.5.4
workbox-precaching: 6.5.4 workbox-precaching: 6.5.4
@ -87,7 +86,7 @@ dependencies:
'@fortawesome/fontawesome-svg-core': 6.2.0 '@fortawesome/fontawesome-svg-core': 6.2.0
'@fortawesome/free-regular-svg-icons': 6.2.0 '@fortawesome/free-regular-svg-icons': 6.2.0
'@fortawesome/free-solid-svg-icons': 6.2.0 '@fortawesome/free-solid-svg-icons': 6.2.0
'@fortawesome/vue-fontawesome': 3.0.1_21e6b971ab1cbc4f6c07645df616013e '@fortawesome/vue-fontawesome': 3.0.1_ehtls4nlds6e63ahmro7mfqbhy
'@github/hotkey': 2.0.1 '@github/hotkey': 2.0.1
'@kyvg/vue3-notification': 2.4.1_vue@3.2.40 '@kyvg/vue3-notification': 2.4.1_vue@3.2.40
'@sentry/tracing': 7.14.0 '@sentry/tracing': 7.14.0
@ -96,7 +95,7 @@ dependencies:
'@types/lodash.clonedeep': 4.5.7 '@types/lodash.clonedeep': 4.5.7
'@types/sortablejs': 1.15.0 '@types/sortablejs': 1.15.0
'@vueuse/core': 9.3.0_vue@3.2.40 '@vueuse/core': 9.3.0_vue@3.2.40
'@vueuse/router': 9.3.0_vue-router@4.1.5+vue@3.2.40 '@vueuse/router': 9.3.0_c7eza3xvlyb4mo6qeit5ggeo6u
axios: 0.27.2 axios: 0.27.2
blurhash: 2.0.2 blurhash: 2.0.2
bulma-css-variables: 0.9.33 bulma-css-variables: 0.9.33
@ -113,7 +112,7 @@ dependencies:
lodash.debounce: 4.0.8 lodash.debounce: 4.0.8
marked: 4.1.1 marked: 4.1.1
minimist: 1.2.6 minimist: 1.2.6
pinia: 2.0.22_typescript@4.8.4+vue@3.2.40 pinia: 2.0.22_bfjwoga25wxjazzogo7o372nwq
register-service-worker: 1.7.2 register-service-worker: 1.7.2
snake-case: 3.0.4 snake-case: 3.0.4
sortablejs: 1.15.0 sortablejs: 1.15.0
@ -125,7 +124,6 @@ dependencies:
vue-flatpickr-component: 9.0.6_vue@3.2.40 vue-flatpickr-component: 9.0.6_vue@3.2.40
vue-i18n: 9.2.2_vue@3.2.40 vue-i18n: 9.2.2_vue@3.2.40
vue-router: 4.1.5_vue@3.2.40 vue-router: 4.1.5_vue@3.2.40
vuex: 4.0.2_vue@3.2.40
workbox-precaching: 6.5.4 workbox-precaching: 6.5.4
zhyswan-vuedraggable: 4.1.3_vue@3.2.40 zhyswan-vuedraggable: 4.1.3_vue@3.2.40
@ -137,11 +135,11 @@ devDependencies:
'@types/dompurify': 2.3.4 '@types/dompurify': 2.3.4
'@types/flexsearch': 0.7.3 '@types/flexsearch': 0.7.3
'@types/node': 16.11.62 '@types/node': 16.11.62
'@typescript-eslint/eslint-plugin': 5.38.1_17e047bdec5ec7c01e9d134b6813cb9c '@typescript-eslint/eslint-plugin': 5.38.1_c7qepppml3d4ahu5cnfwqe6ltq
'@typescript-eslint/parser': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
'@vitejs/plugin-legacy': 2.2.0_terser@5.10.0+vite@3.1.4 '@vitejs/plugin-legacy': 2.2.0_terser@5.10.0+vite@3.1.4
'@vitejs/plugin-vue': 3.1.0_vite@3.1.4+vue@3.2.40 '@vitejs/plugin-vue': 3.1.0_vite@3.1.4+vue@3.2.40
'@vue/eslint-config-typescript': 11.0.2_b985cba226e1126d4cc23df4d3ba9cd4 '@vue/eslint-config-typescript': 11.0.2_xgc4xirg4ejg2tgchx2nhou42q
'@vue/test-utils': 2.1.0_vue@3.2.40 '@vue/test-utils': 2.1.0_vue@3.2.40
'@vue/tsconfig': 0.1.3_@types+node@16.11.62 '@vue/tsconfig': 0.1.3_@types+node@16.11.62
autoprefixer: 10.4.12_postcss@8.4.17 autoprefixer: 10.4.12_postcss@8.4.17
@ -161,12 +159,12 @@ devDependencies:
sass: 1.55.0 sass: 1.55.0
typescript: 4.8.4 typescript: 4.8.4
vite: 3.1.4_sass@1.55.0+terser@5.10.0 vite: 3.1.4_sass@1.55.0+terser@5.10.0
vite-plugin-pwa: 0.13.1_vite@3.1.4 vite-plugin-pwa: 0.13.1_bhe5iaipiq3lmbaxwdxgnnn2gq
vite-svg-loader: 3.6.0 vite-svg-loader: 3.6.0
vitest: 0.23.4_ddc85b0b7a78b2cfae025c8e16b7f605 vitest: 0.23.4_3xefwc32pczm7lqclshbnn7wau
vue-tsc: 0.40.13_typescript@4.8.4 vue-tsc: 0.40.13_typescript@4.8.4
wait-on: 6.0.1 wait-on: 6.0.1
workbox-cli: 6.5.4 workbox-cli: 6.5.4_acorn@8.8.0
packages: packages:
@ -1394,7 +1392,7 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.2 postcss: ^8.2
dependencies: dependencies:
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448 '@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
postcss: 8.4.17 postcss: 8.4.17
postcss-selector-parser: 6.0.10 postcss-selector-parser: 6.0.10
dev: true dev: true
@ -1447,7 +1445,7 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.2 postcss: ^8.2
dependencies: dependencies:
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448 '@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
postcss: 8.4.17 postcss: 8.4.17
postcss-selector-parser: 6.0.10 postcss-selector-parser: 6.0.10
dev: true dev: true
@ -1532,7 +1530,7 @@ packages:
postcss: 8.4.17 postcss: 8.4.17
dev: true dev: true
/@csstools/selector-specificity/2.0.2_cd239324a5aeb6e3cee0fb61f6a33448: /@csstools/selector-specificity/2.0.2_zurzgjffv23ohtxa7nq7nizuja:
resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==} resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==}
engines: {node: ^12 || ^14 || >=16} engines: {node: ^12 || ^14 || >=16}
peerDependencies: peerDependencies:
@ -1681,7 +1679,7 @@ packages:
'@fortawesome/fontawesome-common-types': 6.2.0 '@fortawesome/fontawesome-common-types': 6.2.0
dev: false dev: false
/@fortawesome/vue-fontawesome/3.0.1_21e6b971ab1cbc4f6c07645df616013e: /@fortawesome/vue-fontawesome/3.0.1_ehtls4nlds6e63ahmro7mfqbhy:
resolution: {integrity: sha512-CdXZJoCS+aEPec26ZP7hWWU3SaJlQPZSCGdgpQ2qGl2HUmtUUNrI3zC4XWdn1JUmh3t5OuDeRG1qB4eGRNSD4A==} resolution: {integrity: sha512-CdXZJoCS+aEPec26ZP7hWWU3SaJlQPZSCGdgpQ2qGl2HUmtUUNrI3zC4XWdn1JUmh3t5OuDeRG1qB4eGRNSD4A==}
peerDependencies: peerDependencies:
'@fortawesome/fontawesome-svg-core': ~1 || ~6 '@fortawesome/fontawesome-svg-core': ~1 || ~6
@ -1919,7 +1917,7 @@ packages:
strip-ansi: 7.0.1 strip-ansi: 7.0.1
supports-color: 9.2.1 supports-color: 9.2.1
tmp-promise: 3.0.3 tmp-promise: 3.0.3
ts-node: 10.8.1_8274f11304fdf7eb271c33cd723ceaff ts-node: 10.8.1_qj2pceye7x36wjy4gpgxephk74
typescript: 4.8.4 typescript: 4.8.4
update-notifier: 5.1.0 update-notifier: 5.1.0
uuid: 8.3.2 uuid: 8.3.2
@ -2607,7 +2605,7 @@ packages:
resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==} resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==}
dev: false dev: false
/@rollup/plugin-babel/5.3.0_@babel+core@7.17.2+rollup@2.79.1: /@rollup/plugin-babel/5.3.0_pf2mys4p2khuj2gysypj3zzjia:
resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==} resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
peerDependencies: peerDependencies:
@ -3106,7 +3104,7 @@ packages:
dev: true dev: true
optional: true optional: true
/@typescript-eslint/eslint-plugin/5.38.1_17e047bdec5ec7c01e9d134b6813cb9c: /@typescript-eslint/eslint-plugin/5.38.1_c7qepppml3d4ahu5cnfwqe6ltq:
resolution: {integrity: sha512-ky7EFzPhqz3XlhS7vPOoMDaQnQMn+9o5ICR9CPr/6bw8HrFkzhMSxuA3gRfiJVvs7geYrSeawGJjZoZQKCOglQ==} resolution: {integrity: sha512-ky7EFzPhqz3XlhS7vPOoMDaQnQMn+9o5ICR9CPr/6bw8HrFkzhMSxuA3gRfiJVvs7geYrSeawGJjZoZQKCOglQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3117,10 +3115,10 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/parser': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
'@typescript-eslint/scope-manager': 5.38.1 '@typescript-eslint/scope-manager': 5.38.1
'@typescript-eslint/type-utils': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/type-utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
'@typescript-eslint/utils': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
debug: 4.3.4 debug: 4.3.4
eslint: 8.24.0 eslint: 8.24.0
ignore: 5.2.0 ignore: 5.2.0
@ -3132,7 +3130,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/parser/5.38.1_eslint@8.24.0+typescript@4.8.4: /@typescript-eslint/parser/5.38.1_ypn2ylkkyfa5i233caldtndbqa:
resolution: {integrity: sha512-LDqxZBVFFQnQRz9rUZJhLmox+Ep5kdUmLatLQnCRR6523YV+XhRjfYzStQ4MheFA8kMAfUlclHSbu+RKdRwQKw==} resolution: {integrity: sha512-LDqxZBVFFQnQRz9rUZJhLmox+Ep5kdUmLatLQnCRR6523YV+XhRjfYzStQ4MheFA8kMAfUlclHSbu+RKdRwQKw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3160,7 +3158,7 @@ packages:
'@typescript-eslint/visitor-keys': 5.38.1 '@typescript-eslint/visitor-keys': 5.38.1
dev: true dev: true
/@typescript-eslint/type-utils/5.38.1_eslint@8.24.0+typescript@4.8.4: /@typescript-eslint/type-utils/5.38.1_ypn2ylkkyfa5i233caldtndbqa:
resolution: {integrity: sha512-UU3j43TM66gYtzo15ivK2ZFoDFKKP0k03MItzLdq0zV92CeGCXRfXlfQX5ILdd4/DSpHkSjIgLLLh1NtkOJOAw==} resolution: {integrity: sha512-UU3j43TM66gYtzo15ivK2ZFoDFKKP0k03MItzLdq0zV92CeGCXRfXlfQX5ILdd4/DSpHkSjIgLLLh1NtkOJOAw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3171,7 +3169,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 5.38.1_typescript@4.8.4 '@typescript-eslint/typescript-estree': 5.38.1_typescript@4.8.4
'@typescript-eslint/utils': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
debug: 4.3.4 debug: 4.3.4
eslint: 8.24.0 eslint: 8.24.0
tsutils: 3.21.0_typescript@4.8.4 tsutils: 3.21.0_typescript@4.8.4
@ -3185,7 +3183,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@typescript-eslint/typescript-estree/5.38.1_f1deb5be19df0fe0ff039530117daddf: /@typescript-eslint/typescript-estree/5.38.1_6hpllpqz34h6b7ydsuybc7nn34:
resolution: {integrity: sha512-99b5e/Enoe8fKMLdSuwrfH/C0EIbpUWmeEKHmQlGZb8msY33qn1KlkFww0z26o5Omx7EVjzVDCWEfrfCDHfE7g==} resolution: {integrity: sha512-99b5e/Enoe8fKMLdSuwrfH/C0EIbpUWmeEKHmQlGZb8msY33qn1KlkFww0z26o5Omx7EVjzVDCWEfrfCDHfE7g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3227,7 +3225,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils/5.38.1_eslint@8.24.0+typescript@4.8.4: /@typescript-eslint/utils/5.38.1_ypn2ylkkyfa5i233caldtndbqa:
resolution: {integrity: sha512-oIuUiVxPBsndrN81oP8tXnFa/+EcZ03qLqPDfSZ5xIJVm7A9V0rlkQwwBOAGtrdN70ZKDlKv+l1BeT4eSFxwXA==} resolution: {integrity: sha512-oIuUiVxPBsndrN81oP8tXnFa/+EcZ03qLqPDfSZ5xIJVm7A9V0rlkQwwBOAGtrdN70ZKDlKv+l1BeT4eSFxwXA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3305,7 +3303,7 @@ packages:
magic-string: 0.26.3 magic-string: 0.26.3
regenerator-runtime: 0.13.9 regenerator-runtime: 0.13.9
systemjs: 6.12.6 systemjs: 6.12.6
terser: 5.10.0 terser: 5.10.0_acorn@8.8.0
vite: 3.1.4_sass@1.55.0+terser@5.10.0 vite: 3.1.4_sass@1.55.0+terser@5.10.0
dev: true dev: true
@ -3430,15 +3428,11 @@ packages:
'@vue/compiler-dom': 3.2.40 '@vue/compiler-dom': 3.2.40
'@vue/shared': 3.2.40 '@vue/shared': 3.2.40
/@vue/devtools-api/6.0.9:
resolution: {integrity: sha512-O9tAMBMNMAMzgvbSS3OZlTpfgKCGjvjo5LTjWNtQ/M6A/SKWghJfvoMKuQL/vykLb6rjB/AkaQVFg9yDHprN6w==}
dev: false
/@vue/devtools-api/6.2.1: /@vue/devtools-api/6.2.1:
resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==} resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==}
dev: false dev: false
/@vue/eslint-config-typescript/11.0.2_b985cba226e1126d4cc23df4d3ba9cd4: /@vue/eslint-config-typescript/11.0.2_xgc4xirg4ejg2tgchx2nhou42q:
resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==} resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==}
engines: {node: ^14.17.0 || >=16.0.0} engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -3449,8 +3443,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 5.38.1_17e047bdec5ec7c01e9d134b6813cb9c '@typescript-eslint/eslint-plugin': 5.38.1_c7qepppml3d4ahu5cnfwqe6ltq
'@typescript-eslint/parser': 5.38.1_eslint@8.24.0+typescript@4.8.4 '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa
eslint: 8.24.0 eslint: 8.24.0
eslint-plugin-vue: 9.5.1_eslint@8.24.0 eslint-plugin-vue: 9.5.1_eslint@8.24.0
typescript: 4.8.4 typescript: 4.8.4
@ -3557,7 +3551,7 @@ packages:
resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==} resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==}
dev: false dev: false
/@vueuse/router/9.3.0_vue-router@4.1.5+vue@3.2.40: /@vueuse/router/9.3.0_c7eza3xvlyb4mo6qeit5ggeo6u:
resolution: {integrity: sha512-UFN2MFciprH21oYsAgNHeDJ4Bd86HpRm9gximSN8j6h4fc2aa62fvfhprfHqdTxYAcgcGkMwcc9TO75jOvr8gg==} resolution: {integrity: sha512-UFN2MFciprH21oYsAgNHeDJ4Bd86HpRm9gximSN8j6h4fc2aa62fvfhprfHqdTxYAcgcGkMwcc9TO75jOvr8gg==}
peerDependencies: peerDependencies:
vue-router: '>=4.0.0-rc.1' vue-router: '>=4.0.0-rc.1'
@ -5578,7 +5572,7 @@ packages:
resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==} resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==}
engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0} engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0}
dependencies: dependencies:
'@typescript-eslint/typescript-estree': 5.38.1_f1deb5be19df0fe0ff039530117daddf '@typescript-eslint/typescript-estree': 5.38.1_6hpllpqz34h6b7ydsuybc7nn34
ast-module-types: 3.0.0 ast-module-types: 3.0.0
node-source-walk: 5.0.0 node-source-walk: 5.0.0
typescript: 4.8.4 typescript: 4.8.4
@ -10096,7 +10090,7 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/pinia/2.0.22_typescript@4.8.4+vue@3.2.40: /pinia/2.0.22_bfjwoga25wxjazzogo7o372nwq:
resolution: {integrity: sha512-u+b8/BC+tmvo3ACbYO2w5NfxHWFOjvvw9DQnyT0dW8aUMCPRQT5QnfZ5R5W2MzZBMTeZRMQI7V/QFbafmM9QHw==} resolution: {integrity: sha512-u+b8/BC+tmvo3ACbYO2w5NfxHWFOjvvw9DQnyT0dW8aUMCPRQT5QnfZ5R5W2MzZBMTeZRMQI7V/QFbafmM9QHw==}
peerDependencies: peerDependencies:
'@vue/composition-api': ^1.4.0 '@vue/composition-api': ^1.4.0
@ -10339,7 +10333,7 @@ packages:
peerDependencies: peerDependencies:
postcss: ^8.2 postcss: ^8.2
dependencies: dependencies:
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448 '@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
postcss: 8.4.17 postcss: 8.4.17
postcss-selector-parser: 6.0.10 postcss-selector-parser: 6.0.10
dev: true dev: true
@ -11055,7 +11049,7 @@ packages:
glob: 7.2.0 glob: 7.2.0
dev: true dev: true
/rollup-plugin-terser/7.0.2_rollup@2.79.1: /rollup-plugin-terser/7.0.2_acorn@8.8.0+rollup@2.79.1:
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
peerDependencies: peerDependencies:
rollup: ^2.0.0 rollup: ^2.0.0
@ -11064,7 +11058,9 @@ packages:
jest-worker: 26.6.2 jest-worker: 26.6.2
rollup: 2.79.1 rollup: 2.79.1
serialize-javascript: 4.0.0 serialize-javascript: 4.0.0
terser: 5.10.0 terser: 5.10.0_acorn@8.8.0
transitivePeerDependencies:
- acorn
dev: true dev: true
/rollup-plugin-visualizer/5.8.2_rollup@2.79.1: /rollup-plugin-visualizer/5.8.2_rollup@2.79.1:
@ -11946,10 +11942,12 @@ packages:
supports-hyperlinks: 2.2.0 supports-hyperlinks: 2.2.0
dev: true dev: true
/terser/5.10.0: /terser/5.10.0_acorn@8.8.0:
resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==} resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==}
engines: {node: '>=10'} engines: {node: '>=10'}
hasBin: true hasBin: true
peerDependencies:
acorn: ^8.5.0
peerDependenciesMeta: peerDependenciesMeta:
acorn: acorn:
optional: true optional: true
@ -12155,7 +12153,7 @@ packages:
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==} resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
dev: true dev: true
/ts-node/10.8.1_8274f11304fdf7eb271c33cd723ceaff: /ts-node/10.8.1_qj2pceye7x36wjy4gpgxephk74:
resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==} resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -12553,20 +12551,21 @@ packages:
extsprintf: 1.3.0 extsprintf: 1.3.0
dev: true dev: true
/vite-plugin-pwa/0.13.1_vite@3.1.4: /vite-plugin-pwa/0.13.1_bhe5iaipiq3lmbaxwdxgnnn2gq:
resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==} resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==}
peerDependencies: peerDependencies:
vite: ^3.1.0 vite: ^3.1.0
workbox-build: ^6.5.4
workbox-window: ^6.5.4
dependencies: dependencies:
debug: 4.3.4 debug: 4.3.4
fast-glob: 3.2.11 fast-glob: 3.2.11
pretty-bytes: 6.0.0 pretty-bytes: 6.0.0
rollup: 2.79.1 rollup: 2.79.1
vite: 3.1.4_sass@1.55.0+terser@5.10.0 vite: 3.1.4_sass@1.55.0+terser@5.10.0
workbox-build: 6.5.4 workbox-build: 6.5.4_acorn@8.8.0
workbox-window: 6.5.4 workbox-window: 6.5.4
transitivePeerDependencies: transitivePeerDependencies:
- '@types/babel__core'
- supports-color - supports-color
dev: true dev: true
@ -12601,12 +12600,12 @@ packages:
resolve: 1.22.1 resolve: 1.22.1
rollup: 2.78.0 rollup: 2.78.0
sass: 1.55.0 sass: 1.55.0
terser: 5.10.0 terser: 5.10.0_acorn@8.8.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
dev: true dev: true
/vitest/0.23.4_ddc85b0b7a78b2cfae025c8e16b7f605: /vitest/0.23.4_3xefwc32pczm7lqclshbnn7wau:
resolution: {integrity: sha512-iukBNWqQAv8EKDBUNntspLp9SfpaVFbmzmM0sNcnTxASQZMzRw3PsM6DMlsHiI+I6GeO5/sYDg3ecpC+SNFLrQ==} resolution: {integrity: sha512-iukBNWqQAv8EKDBUNntspLp9SfpaVFbmzmM0sNcnTxASQZMzRw3PsM6DMlsHiI+I6GeO5/sYDg3ecpC+SNFLrQ==}
engines: {node: '>=v14.16.0'} engines: {node: '>=v14.16.0'}
hasBin: true hasBin: true
@ -12757,15 +12756,6 @@ packages:
'@vue/server-renderer': 3.2.40_vue@3.2.40 '@vue/server-renderer': 3.2.40_vue@3.2.40
'@vue/shared': 3.2.40 '@vue/shared': 3.2.40
/vuex/4.0.2_vue@3.2.40:
resolution: {integrity: sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==}
peerDependencies:
vue: ^3.0.2
dependencies:
'@vue/devtools-api': 6.0.9
vue: 3.2.40
dev: false
/wait-on/6.0.1: /wait-on/6.0.1:
resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
@ -12929,7 +12919,7 @@ packages:
workbox-core: 6.5.4 workbox-core: 6.5.4
dev: true dev: true
/workbox-build/6.5.4: /workbox-build/6.5.4_acorn@8.8.0:
resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==} resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
dependencies: dependencies:
@ -12937,7 +12927,7 @@ packages:
'@babel/core': 7.17.2 '@babel/core': 7.17.2
'@babel/preset-env': 7.16.11_@babel+core@7.17.2 '@babel/preset-env': 7.16.11_@babel+core@7.17.2
'@babel/runtime': 7.17.2 '@babel/runtime': 7.17.2
'@rollup/plugin-babel': 5.3.0_@babel+core@7.17.2+rollup@2.79.1 '@rollup/plugin-babel': 5.3.0_pf2mys4p2khuj2gysypj3zzjia
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1 '@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1
'@rollup/plugin-replace': 2.4.2_rollup@2.79.1 '@rollup/plugin-replace': 2.4.2_rollup@2.79.1
'@surma/rollup-plugin-off-main-thread': 2.2.3 '@surma/rollup-plugin-off-main-thread': 2.2.3
@ -12949,7 +12939,7 @@ packages:
lodash: 4.17.21 lodash: 4.17.21
pretty-bytes: 5.6.0 pretty-bytes: 5.6.0
rollup: 2.79.1 rollup: 2.79.1
rollup-plugin-terser: 7.0.2_rollup@2.79.1 rollup-plugin-terser: 7.0.2_acorn@8.8.0+rollup@2.79.1
source-map: 0.8.0-beta.0 source-map: 0.8.0-beta.0
stringify-object: 3.3.0 stringify-object: 3.3.0
strip-comments: 2.0.1 strip-comments: 2.0.1
@ -12972,6 +12962,7 @@ packages:
workbox-window: 6.5.4 workbox-window: 6.5.4
transitivePeerDependencies: transitivePeerDependencies:
- '@types/babel__core' - '@types/babel__core'
- acorn
- supports-color - supports-color
dev: true dev: true
@ -12981,7 +12972,7 @@ packages:
workbox-core: 6.5.4 workbox-core: 6.5.4
dev: true dev: true
/workbox-cli/6.5.4: /workbox-cli/6.5.4_acorn@8.8.0:
resolution: {integrity: sha512-+Cc0jYh25MofhCROZqfQkpYSAGvykyrUVekuuPaLFbJ8qxX/zzX8hRRpglfwxDwokAjz8S20oEph4s+MyQc+Yw==} resolution: {integrity: sha512-+Cc0jYh25MofhCROZqfQkpYSAGvykyrUVekuuPaLFbJ8qxX/zzX8hRRpglfwxDwokAjz8S20oEph4s+MyQc+Yw==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
hasBin: true hasBin: true
@ -12998,9 +12989,10 @@ packages:
stringify-object: 3.3.0 stringify-object: 3.3.0
upath: 1.2.0 upath: 1.2.0
update-notifier: 4.1.3 update-notifier: 4.1.3
workbox-build: 6.5.4 workbox-build: 6.5.4_acorn@8.8.0
transitivePeerDependencies: transitivePeerDependencies:
- '@types/babel__core' - '@types/babel__core'
- acorn
- supports-color - supports-color
dev: true dev: true

View file

@ -18,7 +18,6 @@
import {computed, watch, type Ref} from 'vue' import {computed, watch, type Ref} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useRouteQuery} from '@vueuse/router' import {useRouteQuery} from '@vueuse/router'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import isTouchDevice from 'is-touch-device' import isTouchDevice from 'is-touch-device'
import {success} from '@/message' import {success} from '@/message'
@ -34,16 +33,17 @@ import Ready from '@/components/misc/ready.vue'
import {setLanguage} from './i18n' import {setLanguage} from './i18n'
import AccountDeleteService from '@/services/accountDelete' import AccountDeleteService from '@/services/accountDelete'
import {useBaseStore} from '@/stores/base'
import {useColorScheme} from '@/composables/useColorScheme' import {useColorScheme} from '@/composables/useColorScheme'
import {useBodyClass} from '@/composables/useBodyClass' import {useBodyClass} from '@/composables/useBodyClass'
import {useAuthStore} from './stores/auth' import {useAuthStore} from './stores/auth'
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const router = useRouter() const router = useRouter()
useBodyClass('is-touch', isTouchDevice()) useBodyClass('is-touch', isTouchDevice())
const keyboardShortcutsActive = computed(() => store.state.keyboardShortcutsActive) const keyboardShortcutsActive = computed(() => baseStore.keyboardShortcutsActive)
const authUser = computed(() => authStore.authUser) const authUser = computed(() => authStore.authUser)
const authLinkShare = computed(() => authStore.authLinkShare) const authLinkShare = computed(() => authStore.authLinkShare)

View file

@ -1,8 +1,8 @@
<template> <template>
<BaseButton <BaseButton
class="menu-show-button" class="menu-show-button"
@click="$store.commit('toggleMenu')" @click="baseStore.toggleMenu()"
@shortkey="() => $store.commit('toggleMenu')" @shortkey="() => baseStore.toggleMenu()"
v-shortcut="'Control+e'" v-shortcut="'Control+e'"
:title="$t('keyboardShortcuts.toggleMenu')" :title="$t('keyboardShortcuts.toggleMenu')"
:aria-label="menuActive ? $t('misc.hideMenu') : $t('misc.showMenu')" :aria-label="menuActive ? $t('misc.hideMenu') : $t('misc.showMenu')"
@ -11,12 +11,12 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed} from 'vue' import {computed} from 'vue'
import {useStore} from '@/store' import {useBaseStore} from '@/stores/base'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
const store = useStore() const baseStore = useBaseStore()
const menuActive = computed(() => store.state.menuActive) const menuActive = computed(() => baseStore.menuActive)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -70,7 +70,7 @@
{{ $t('navigation.privacy') }} {{ $t('navigation.privacy') }}
</dropdown-item> </dropdown-item>
<dropdown-item <dropdown-item
@click="$store.commit('keyboardShortcutsActive', true)" @click="baseStore.setKeyboardShortcutsActive(true)"
> >
{{ $t('keyboardShortcuts.title') }} {{ $t('keyboardShortcuts.title') }}
</dropdown-item> </dropdown-item>
@ -92,9 +92,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, computed, onMounted, nextTick} from 'vue' import {ref, computed, onMounted, nextTick} from 'vue'
import {useStore} from '@/store'
import {QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
import {RIGHTS as Rights} from '@/constants/rights' import {RIGHTS as Rights} from '@/constants/rights'
import Update from '@/components/home/update.vue' import Update from '@/components/home/update.vue'
@ -107,21 +105,24 @@ import BaseButton from '@/components/base/BaseButton.vue'
import MenuButton from '@/components/home/MenuButton.vue' import MenuButton from '@/components/home/MenuButton.vue'
import {getListTitle} from '@/helpers/getListTitle' import {getListTitle} from '@/helpers/getListTitle'
import {useBaseStore} from '@/stores/base'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const currentList = computed(() => baseStore.currentList)
const configStore = useConfigStore() const background = computed(() => baseStore.background)
const canWriteCurrentList = computed(() => baseStore.currentList.maxRight > Rights.READ)
const menuActive = computed(() => baseStore.menuActive)
const authStore = useAuthStore()
const userInfo = computed(() => authStore.info) const userInfo = computed(() => authStore.info)
const userAvatar = computed(() => authStore.avatarUrl) const userAvatar = computed(() => authStore.avatarUrl)
const currentList = computed(() => store.state.currentList)
const background = computed(() => store.state.background) const configStore = useConfigStore()
const imprintUrl = computed(() => configStore.legal.imprintUrl) const imprintUrl = computed(() => configStore.legal.imprintUrl)
const privacyPolicyUrl = computed(() => configStore.legal.privacyPolicyUrl) const privacyPolicyUrl = computed(() => configStore.legal.privacyPolicyUrl)
const canWriteCurrentList = computed(() => store.state.currentList.maxRight > Rights.READ)
const menuActive = computed(() => store.state.menuActive)
const usernameDropdown = ref() const usernameDropdown = ref()
const listTitle = ref() const listTitle = ref()
@ -140,7 +141,7 @@ function logout() {
} }
function openQuickActions() { function openQuickActions() {
store.commit(QUICK_ACTIONS_ACTIVE, true) baseStore.setQuickActionsActive(true)
} }
</script> </script>

View file

@ -2,7 +2,7 @@
<div class="content-auth"> <div class="content-auth">
<BaseButton <BaseButton
v-if="menuActive" v-if="menuActive"
@click="$store.commit('menuActive', false)" @click="baseStore.setMenuActive(false)"
class="menu-hide-button d-print-none" class="menu-hide-button d-print-none"
> >
<icon icon="times"/> <icon icon="times"/>
@ -26,7 +26,7 @@
> >
<BaseButton <BaseButton
v-if="menuActive" v-if="menuActive"
@click="$store.commit('menuActive', false)" @click="baseStore.setMenuActive(false)"
class="mobile-overlay d-print-none" class="mobile-overlay d-print-none"
/> />
@ -61,11 +61,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import {watch, computed, shallowRef, watchEffect, type VNode, h} from 'vue' import {watch, computed, shallowRef, watchEffect, type VNode, h} from 'vue'
import {useStore} from '@/store' import {useBaseStore} from '@/stores/base'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useEventListener} from '@vueuse/core' import {useEventListener} from '@vueuse/core'
import {CURRENT_LIST, KEYBOARD_SHORTCUTS_ACTIVE, MENU_ACTIVE} from '@/store/mutation-types'
import {useLabelStore} from '@/stores/labels' import {useLabelStore} from '@/stores/labels'
import Navigation from '@/components/home/navigation.vue' import Navigation from '@/components/home/navigation.vue'
import QuickActions from '@/components/quick-actions/quick-actions.vue' import QuickActions from '@/components/quick-actions/quick-actions.vue'
@ -123,20 +122,19 @@ function useRouteWithModal() {
const {routeWithModal, currentModal, closeModal} = useRouteWithModal() const {routeWithModal, currentModal, closeModal} = useRouteWithModal()
const store = useStore() const baseStore = useBaseStore()
const background = computed(() => baseStore.background)
const background = computed(() => store.state.background) const blurHash = computed(() => baseStore.blurHash)
const blurHash = computed(() => store.state.blurHash) const menuActive = computed(() => baseStore.menuActive)
const menuActive = computed(() => store.state.menuActive)
function showKeyboardShortcuts() { function showKeyboardShortcuts() {
store.commit(KEYBOARD_SHORTCUTS_ACTIVE, true) baseStore.setKeyboardShortcutsActive(true)
} }
const route = useRoute() const route = useRoute()
// hide menu on mobile // hide menu on mobile
watch(() => route.fullPath, () => window.innerWidth < 769 && store.commit(MENU_ACTIVE, false)) watch(() => route.fullPath, () => window.innerWidth < 769 && baseStore.setMenuActive(false))
// FIXME: this is really error prone // FIXME: this is really error prone
// Reset the current list highlight in menu if the current route is not list related. // Reset the current list highlight in menu if the current route is not list related.
@ -158,7 +156,7 @@ watch(() => route.name as string, (routeName) => {
routeName.startsWith('user.settings') routeName.startsWith('user.settings')
) )
) { ) {
store.dispatch(CURRENT_LIST, {list: null}) baseStore.handleSetCurrentList({list: null})
} }
}) })

View file

@ -24,15 +24,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import {computed} from 'vue' import {computed} from 'vue'
import {useStore} from '@/store'
import {useBaseStore} from '@/stores/base'
import Logo from '@/components/home/Logo.vue' import Logo from '@/components/home/Logo.vue'
import PoweredByLink from './PoweredByLink.vue' import PoweredByLink from './PoweredByLink.vue'
const store = useStore() const baseStore = useBaseStore()
const currentList = computed(() => store.state.currentList) const currentList = computed(() => baseStore.currentList)
const background = computed(() => store.state.background) const background = computed(() => baseStore.background)
const logoVisible = computed(() => store.state.logoVisible) const logoVisible = computed(() => baseStore.logoVisible)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -141,7 +141,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, computed, onMounted, onBeforeMount} from 'vue' import {ref, computed, onMounted, onBeforeMount} from 'vue'
import {useStore} from '@/store'
import draggable from 'zhyswan-vuedraggable' import draggable from 'zhyswan-vuedraggable'
import type {SortableEvent} from 'sortablejs' import type {SortableEvent} from 'sortablejs'
@ -151,7 +150,6 @@ import NamespaceSettingsDropdown from '@/components/namespace/namespace-settings
import PoweredByLink from '@/components/home/PoweredByLink.vue' import PoweredByLink from '@/components/home/PoweredByLink.vue'
import Logo from '@/components/home/Logo.vue' import Logo from '@/components/home/Logo.vue'
import {MENU_ACTIVE} from '@/store/mutation-types'
import {calculateItemPosition} from '@/helpers/calculateItemPosition' import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle' import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {getListTitle} from '@/helpers/getListTitle' import {getListTitle} from '@/helpers/getListTitle'
@ -159,6 +157,8 @@ import {useEventListener} from '@vueuse/core'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import type {INamespace} from '@/modelTypes/INamespace' import type {INamespace} from '@/modelTypes/INamespace'
import ColorBubble from '@/components/misc/colorBubble.vue' import ColorBubble from '@/components/misc/colorBubble.vue'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
@ -168,10 +168,10 @@ const dragOptions = {
ghostClass: 'ghost', ghostClass: 'ghost',
} }
const store = useStore() const baseStore = useBaseStore()
const namespaceStore = useNamespaceStore() const namespaceStore = useNamespaceStore()
const currentList = computed(() => store.state.currentList) const currentList = computed(() => baseStore.currentList)
const menuActive = computed(() => store.state.menuActive) const menuActive = computed(() => baseStore.menuActive)
const loading = computed(() => namespaceStore.isLoading) const loading = computed(() => namespaceStore.isLoading)
@ -202,7 +202,7 @@ const listStore = useListStore()
function resize() { function resize() {
// Hide the menu by default on mobile // Hide the menu by default on mobile
store.commit(MENU_ACTIVE, window.innerWidth >= 770) baseStore.setMenuActive(window.innerWidth >= 770)
} }
function toggleLists(namespaceId: INamespace['id']) { function toggleLists(namespaceId: INamespace['id']) {
@ -262,7 +262,7 @@ async function saveListPosition(e: SortableEvent) {
) )
try { try {
// create a copy of the list in order to not violate vuex mutations // create a copy of the list in order to not violate pinia manipulation
await listStore.updateList({ await listStore.updateList({
...list, ...list,
position, position,

View file

@ -1,22 +1,25 @@
<template> <template>
<card class="filters has-overflow" :title="hasTitle ? $t('filters.title') : ''"> <card class="filters has-overflow" :title="hasTitle ? $t('filters.title') : ''">
<div class="field is-flex is-flex-direction-column"> <div class="field is-flex is-flex-direction-column">
<fancycheckbox v-model="params.filter_include_nulls" @change="change()"> <fancycheckbox
v-model="params.filter_include_nulls"
@update:model-value="change()"
>
{{ $t('filters.attributes.includeNulls') }} {{ $t('filters.attributes.includeNulls') }}
</fancycheckbox> </fancycheckbox>
<fancycheckbox <fancycheckbox
v-model="filters.requireAllFilters" v-model="filters.requireAllFilters"
@change="setFilterConcat()" @update:model-value="setFilterConcat()"
> >
{{ $t('filters.attributes.requireAll') }} {{ $t('filters.attributes.requireAll') }}
</fancycheckbox> </fancycheckbox>
<fancycheckbox @change="setDoneFilter" v-model="filters.done"> <fancycheckbox v-model="filters.done" @update:model-value="setDoneFilter">
{{ $t('filters.attributes.showDoneTasks') }} {{ $t('filters.attributes.showDoneTasks') }}
</fancycheckbox> </fancycheckbox>
<fancycheckbox <fancycheckbox
v-if="!$route.name.includes('list.kanban') || !$route.name.includes('list.table')" v-if="!$route.name.includes('list.kanban') || !$route.name.includes('list.table')"
v-model="sortAlphabetically" v-model="sortAlphabetically"
@change="change()" @update:model-value="change()"
> >
{{ $t('filters.attributes.sortAlphabetically') }} {{ $t('filters.attributes.sortAlphabetically') }}
</fancycheckbox> </fancycheckbox>
@ -43,7 +46,7 @@
/> />
<fancycheckbox <fancycheckbox
v-model="filters.usePriority" v-model="filters.usePriority"
@change="setPriority" @update:model-value="setPriority"
> >
{{ $t('filters.attributes.enablePriority') }} {{ $t('filters.attributes.enablePriority') }}
</fancycheckbox> </fancycheckbox>
@ -59,7 +62,7 @@
/> />
<fancycheckbox <fancycheckbox
v-model="filters.usePercentDone" v-model="filters.usePercentDone"
@change="setPercentDoneFilter" @update:model-value="setPercentDoneFilter"
> >
{{ $t('filters.attributes.enablePercentDone') }} {{ $t('filters.attributes.enablePercentDone') }}
</fancycheckbox> </fancycheckbox>

View file

@ -33,18 +33,15 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {useStore} from '@/store' import {useBaseStore} from '@/stores/base'
import Shortcut from '@/components/misc/shortcut.vue' import Shortcut from '@/components/misc/shortcut.vue'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {KEYBOARD_SHORTCUTS_ACTIVE} from '@/store/mutation-types'
import {KEYBOARD_SHORTCUTS as shortcuts} from './shortcuts' import {KEYBOARD_SHORTCUTS as shortcuts} from './shortcuts'
const store = useStore()
function close() { function close() {
store.commit(KEYBOARD_SHORTCUTS_ACTIVE, false) useBaseStore().setKeyboardShortcutsActive(false)
} }
</script> </script>

View file

@ -42,7 +42,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import {ref, computed} from 'vue' import {ref, computed} from 'vue'
import {useStore} from '@/store' import {useRouter, useRoute} from 'vue-router'
import Logo from '@/assets/logo.svg?component' import Logo from '@/assets/logo.svg?component'
import ApiConfig from '@/components/misc/api-config.vue' import ApiConfig from '@/components/misc/api-config.vue'
@ -52,13 +52,14 @@ import NoAuthWrapper from '@/components/misc/no-auth-wrapper.vue'
import {ERROR_NO_API_URL} from '@/helpers/checkAndSetApiUrl' import {ERROR_NO_API_URL} from '@/helpers/checkAndSetApiUrl'
import {useOnline} from '@/composables/useOnline' import {useOnline} from '@/composables/useOnline'
import {useRouter, useRoute} from 'vue-router'
import {getAuthForRoute} from '@/router' import {getAuthForRoute} from '@/router'
import {useBaseStore} from '@/stores/base'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const store = useStore() const baseStore = useBaseStore()
const ready = ref(false) const ready = ref(false)
const online = useOnline() const online = useOnline()
@ -68,7 +69,7 @@ const showLoading = computed(() => !ready.value && error.value === '')
async function load() { async function load() {
try { try {
await store.dispatch('loadApp') await baseStore.loadApp()
const redirectTo = getAuthForRoute(route) const redirectTo = getAuthForRoute(route)
if (typeof redirectTo !== 'undefined') { if (typeof redirectTo !== 'undefined') {
await router.push(redirectTo) await router.push(redirectTo)

View file

@ -61,7 +61,6 @@ import TeamService from '@/services/team'
import NamespaceModel from '@/models/namespace' import NamespaceModel from '@/models/namespace'
import TeamModel from '@/models/team' import TeamModel from '@/models/team'
import {CURRENT_LIST, LOADING, LOADING_MODULE, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
import ListModel from '@/models/list' import ListModel from '@/models/list'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
@ -70,6 +69,8 @@ import {getHistory} from '@/modules/listHistory'
import {parseTaskText, PrefixMode} from '@/modules/parseTaskText' import {parseTaskText, PrefixMode} from '@/modules/parseTaskText'
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode' import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
import {PREFIXES} from '@/modules/parseTaskText' import {PREFIXES} from '@/modules/parseTaskText'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
import {useLabelStore} from '@/stores/labels' import {useLabelStore} from '@/stores/labels'
@ -112,8 +113,10 @@ export default defineComponent({
}, },
computed: { computed: {
active() { active() {
const active = this.$store.state[QUICK_ACTIONS_ACTIVE] const active = useBaseStore().quickActionsActive
if (!active) { if (!active) {
// FIXME: computeds shouldn't have side effects.
// create a watcher instead
this.reset() this.reset()
} }
return active return active
@ -181,8 +184,7 @@ export default defineComponent({
}, },
loading() { loading() {
return this.taskService.loading || return this.taskService.loading ||
(this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'namespaces') || useNamespaceStore().isLoading || useListStore().isLoading ||
(this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'lists') ||
this.teamService.loading this.teamService.loading
}, },
placeholder() { placeholder() {
@ -219,7 +221,8 @@ export default defineComponent({
return this.$t('quickActions.hint', prefixes) return this.$t('quickActions.hint', prefixes)
}, },
currentList() { currentList() {
return Object.keys(this.$store.state[CURRENT_LIST]).length === 0 ? null : this.$store.state[CURRENT_LIST] const currentList = useBaseStore().currentList
return Object.keys(currentList).length === 0 ? null : currentList
}, },
availableCmds() { availableCmds() {
const cmds = [] const cmds = []
@ -360,7 +363,7 @@ export default defineComponent({
}, 150) }, 150)
}, },
closeQuickActions() { closeQuickActions() {
this.$store.commit(QUICK_ACTIONS_ACTIVE, false) useBaseStore().setQuickActionsActive(false)
}, },
doAction(type, item) { doAction(type, item) {
switch (type) { switch (type) {

View file

@ -173,6 +173,7 @@
<script lang="ts"> <script lang="ts">
import {defineComponent} from 'vue' import {defineComponent} from 'vue'
import {mapState} from 'pinia'
import VueDragResize from 'vue-drag-resize' import VueDragResize from 'vue-drag-resize'
import EditTask from './edit-task.vue' import EditTask from './edit-task.vue'
@ -182,7 +183,6 @@ import TaskModel from '../../models/task'
import {PRIORITIES as priorities} from '@/constants/priorities' import {PRIORITIES as priorities} from '@/constants/priorities'
import PriorityLabel from './partials/priorityLabel.vue' import PriorityLabel from './partials/priorityLabel.vue'
import TaskCollectionService from '../../services/taskCollection' import TaskCollectionService from '../../services/taskCollection'
import {mapState} from 'vuex'
import {RIGHTS as Rights} from '@/constants/rights' import {RIGHTS as Rights} from '@/constants/rights'
import FilterPopup from '@/components/list/partials/filter-popup.vue' import FilterPopup from '@/components/list/partials/filter-popup.vue'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
@ -190,6 +190,8 @@ import BaseButton from '@/components/base/BaseButton.vue'
import {colorIsDark} from '@/helpers/color/colorIsDark' import {colorIsDark} from '@/helpers/color/colorIsDark'
import {formatDate} from '@/helpers/time/formatDate' import {formatDate} from '@/helpers/time/formatDate'
import {useBaseStore} from '@/stores/base'
export default defineComponent({ export default defineComponent({
name: 'GanttChart', name: 'GanttChart',
components: { components: {
@ -256,7 +258,7 @@ export default defineComponent({
mounted() { mounted() {
this.buildTheGanttChart() this.buildTheGanttChart()
}, },
computed: mapState({ computed: mapState(useBaseStore, {
canWrite: (state) => state.currentList.maxRight > Rights.READ, canWrite: (state) => state.currentList.maxRight > Rights.READ,
}), }),
methods: { methods: {

View file

@ -41,13 +41,13 @@ import {ref, computed, type PropType} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
import ColorBubble from '@/components/misc/colorBubble.vue'
import Done from '@/components/misc/Done.vue' import Done from '@/components/misc/Done.vue'
import {useCopyToClipboard} from '@/composables/useCopyToClipboard' import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
import {useTaskStore} from '@/stores/tasks'
import type {ITask} from '@/modelTypes/ITask' import type {ITask} from '@/modelTypes/ITask'
import ColorBubble from '@/components/misc/colorBubble.vue'
import {useTaskStore} from '@/stores/tasks'
const props = defineProps({ const props = defineProps({
task: { task: {

View file

@ -35,7 +35,7 @@
{{ task.title }} {{ task.title }}
</span> </span>
<labels class="labels ml-2 mr-1" :labels="task.labels" v-if="task.labels.length > 0"/> <labels class="labels ml-2 mr-1" :labels="task.labels" v-if="task.labels.length > 0" />
<user <user
:avatar-size="27" :avatar-size="27"
:is-inline="true" :is-inline="true"
@ -119,6 +119,7 @@ import {formatDateSince, formatISO, formatDateLong} from '@/helpers/time/formatD
import ColorBubble from '@/components/misc/colorBubble.vue' import ColorBubble from '@/components/misc/colorBubble.vue'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
import {useBaseStore} from '@/stores/base'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
export default defineComponent({ export default defineComponent({
@ -188,10 +189,11 @@ export default defineComponent({
return list !== null ? list.hexColor : '' return list !== null ? list.hexColor : ''
}, },
currentList() { currentList() {
return typeof this.$store.state.currentList === 'undefined' ? { const baseStore = useBaseStore()
return typeof baseStore.currentList === 'undefined' ? {
id: 0, id: 0,
title: '', title: '',
} : this.$store.state.currentList } : baseStore.currentList
}, },
taskDetailRoute() { taskDetailRoute() {
return { return {
@ -238,8 +240,7 @@ export default defineComponent({
this.task.isFavorite = !this.task.isFavorite this.task.isFavorite = !this.task.isFavorite
this.task = await this.taskService.update(this.task) this.task = await this.taskService.update(this.task)
this.$emit('task-updated', this.task) this.$emit('task-updated', this.task)
const namespaceStore = useNamespaceStore() useNamespaceStore().loadNamespacesIfFavoritesDontExist()
namespaceStore.loadNamespacesIfFavoritesDontExist()
}, },
hideDeferDueDatePopup(e) { hideDeferDueDatePopup(e) {
if (!this.showDefer) { if (!this.showDefer) {

View file

@ -1,5 +1,5 @@
// Save the current list view to local storage // Save the current list view to local storage
// We use local storage and not vuex here to make it persistent across reloads. // We use local storage and not a store here to make it persistent across reloads.
export const saveListView = (listId, routeName) => { export const saveListView = (listId, routeName) => {
if (routeName.includes('settings.')) { if (routeName.includes('settings.')) {
return return

View file

@ -14,8 +14,6 @@ import Notifications from '@kyvg/vue3-notification'
// PWA // PWA
import './registerServiceWorker' import './registerServiceWorker'
// Vuex
import { store, key } from './store'
// i18n // i18n
import {i18n} from './i18n' import {i18n} from './i18n'
@ -106,8 +104,6 @@ if (window.SENTRY_ENABLED) {
} }
app.use(pinia) app.use(pinia)
app.use(store, key) // pass the injection key
app.use(router) app.use(router)
app.use(i18n) app.use(i18n)

View file

@ -1,7 +1,7 @@
import AbstractModel from './abstractModel' import AbstractModel from './abstractModel'
import UserSettingsModel from '@/models/userSettings' import UserSettingsModel from '@/models/userSettings'
import { AUTH_TYPES, type IUser } from '@/modelTypes/IUser' import { AUTH_TYPES, type IUser, type AuthType } from '@/modelTypes/IUser'
import type { IUserSettings } from '@/modelTypes/IUserSettings' import type { IUserSettings } from '@/modelTypes/IUserSettings'
export function getAvatarUrl(user: IUser, size = 50) { export function getAvatarUrl(user: IUser, size = 50) {
@ -22,7 +22,7 @@ export default class UserModel extends AbstractModel<IUser> implements IUser {
username = '' username = ''
name = '' name = ''
exp = 0 exp = 0
type = AUTH_TYPES.UNKNOWN type: AuthType = AUTH_TYPES.UNKNOWN
created: Date created: Date
updated: Date updated: Date

View file

@ -1,53 +0,0 @@
import type { ActionContext } from 'vuex'
import type { StoreDefinition } from 'pinia'
import {LOADING, LOADING_MODULE} from './mutation-types'
import type { RootStoreState } from './types'
/**
* This helper sets the loading state with a 100ms delay to avoid flickering.
*
* @param {*} context The vuex module context.
* @param {null|String} module The module that is loading. This parameter allows components to listen for specific parts of the application loading.
* @param {null|function} loadFunc If not null, this function will be executed instead of the default setting loading.
*/
export function setLoading<State>(
context : ActionContext<State, RootStoreState>,
module : string | null = null,
loadFunc : (() => void) | null = null,
) {
const timeout = setTimeout(() => {
if (loadFunc === null) {
context.commit(LOADING, true, {root: true})
context.commit(LOADING_MODULE, module, {root: true})
} else {
loadFunc(true)
}
}, 100)
return () => {
clearTimeout(timeout)
if (loadFunc === null) {
context.commit(LOADING, false, {root: true})
context.commit(LOADING_MODULE, null, {root: true})
} else {
loadFunc(false)
}
}
}
export const setLoadingPinia = (store: StoreDefinition, loadFunc : ((isLoading: boolean) => void) | null = null) => {
const timeout = setTimeout(() => {
if (loadFunc === null) {
store.isLoading = true
} else {
loadFunc(true)
}
}, 100)
return () => {
clearTimeout(timeout)
if (loadFunc === null) {
store.isLoading = false
} else {
loadFunc(false)
}
}
}

View file

@ -1,12 +0,0 @@
export const LOADING = 'loading'
export const LOADING_MODULE = 'loadingModule'
export const CURRENT_LIST = 'currentList'
export const HAS_TASKS = 'hasTasks'
export const MENU_ACTIVE = 'menuActive'
export const KEYBOARD_SHORTCUTS_ACTIVE = 'keyboardShortcutsActive'
export const QUICK_ACTIONS_ACTIVE = 'quickActionsActive'
export const BACKGROUND = 'background'
export const BLUR_HASH = 'blurHash'
export const LOGO_VISIBLE = 'logoVisible'
export const CONFIG = 'config'

View file

@ -1,114 +0,0 @@
import type { IBucket } from '@/modelTypes/IBucket'
import type { IUserSettings } from '@/modelTypes/IUserSettings'
import type { IList } from '@/modelTypes/IList'
import type { IAttachment } from '@/modelTypes/IAttachment'
import type { ILabel } from '@/modelTypes/ILabel'
import type { INamespace } from '@/modelTypes/INamespace'
import type { IUser } from '@/modelTypes/IUser'
export interface RootStoreState {
loading: boolean,
loadingModule: null,
currentList: IList,
background: string,
blurHash: string,
hasTasks: boolean,
menuActive: boolean,
keyboardShortcutsActive: boolean,
quickActionsActive: boolean,
logoVisible: boolean,
}
export interface AttachmentState {
attachments: IAttachment[],
}
export interface AuthState {
authenticated: boolean,
isLinkShareAuth: boolean,
info: IUser | null,
needsTotpPasscode: boolean,
avatarUrl: string,
lastUserInfoRefresh: Date | null,
settings: IUserSettings,
isLoading: boolean,
isLoadingGeneralSettings: boolean
}
export interface ConfigState {
version: string,
frontendUrl: string,
motd: string,
linkSharingEnabled: boolean,
maxFileSize: '20MB',
registrationEnabled: boolean,
availableMigrators: [],
taskAttachmentsEnabled: boolean,
totpEnabled: boolean,
enabledBackgroundProviders: [],
legal: {
imprintUrl: string,
privacyPolicyUrl: string,
},
caldavEnabled: boolean,
userDeletionEnabled: boolean,
taskCommentsEnabled: boolean,
auth: {
local: {
enabled: boolean,
},
openidConnect: {
enabled: boolean,
redirectUrl: string,
providers: [],
},
},
}
export interface KanbanState {
buckets: IBucket[],
listId: IList['id'],
bucketLoading: {
[id: IBucket['id']]: boolean
},
taskPagesPerBucket: {
[id: IBucket['id']]: number
},
allTasksLoadedForBucket: {
[id: IBucket['id']]: boolean
},
isLoading: boolean,
}
export interface LabelState {
labels: {
[id: ILabel['id']]: ILabel
},
isLoading: boolean,
}
export interface ListState {
lists: { [id: IList['id']]: IList },
isLoading: boolean,
}
export interface NamespaceState {
namespaces: INamespace[]
isLoading: boolean,
}
export interface TaskState {
isLoading: boolean,
}
export type StoreState = RootStoreState & {
config: ConfigState,
auth: AuthState,
namespaces: NamespaceState,
kanban: KanbanState,
tasks: TaskState,
lists: ListState,
attachments: AttachmentState,
labels: LabelState,
}

View file

@ -1,9 +1,12 @@
import {defineStore, acceptHMRUpdate} from 'pinia' import {defineStore, acceptHMRUpdate} from 'pinia'
import {findIndexById} from '@/helpers/utils' import {findIndexById} from '@/helpers/utils'
import type {AttachmentState} from '@/store/types'
import type {IAttachment} from '@/modelTypes/IAttachment' import type {IAttachment} from '@/modelTypes/IAttachment'
export interface AttachmentState {
attachments: IAttachment[],
}
export const useAttachmentStore = defineStore('attachment', { export const useAttachmentStore = defineStore('attachment', {
state: (): AttachmentState => ({ state: (): AttachmentState => ({
attachments: [], attachments: [],

View file

@ -6,16 +6,27 @@ import {objectToSnakeCase} from '@/helpers/case'
import UserModel, { getAvatarUrl } from '@/models/user' import UserModel, { getAvatarUrl } from '@/models/user'
import UserSettingsService from '@/services/userSettings' import UserSettingsService from '@/services/userSettings'
import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth' import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth'
import {setLoadingPinia} from '@/store/helper' import {setLoadingPinia} from '@/stores/helper'
import {success} from '@/message' import {success} from '@/message'
import {redirectToProvider} from '@/helpers/redirectToProvider' import {redirectToProvider} from '@/helpers/redirectToProvider'
import {AUTH_TYPES, type IUser} from '@/modelTypes/IUser' import {AUTH_TYPES, type IUser} from '@/modelTypes/IUser'
import type {AuthState} from '@/store/types'
import type {IUserSettings} from '@/modelTypes/IUserSettings' import type {IUserSettings} from '@/modelTypes/IUserSettings'
import router from '@/router' import router from '@/router'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
import {useBaseStore} from '@/stores/base'
import UserSettingsModel from '@/models/userSettings' import UserSettingsModel from '@/models/userSettings'
import {store} from '@/store'
export interface AuthState {
authenticated: boolean,
isLinkShareAuth: boolean,
info: IUser | null,
needsTotpPasscode: boolean,
avatarUrl: string,
lastUserInfoRefresh: Date | null,
settings: IUserSettings,
isLoading: boolean,
isLoadingGeneralSettings: boolean
}
export const useAuthStore = defineStore('auth', { export const useAuthStore = defineStore('auth', {
state: () : AuthState => ({ state: () : AuthState => ({
@ -93,7 +104,8 @@ export const useAuthStore = defineStore('auth', {
// Logs a user in with a set of credentials. // Logs a user in with a set of credentials.
async login(credentials) { async login(credentials) {
const HTTP = HTTPFactory() const HTTP = HTTPFactory()
store.commit('loading', true) const baseStore = useBaseStore()
baseStore.setLoading(true)
this.setIsLoading(true) this.setIsLoading(true)
// Delete an eventually preexisting old token // Delete an eventually preexisting old token
@ -117,7 +129,7 @@ export const useAuthStore = defineStore('auth', {
throw e throw e
} finally { } finally {
store.commit('loading', false) baseStore.setLoading(false)
this.setIsLoading(false) this.setIsLoading(false)
} }
}, },
@ -126,7 +138,8 @@ export const useAuthStore = defineStore('auth', {
// Not sure if this is the right place to put the logic in, maybe a seperate js component would be better suited. // Not sure if this is the right place to put the logic in, maybe a seperate js component would be better suited.
async register(credentials) { async register(credentials) {
const HTTP = HTTPFactory() const HTTP = HTTPFactory()
store.commit('loading', true) const baseStore = useBaseStore()
baseStore.setLoading(true)
this.setIsLoading(true) this.setIsLoading(true)
try { try {
await HTTP.post('register', credentials) await HTTP.post('register', credentials)
@ -138,14 +151,15 @@ export const useAuthStore = defineStore('auth', {
throw e throw e
} finally { } finally {
store.commit('loading', false) baseStore.setLoading(false)
this.setIsLoading(false) this.setIsLoading(false)
} }
}, },
async openIdAuth({provider, code}) { async openIdAuth({provider, code}) {
const HTTP = HTTPFactory() const HTTP = HTTPFactory()
store.commit('loading', true) const baseStore = useBaseStore()
baseStore.setLoading(true)
this.setIsLoading(true) this.setIsLoading(true)
const data = { const data = {
@ -162,7 +176,7 @@ export const useAuthStore = defineStore('auth', {
// Tell others the user is autheticated // Tell others the user is autheticated
this.checkAuth() this.checkAuth()
} finally { } finally {
store.commit('loading', false) baseStore.setLoading(false)
this.setIsLoading(false) this.setIsLoading(false)
} }
}, },

View file

@ -1,40 +1,34 @@
import type {InjectionKey} from 'vue' import {defineStore, acceptHMRUpdate} from 'pinia'
import {createStore, useStore as baseUseStore, Store} from 'vuex'
import {getBlobFromBlurHash} from '../helpers/getBlobFromBlurHash' import {getBlobFromBlurHash} from '@/helpers/getBlobFromBlurHash'
import {
BACKGROUND,
BLUR_HASH,
CURRENT_LIST,
HAS_TASKS,
KEYBOARD_SHORTCUTS_ACTIVE,
LOADING,
LOADING_MODULE, LOGO_VISIBLE,
MENU_ACTIVE,
QUICK_ACTIONS_ACTIVE,
} from '../store/mutation-types'
import ListModel from '@/models/list' import ListModel from '@/models/list'
import ListService from '../services/list' import ListService from '../services/list'
import {checkAndSetApiUrl} from '@/helpers/checkAndSetApiUrl' import {checkAndSetApiUrl} from '@/helpers/checkAndSetApiUrl'
import type { RootStoreState, StoreState } from '../store/types'
import pinia from '@/pinia'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
import type {IList} from '@/modelTypes/IList'
export const key: InjectionKey<Store<StoreState>> = Symbol() export interface RootStoreState {
loading: boolean,
loadingModule: null,
// define your own `useStore` composition function currentList: IList,
export function useStore () { background: string,
return baseUseStore(key) blurHash: string,
hasTasks: boolean,
menuActive: boolean,
keyboardShortcutsActive: boolean,
quickActionsActive: boolean,
logoVisible: boolean,
} }
export const store = createStore<RootStoreState>({ export const useBaseStore = defineStore('base', {
strict: import.meta.env.DEV, state: () : RootStoreState => ({
state: () => ({
loading: false, loading: false,
loadingModule: null, loadingModule: null,
// This is used to highlight the current list in menu for all list related views // This is used to highlight the current list in menu for all list related views
currentList: new ListModel({ currentList: new ListModel({
id: 0, id: 0,
@ -42,76 +36,94 @@ export const store = createStore<RootStoreState>({
}), }),
background: '', background: '',
blurHash: '', blurHash: '',
hasTasks: false, hasTasks: false,
menuActive: true, menuActive: true,
keyboardShortcutsActive: false, keyboardShortcutsActive: false,
quickActionsActive: false, quickActionsActive: false,
logoVisible: true, logoVisible: true,
}), }),
mutations: {
[LOADING](state, loading) { actions: {
state.loading = loading setLoading(loading: boolean) {
this.loading = loading
}, },
[LOADING_MODULE](state, module) {
state.loadingModule = module setLoadingModule(module) {
this.loadingModule = module
}, },
[CURRENT_LIST](state, currentList) {
// FIXME: same action as mutation name
setCurrentList(currentList: IList) {
// Server updates don't return the right. Therefore, the right is reset after updating the list which is // Server updates don't return the right. Therefore, the right is reset after updating the list which is
// confusing because all the buttons will disappear in that case. To prevent this, we're keeping the right // confusing because all the buttons will disappear in that case. To prevent this, we're keeping the right
// when updating the list in global state. // when updating the list in global state.
if (typeof state.currentList.maxRight !== 'undefined' && (typeof currentList.maxRight === 'undefined' || currentList.maxRight === null)) { if (
currentList.maxRight = state.currentList.maxRight typeof this.currentList.maxRight !== 'undefined' &&
(
typeof currentList.maxRight === 'undefined' ||
currentList.maxRight === null
)
) {
currentList.maxRight = this.currentList.maxRight
} }
state.currentList = currentList this.currentList = currentList
}, },
[HAS_TASKS](state, hasTasks) {
state.hasTasks = hasTasks
},
[MENU_ACTIVE](state, menuActive) {
state.menuActive = menuActive
},
toggleMenu(state) {
state.menuActive = !state.menuActive
},
[KEYBOARD_SHORTCUTS_ACTIVE](state, active) {
state.keyboardShortcutsActive = active
},
[QUICK_ACTIONS_ACTIVE](state, active) {
state.quickActionsActive = active
},
[BACKGROUND](state, background) {
state.background = background
},
[BLUR_HASH](state, blurHash) {
state.blurHash = blurHash
},
[LOGO_VISIBLE](state, visible: boolean) {
state.logoVisible = visible
},
},
actions: {
async [CURRENT_LIST]({state, commit}, {list, forceUpdate = false}) {
setHasTasks(hasTasks: boolean) {
this.hasTasks = hasTasks
},
setMenuActive(menuActive: boolean) {
this.menuActive = menuActive
},
toggleMenu() {
this.menuActive = !this.menuActive
},
setKeyboardShortcutsActive(active: boolean) {
this.keyboardShortcutsActive = active
},
setQuickActionsActive(active: boolean) {
this.quickActionsActive = active
},
setBackground(background: string) {
this.background = background
},
setBlurHash(blurHash: string) {
this.blurHash = blurHash
},
setLogoVisible(visible: boolean) {
this.logoVisible = visible
},
// FIXME: update all actions handleSetCurrentList
async handleSetCurrentList({list, forceUpdate = false}) {
if (list === null) { if (list === null) {
commit(CURRENT_LIST, {}) this.setCurrentList({})
commit(BACKGROUND, null) this.setBackground('')
commit(BLUR_HASH, null) this.setBlurHash('')
return return
} }
// The forceUpdate parameter is used only when updating a list background directly because in that case // The forceUpdate parameter is used only when updating a list background directly because in that case
// the current list stays the same, but we want to show the new background right away. // the current list stays the same, but we want to show the new background right away.
if (list.id !== state.currentList.id || forceUpdate) { if (list.id !== this.currentList.id || forceUpdate) {
if (list.backgroundInformation) { if (list.backgroundInformation) {
try { try {
const blurHash = await getBlobFromBlurHash(list.backgroundBlurHash) const blurHash = await getBlobFromBlurHash(list.backgroundBlurHash)
if (blurHash) { if (blurHash) {
commit(BLUR_HASH, window.URL.createObjectURL(blurHash)) this.setBlurHash(window.URL.createObjectURL(blurHash))
} }
const listService = new ListService() const listService = new ListService()
const background = await listService.background(list) const background = await listService.background(list)
commit(BACKGROUND, background) this.setBackground(background)
} catch (e) { } catch (e) {
console.error('Error getting background image for list', list.id, e) console.error('Error getting background image for list', list.id, e)
} }
@ -119,16 +131,21 @@ export const store = createStore<RootStoreState>({
} }
if (typeof list.backgroundInformation === 'undefined' || list.backgroundInformation === null) { if (typeof list.backgroundInformation === 'undefined' || list.backgroundInformation === null) {
commit(BACKGROUND, null) this.setBackground('')
commit(BLUR_HASH, null) this.setBlurHash('')
} }
commit(CURRENT_LIST, list) this.setCurrentList(list)
}, },
async loadApp() { async loadApp() {
await checkAndSetApiUrl(window.API_URL) await checkAndSetApiUrl(window.API_URL)
const authStore = useAuthStore(pinia) await useAuthStore().checkAuth()
await authStore.checkAuth()
}, },
}, },
}) })
// support hot reloading
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useBaseStore, import.meta.hot))
}

View file

@ -1,10 +1,38 @@
import {defineStore, acceptHMRUpdate} from 'pinia' import {defineStore, acceptHMRUpdate} from 'pinia'
import {parseURL} from 'ufo' import {parseURL} from 'ufo'
import {CONFIG} from '../store/mutation-types'
import {HTTPFactory} from '@/http-common' import {HTTPFactory} from '@/http-common'
import {objectToCamelCase} from '@/helpers/case' import {objectToCamelCase} from '@/helpers/case'
import type {ConfigState} from '@/store/types'
export interface ConfigState {
version: string,
frontendUrl: string,
motd: string,
linkSharingEnabled: boolean,
maxFileSize: '20MB',
registrationEnabled: boolean,
availableMigrators: [],
taskAttachmentsEnabled: boolean,
totpEnabled: boolean,
enabledBackgroundProviders: [],
legal: {
imprintUrl: string,
privacyPolicyUrl: string,
},
caldavEnabled: boolean,
userDeletionEnabled: boolean,
taskCommentsEnabled: boolean,
auth: {
local: {
enabled: boolean,
},
openidConnect: {
enabled: boolean,
redirectUrl: string,
providers: [],
},
},
}
export const useConfigStore = defineStore('config', { export const useConfigStore = defineStore('config', {
state: (): ConfigState => ({ state: (): ConfigState => ({
@ -45,13 +73,13 @@ export const useConfigStore = defineStore('config', {
}, },
}, },
actions: { actions: {
[CONFIG](config: ConfigState) { setConfig(config: ConfigState) {
Object.assign(this, config) Object.assign(this, config)
}, },
async update() { async update() {
const HTTP = HTTPFactory() const HTTP = HTTPFactory()
const {data: config} = await HTTP.get('info') const {data: config} = await HTTP.get('info')
this[CONFIG](objectToCamelCase(config)) this.setConfig(objectToCamelCase(config))
return config return config
}, },
}, },

19
src/stores/helper.ts Normal file
View file

@ -0,0 +1,19 @@
import type { StoreDefinition } from 'pinia'
export const setLoadingPinia = (store: StoreDefinition, loadFunc : ((isLoading: boolean) => void) | null = null) => {
const timeout = setTimeout(() => {
if (loadFunc === null) {
store.isLoading = true
} else {
loadFunc(true)
}
}, 100)
return () => {
clearTimeout(timeout)
if (loadFunc === null) {
store.isLoading = false
} else {
loadFunc(false)
}
}
}

View file

@ -5,10 +5,11 @@ import {findById, findIndexById} from '@/helpers/utils'
import {i18n} from '@/i18n' import {i18n} from '@/i18n'
import {success} from '@/message' import {success} from '@/message'
import BucketService from '../services/bucket' import BucketService from '@/services/bucket'
import {setLoadingPinia} from '@/store/helper'
import TaskCollectionService from '@/services/taskCollection' import TaskCollectionService from '@/services/taskCollection'
import type { KanbanState } from '@/store/types'
import {setLoadingPinia} from '@/stores/helper'
import type { ITask } from '@/modelTypes/ITask' import type { ITask } from '@/modelTypes/ITask'
import type { IList } from '@/modelTypes/IList' import type { IList } from '@/modelTypes/IList'
import type { IBucket } from '@/modelTypes/IBucket' import type { IBucket } from '@/modelTypes/IBucket'
@ -37,6 +38,21 @@ const addTaskToBucketAndSort = (state: KanbanState, task: ITask) => {
state.buckets[bucketIndex].tasks.sort((a, b) => a.kanbanPosition > b.kanbanPosition ? 1 : -1) state.buckets[bucketIndex].tasks.sort((a, b) => a.kanbanPosition > b.kanbanPosition ? 1 : -1)
} }
export interface KanbanState {
buckets: IBucket[],
listId: IList['id'],
bucketLoading: {
[id: IBucket['id']]: boolean
},
taskPagesPerBucket: {
[id: IBucket['id']]: number
},
allTasksLoadedForBucket: {
[id: IBucket['id']]: boolean
},
isLoading: boolean,
}
/** /**
* This store is intended to hold the currently active kanban view. * This store is intended to hold the currently active kanban view.
* It should hold only the current buckets. * It should hold only the current buckets.

View file

@ -4,7 +4,7 @@ import LabelService from '@/services/label'
import {success} from '@/message' import {success} from '@/message'
import {i18n} from '@/i18n' import {i18n} from '@/i18n'
import {createNewIndexer} from '@/indexes' import {createNewIndexer} from '@/indexes'
import {setLoadingPinia} from '@/store/helper' import {setLoadingPinia} from '@/stores/helper'
import type {ILabel} from '@/modelTypes/ILabel' import type {ILabel} from '@/modelTypes/ILabel'
const {add, remove, update, search} = createNewIndexer('labels', ['title', 'description']) const {add, remove, update, search} = createNewIndexer('labels', ['title', 'description'])
@ -20,7 +20,12 @@ async function getAllLabels(page = 1): Promise<ILabel[]> {
} }
} }
import type {LabelState} from '@/store/types' export interface LabelState {
labels: {
[id: ILabel['id']]: ILabel
},
isLoading: boolean,
}
export const useLabelStore = defineStore('label', { export const useLabelStore = defineStore('label', {
state: () : LabelState => ({ state: () : LabelState => ({

View file

@ -3,12 +3,11 @@ import {acceptHMRUpdate, defineStore} from 'pinia'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import ListService from '@/services/list' import ListService from '@/services/list'
import {setLoadingPinia} from '@/store/helper' import {setLoadingPinia} from '@/stores/helper'
import {removeListFromHistory} from '@/modules/listHistory' import {removeListFromHistory} from '@/modules/listHistory'
import {createNewIndexer} from '@/indexes' import {createNewIndexer} from '@/indexes'
import {useNamespaceStore} from './namespaces' import {useNamespaceStore} from './namespaces'
import type {ListState} from '@/store/types'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import type {MaybeRef} from '@vueuse/core' import type {MaybeRef} from '@vueuse/core'
@ -20,6 +19,11 @@ const {add, remove, search, update} = createNewIndexer('lists', ['title', 'descr
const FavoriteListsNamespace = -2 const FavoriteListsNamespace = -2
export interface ListState {
lists: { [id: IList['id']]: IList },
isLoading: boolean,
}
export const useListStore = defineStore('list', { export const useListStore = defineStore('list', {
state: () : ListState => ({ state: () : ListState => ({
isLoading: false, isLoading: false,
@ -113,7 +117,7 @@ export const useListStore = defineStore('list', {
namespaceStore.setListInNamespaceById(list) namespaceStore.setListInNamespaceById(list)
// the returned list from listService.update is the same! // the returned list from listService.update is the same!
// in order to not validate vuex mutations we have to create a new copy // in order to not create a manipulation in pinia store we have to create a new copy
const newList = { const newList = {
...list, ...list,
namespaceId: FavoriteListsNamespace, namespaceId: FavoriteListsNamespace,

View file

@ -1,15 +1,19 @@
import {defineStore, acceptHMRUpdate} from 'pinia' import {defineStore, acceptHMRUpdate} from 'pinia'
import NamespaceService from '../services/namespace' import NamespaceService from '../services/namespace'
import {setLoadingPinia} from '@/store/helper' import {setLoadingPinia} from '@/stores/helper'
import {createNewIndexer} from '@/indexes' import {createNewIndexer} from '@/indexes'
import type {NamespaceState} from '@/store/types'
import type {INamespace} from '@/modelTypes/INamespace' import type {INamespace} from '@/modelTypes/INamespace'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description']) const {add, remove, search, update} = createNewIndexer('namespaces', ['title', 'description'])
export interface NamespaceState {
namespaces: INamespace[]
isLoading: boolean,
}
export const useNamespaceStore = defineStore('namespace', { export const useNamespaceStore = defineStore('namespace', {
state: (): NamespaceState => ({ state: (): NamespaceState => ({
isLoading: false, isLoading: false,

View file

@ -7,8 +7,7 @@ import TaskAssigneeService from '@/services/taskAssignee'
import LabelTaskService from '@/services/labelTask' import LabelTaskService from '@/services/labelTask'
import UserService from '@/services/user' import UserService from '@/services/user'
import {HAS_TASKS} from '../store/mutation-types' import {playPop} from '@/helpers/playPop'
import {setLoadingPinia} from '../store/helper'
import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode' import {getQuickAddMagicMode} from '@/helpers/quickAddMagicMode'
import {parseTaskText} from '@/modules/parseTaskText' import {parseTaskText} from '@/modules/parseTaskText'
@ -24,13 +23,12 @@ import type {IUser} from '@/modelTypes/IUser'
import type {IAttachment} from '@/modelTypes/IAttachment' import type {IAttachment} from '@/modelTypes/IAttachment'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import type {TaskState} from '@/store/types' import {setLoadingPinia} from '@/stores/helper'
import {useBaseStore} from '@/stores/base'
import {useLabelStore} from '@/stores/labels' import {useLabelStore} from '@/stores/labels'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useAttachmentStore} from '@/stores/attachments' import {useAttachmentStore} from '@/stores/attachments'
import {useKanbanStore} from '@/stores/kanban' import {useKanbanStore} from '@/stores/kanban'
import {playPop} from '@/helpers/playPop'
import {store} from '@/store'
// IDEA: maybe use a small fuzzy search here to prevent errors // IDEA: maybe use a small fuzzy search here to prevent errors
function findPropertyByValue(object, key, value) { function findPropertyByValue(object, key, value) {
@ -40,10 +38,13 @@ function findPropertyByValue(object, key, value) {
} }
// Check if the user exists in the search results // Check if the user exists in the search results
function validateUser(users: IUser[], username: IUser['username']) { function validateUser(
return findPropertyByValue(users, 'username', username) || users: IUser[],
findPropertyByValue(users, 'name', username) || query: IUser['username'] | IUser['name'] | IUser['email'],
findPropertyByValue(users, 'email', username) ) {
return findPropertyByValue(users, 'username', query) ||
findPropertyByValue(users, 'name', query) ||
findPropertyByValue(users, 'email', query)
} }
// Check if the label exists // Check if the label exists
@ -77,6 +78,9 @@ async function findAssignees(parsedTaskAssignees: string[]) {
return validatedUsers.filter((item) => Boolean(item)) return validatedUsers.filter((item) => Boolean(item))
} }
export interface TaskState {
isLoading: boolean,
}
export const useTaskStore = defineStore('task', { export const useTaskStore = defineStore('task', {
state: () : TaskState => ({ state: () : TaskState => ({
@ -89,7 +93,7 @@ export const useTaskStore = defineStore('task', {
const cancel = setLoadingPinia(this) const cancel = setLoadingPinia(this)
try { try {
const tasks = await taskService.getAll({}, params) const tasks = await taskService.getAll({}, params)
store.commit(HAS_TASKS, tasks.length > 0) useBaseStore().setHasTasks(tasks.length > 0)
return tasks return tasks
} finally { } finally {
cancel() cancel()

View file

@ -1,30 +0,0 @@
// https://next.vuex.vuejs.org/guide/migrating-to-4-0-from-3-x.html#typescript-support
import { Store } from 'vuex'
import type {
RootStoreState,
AttachmentState,
AuthState,
ConfigState,
KanbanState,
LabelState,
ListState,
NamespaceState,
TaskState,
} from '@/store/types'
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$store: Store<RootStoreState & {
config: ConfigState,
auth: AuthState,
namespaces: NamespaceState,
kanban: KanbanState,
tasks: TaskState,
lists: ListState,
attachments: AttachmentState,
labels: LabelState,
}>
}
}

View file

@ -60,7 +60,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import {ref, computed} from 'vue' import {ref, computed} from 'vue'
import {useStore} from '@/store'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import ShowTasks from '@/views/tasks/ShowTasks.vue' import ShowTasks from '@/views/tasks/ShowTasks.vue'
@ -71,18 +70,23 @@ import {getHistory} from '@/modules/listHistory'
import {parseDateOrNull} from '@/helpers/parseDateOrNull' import {parseDateOrNull} from '@/helpers/parseDateOrNull'
import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate' import {formatDateShort, formatDateSince} from '@/helpers/time/formatDate'
import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation' import {useDateTimeSalutation} from '@/composables/useDateTimeSalutation'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
import {useTaskStore} from '@/stores/tasks'
const welcome = useDateTimeSalutation() const welcome = useDateTimeSalutation()
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const configStore = useConfigStore() const configStore = useConfigStore()
const namespaceStore = useNamespaceStore() const namespaceStore = useNamespaceStore()
const listStore = useListStore() const listStore = useListStore()
const taskStore = useTaskStore()
const listHistory = computed(() => { const listHistory = computed(() => {
// If we don't check this, it tries to load the list background right after logging out // If we don't check this, it tries to load the list background right after logging out
if(!authStore.authenticated) { if(!authStore.authenticated) {
@ -96,15 +100,15 @@ const listHistory = computed(() => {
const migratorsEnabled = computed(() => configStore.availableMigrators?.length > 0) const migratorsEnabled = computed(() => configStore.availableMigrators?.length > 0)
const userInfo = computed(() => authStore.info) const userInfo = computed(() => authStore.info)
const hasTasks = computed(() => store.state.hasTasks) const hasTasks = computed(() => baseStore.hasTasks)
const defaultListId = computed(() => authStore.settings.defaultListId) const defaultListId = computed(() => authStore.settings.defaultListId)
const defaultNamespaceId = computed(() => namespaceStore.namespaces?.[0]?.id || 0) const defaultNamespaceId = computed(() => namespaceStore.namespaces?.[0]?.id || 0)
const hasLists = computed(() => namespaceStore.namespaces?.[0]?.lists.length > 0) const hasLists = computed(() => namespaceStore.namespaces?.[0]?.lists.length > 0)
const loading = computed(() => store.state.loading && store.state.loadingModule === 'tasks') const loading = computed(() => taskStore.isLoading)
const deletionScheduledAt = computed(() => parseDateOrNull(authStore.info?.deletionScheduledAt)) const deletionScheduledAt = computed(() => parseDateOrNull(authStore.info?.deletionScheduledAt))
// This is to reload the tasks list after adding a new task through the global task add. // This is to reload the tasks list after adding a new task through the global task add.
// FIXME: Should use vuex (somehow?) // FIXME: Should use pinia (somehow?)
const showTasksKey = ref(0) const showTasksKey = ref(0)
function updateTaskList() { function updateTaskList() {

View file

@ -54,11 +54,9 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, shallowRef, computed, watch, unref } from 'vue' import {ref, shallowRef, computed, watch, unref } from 'vue'
import {useRouter, useRoute} from 'vue-router' import {useRouter, useRoute} from 'vue-router'
import {useStore} from '@/store'
import {success} from '@/message' import {success} from '@/message'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import type {MaybeRef} from '@vueuse/core' import type {MaybeRef} from '@vueuse/core'
import {CURRENT_LIST} from '@/store/mutation-types'
import {default as Editor} from '@/components/input/AsyncEditor' import {default as Editor} from '@/components/input/AsyncEditor'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
@ -70,9 +68,12 @@ import SavedFilterService from '@/services/savedFilter'
import {objectToSnakeCase} from '@/helpers/case' import {objectToSnakeCase} from '@/helpers/case'
import {getSavedFilterIdFromListId} from '@/helpers/savedFilter' import {getSavedFilterIdFromListId} from '@/helpers/savedFilter'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {useBaseStore} from '@/stores/base'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const baseStore = useBaseStore()
const namespaceStore = useNamespaceStore() const namespaceStore = useNamespaceStore()
function useSavedFilter(listId: MaybeRef<IList['id']>) { function useSavedFilter(listId: MaybeRef<IList['id']>) {
@ -115,7 +116,6 @@ function useSavedFilter(listId: MaybeRef<IList['id']>) {
} }
const route = useRoute() const route = useRoute()
const store = useStore()
const listId = computed(() => Number(route.params.listId as string)) const listId = computed(() => Number(route.params.listId as string))
const { const {
@ -129,7 +129,7 @@ const router = useRouter()
async function saveSavedFilter() { async function saveSavedFilter() {
await save() await save()
await store.dispatch(CURRENT_LIST, {list: filter}) await baseStore.setCurrentList({list: filter})
router.back() router.back()
} }
</script> </script>

View file

@ -227,10 +227,9 @@
import {defineComponent} from 'vue' import {defineComponent} from 'vue'
import draggable from 'zhyswan-vuedraggable' import draggable from 'zhyswan-vuedraggable'
import cloneDeep from 'lodash.clonedeep' import cloneDeep from 'lodash.clonedeep'
import {mapState} from 'pinia'
import BucketModel from '../../models/bucket' import BucketModel from '../../models/bucket'
import {mapState as mapStateVuex} from 'vuex'
import {mapState} from 'pinia'
import {RIGHTS as Rights} from '@/constants/rights' import {RIGHTS as Rights} from '@/constants/rights'
import ListWrapper from './ListWrapper.vue' import ListWrapper from './ListWrapper.vue'
import FilterPopup from '@/components/list/partials/filter-popup.vue' import FilterPopup from '@/components/list/partials/filter-popup.vue'
@ -240,6 +239,8 @@ import {calculateItemPosition} from '../../helpers/calculateItemPosition'
import KanbanCard from '@/components/tasks/partials/kanban-card.vue' import KanbanCard from '@/components/tasks/partials/kanban-card.vue'
import DropdownItem from '@/components/misc/dropdown-item.vue' import DropdownItem from '@/components/misc/dropdown-item.vue'
import {isSavedFilter} from '@/helpers/savedFilter' import {isSavedFilter} from '@/helpers/savedFilter'
import {useBaseStore} from '@/stores/base'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
import {useKanbanStore} from '@/stores/kanban' import {useKanbanStore} from '@/stores/kanban'
@ -343,7 +344,7 @@ export default defineComponent({
], ],
} }
}, },
...mapStateVuex({ ...mapState(useBaseStore, {
canWrite: state => state.currentList.maxRight > Rights.READ, canWrite: state => state.currentList.maxRight > Rights.READ,
list: state => state.currentList, list: state => state.currentList,
}), }),
@ -430,7 +431,7 @@ export default defineComponent({
const taskAfter = newBucket.tasks[newTaskIndex + 1] ?? null const taskAfter = newBucket.tasks[newTaskIndex + 1] ?? null
this.taskUpdating[task.id] = true this.taskUpdating[task.id] = true
const newTask = cloneDeep(task) // cloning the task to avoid vuex store mutations const newTask = cloneDeep(task) // cloning the task to avoid pinia store manipulation
newTask.bucketId = newBucket.id newTask.bucketId = newBucket.id
newTask.kanbanPosition = calculateItemPosition( newTask.kanbanPosition = calculateItemPosition(
taskBefore !== null ? taskBefore.kanbanPosition : null, taskBefore !== null ? taskBefore.kanbanPosition : null,
@ -444,7 +445,7 @@ export default defineComponent({
// Make sure the first and second task don't both get position 0 assigned // Make sure the first and second task don't both get position 0 assigned
if(newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) { if(newTaskIndex === 0 && taskAfter !== null && taskAfter.kanbanPosition === 0) {
const taskAfterAfter = newBucket.tasks[newTaskIndex + 2] ?? null const taskAfterAfter = newBucket.tasks[newTaskIndex + 2] ?? null
const newTaskAfter = cloneDeep(taskAfter) // cloning the task to avoid vuex store mutations const newTaskAfter = cloneDeep(taskAfter) // cloning the task to avoid pinia store manipulation
newTaskAfter.bucketId = newBucket.id newTaskAfter.bucketId = newBucket.id
newTaskAfter.kanbanPosition = calculateItemPosition( newTaskAfter.kanbanPosition = calculateItemPosition(
0, 0,

View file

@ -154,13 +154,13 @@ import Nothing from '@/components/misc/nothing.vue'
import Pagination from '@/components/misc/pagination.vue' import Pagination from '@/components/misc/pagination.vue'
import {ALPHABETICAL_SORT} from '@/components/list/partials/filters.vue' import {ALPHABETICAL_SORT} from '@/components/list/partials/filters.vue'
import {useStore} from '@/store'
import {HAS_TASKS} from '@/store/mutation-types'
import {useTaskList} from '@/composables/taskList' import {useTaskList} from '@/composables/taskList'
import {RIGHTS as Rights} from '@/constants/rights' import {RIGHTS as Rights} from '@/constants/rights'
import {calculateItemPosition} from '@/helpers/calculateItemPosition' import {calculateItemPosition} from '@/helpers/calculateItemPosition'
import type {ITask} from '@/modelTypes/ITask' import type {ITask} from '@/modelTypes/ITask'
import {isSavedFilter} from '@/helpers/savedFilter' import {isSavedFilter} from '@/helpers/savedFilter'
import {useBaseStore} from '@/stores/base'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
@ -238,8 +238,8 @@ const firstNewPosition = computed(() => {
}) })
const taskStore = useTaskStore() const taskStore = useTaskStore()
const store = useStore() const baseStore = useBaseStore()
const list = computed(() => store.state.currentList) const list = computed(() => baseStore.currentList)
const canWrite = computed(() => { const canWrite = computed(() => {
return list.value.maxRight > Rights.READ && list.value.id > 0 return list.value.maxRight > Rights.READ && list.value.id > 0
@ -293,7 +293,7 @@ function updateTaskList(task: ITask) {
] ]
} }
store.commit(HAS_TASKS, true) baseStore.setHasTasks(true)
} }
function editTask(id: ITask['id']) { function editTask(id: ITask['id']) {

View file

@ -55,12 +55,11 @@ import Message from '@/components/misc/message.vue'
import ListModel from '@/models/list' import ListModel from '@/models/list'
import ListService from '@/services/list' import ListService from '@/services/list'
import {BACKGROUND, BLUR_HASH, CURRENT_LIST} from '@/store/mutation-types'
import {getListTitle} from '@/helpers/getListTitle' import {getListTitle} from '@/helpers/getListTitle'
import {saveListToHistory} from '@/modules/listHistory' import {saveListToHistory} from '@/modules/listHistory'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useStore} from '@/store'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useKanbanStore} from '@/stores/kanban' import {useKanbanStore} from '@/stores/kanban'
@ -76,20 +75,20 @@ const props = defineProps({
}) })
const route = useRoute() const route = useRoute()
const store = useStore()
const baseStore = useBaseStore()
const kanbanStore = useKanbanStore() const kanbanStore = useKanbanStore()
const listStore = useListStore() const listStore = useListStore()
const listService = ref(new ListService()) const listService = ref(new ListService())
const loadedListId = ref(0) const loadedListId = ref(0)
const currentList = computed(() => { const currentList = computed(() => {
return typeof store.state.currentList === 'undefined' ? { return typeof baseStore.currentList === 'undefined' ? {
id: 0, id: 0,
title: '', title: '',
isArchived: false, isArchived: false,
maxRight: null, maxRight: null,
} : store.state.currentList } : baseStore.currentList
}) })
// watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before. // watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before.
@ -141,16 +140,16 @@ async function loadList(listIdToLoad: number) {
loadedListId.value = 0 loadedListId.value = 0
const listFromStore = listStore.getListById(listData.id) const listFromStore = listStore.getListById(listData.id)
if (listFromStore !== null) { if (listFromStore !== null) {
store.commit(BACKGROUND, null) baseStore.setBackground(null)
store.commit(BLUR_HASH, null) baseStore.setBlurHash(null)
store.dispatch(CURRENT_LIST, {list: listFromStore}) baseStore.handleSetCurrentList({list: listFromStore})
} }
// We create an extra list object instead of creating it in list.value because that would trigger a ui update which would result in bad ux. // We create an extra list object instead of creating it in list.value because that would trigger a ui update which would result in bad ux.
const list = new ListModel(listData) const list = new ListModel(listData)
try { try {
const loadedList = await listService.value.get(list) const loadedList = await listService.value.get(list)
await store.dispatch(CURRENT_LIST, {list: loadedList}) await baseStore.handleSetCurrentList({list: loadedList})
} finally { } finally {
loadedListId.value = props.listId loadedListId.value = props.listId
} }

View file

@ -17,16 +17,16 @@ export default {name: 'list-setting-archive'}
<script setup lang="ts"> <script setup lang="ts">
import {computed} from 'vue' import {computed} from 'vue'
import {useStore} from '@/store'
import {useRouter, useRoute} from 'vue-router' import {useRouter, useRoute} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import { success } from '@/message' import {success} from '@/message'
import { useTitle } from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import { useListStore } from '@/stores/lists'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const store = useStore()
const listStore = useListStore() const listStore = useListStore()
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
@ -40,7 +40,7 @@ async function archiveList() {
...list.value, ...list.value,
isArchived: !list.value.isArchived, isArchived: !list.value.isArchived,
}) })
store.commit('currentList', newList) useBaseStore().setCurrentList(newList)
success({message: t('list.archive.success')}) success({message: t('list.archive.success')})
} finally { } finally {
router.back() router.back()

View file

@ -100,10 +100,11 @@ export default { name: 'list-setting-background' }
<script setup lang="ts"> <script setup lang="ts">
import {ref, computed, shallowReactive} from 'vue' import {ref, computed, shallowReactive} from 'vue'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useStore} from '@/store'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
import {useBaseStore} from '@/stores/base'
import {useListStore} from '@/stores/lists' import {useListStore} from '@/stores/lists'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
@ -115,7 +116,6 @@ import type BackgroundImageModel from '@/models/backgroundImage'
import {getBlobFromBlurHash} from '@/helpers/getBlobFromBlurHash' import {getBlobFromBlurHash} from '@/helpers/getBlobFromBlurHash'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {CURRENT_LIST} from '@/store/mutation-types'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
import {success} from '@/message' import {success} from '@/message'
@ -123,7 +123,7 @@ import {success} from '@/message'
const SEARCH_DEBOUNCE = 300 const SEARCH_DEBOUNCE = 300
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
const store = useStore() const baseStore = useBaseStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -149,8 +149,8 @@ const configStore = useConfigStore()
const unsplashBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('unsplash')) const unsplashBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('unsplash'))
const uploadBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('upload')) const uploadBackgroundEnabled = computed(() => configStore.enabledBackgroundProviders.includes('upload'))
const currentList = computed(() => store.state.currentList) const currentList = computed(() => baseStore.currentList)
const hasBackground = computed(() => store.state.background !== null) const hasBackground = computed(() => baseStore.background !== null)
// Show the default collection of backgrounds // Show the default collection of backgrounds
newBackgroundSearch() newBackgroundSearch()
@ -188,8 +188,11 @@ async function setBackground(backgroundId: string) {
return return
} }
const list = await backgroundService.update({id: backgroundId, listId: route.params.listId}) const list = await backgroundService.update({
await store.dispatch(CURRENT_LIST, {list, forceUpdate: true}) id: backgroundId,
listId: route.params.listId,
})
await baseStore.handleSetCurrentList({list, forceUpdate: true})
namespaceStore.setListInNamespaceById(list) namespaceStore.setListInNamespaceById(list)
listStore.setList(list) listStore.setList(list)
success({message: t('list.background.success')}) success({message: t('list.background.success')})
@ -201,8 +204,11 @@ async function uploadBackground() {
return return
} }
const list = await backgroundUploadService.value.create(route.params.listId, backgroundUploadInput.value?.files[0]) const list = await backgroundUploadService.value.create(
await store.dispatch(CURRENT_LIST, {list, forceUpdate: true}) route.params.listId,
backgroundUploadInput.value?.files[0],
)
await baseStore.handleSetCurrentList({list, forceUpdate: true})
namespaceStore.setListInNamespaceById(list) namespaceStore.setListInNamespaceById(list)
listStore.setList(list) listStore.setList(list)
success({message: t('list.background.success')}) success({message: t('list.background.success')})
@ -210,7 +216,7 @@ async function uploadBackground() {
async function removeBackground() { async function removeBackground() {
const list = await listService.value.removeBackground(currentList.value) const list = await listService.value.removeBackground(currentList.value)
await store.dispatch(CURRENT_LIST, {list, forceUpdate: true}) await baseStore.handleSetCurrentList({list, forceUpdate: true})
namespaceStore.setListInNamespaceById(list) namespaceStore.setListInNamespaceById(list)
listStore.setList(list) listStore.setList(list)
success({message: t('list.background.removeSuccess')}) success({message: t('list.background.removeSuccess')})

View file

@ -72,17 +72,17 @@ export default { name: 'list-setting-edit' }
<script setup lang="ts"> <script setup lang="ts">
import type {PropType} from 'vue' import type {PropType} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useStore} from '@/store'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import Editor from '@/components/input/AsyncEditor' import Editor from '@/components/input/AsyncEditor'
import ColorPicker from '@/components/input/colorPicker.vue' import ColorPicker from '@/components/input/colorPicker.vue'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
import {CURRENT_LIST} from '@/store/mutation-types'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {useBaseStore} from '@/stores/base'
import {useList} from '@/stores/lists' import {useList} from '@/stores/lists'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
const props = defineProps({ const props = defineProps({
@ -93,7 +93,6 @@ const props = defineProps({
}) })
const router = useRouter() const router = useRouter()
const store = useStore()
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
@ -103,7 +102,7 @@ useTitle(() => list?.title ? t('list.edit.title', {list: list.title}) : '')
async function save() { async function save() {
await saveList() await saveList()
await store.dispatch(CURRENT_LIST, {list}) await useBaseStore().handleSetCurrentList({list})
router.back() router.back()
} }
</script> </script>

View file

@ -28,18 +28,18 @@ export default {name: 'list-setting-share'}
<script lang="ts" setup> <script lang="ts" setup>
import {ref, computed, watchEffect} from 'vue' import {ref, computed, watchEffect} from 'vue'
import {useStore} from '@/store'
import {useRoute} from 'vue-router' import {useRoute} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useTitle} from '@vueuse/core' import {useTitle} from '@vueuse/core'
import ListService from '@/services/list' import ListService from '@/services/list'
import ListModel from '@/models/list' import ListModel from '@/models/list'
import {CURRENT_LIST} from '@/store/mutation-types'
import CreateEdit from '@/components/misc/create-edit.vue' import CreateEdit from '@/components/misc/create-edit.vue'
import LinkSharing from '@/components/sharing/linkSharing.vue' import LinkSharing from '@/components/sharing/linkSharing.vue'
import userTeam from '@/components/sharing/userTeam.vue' import userTeam from '@/components/sharing/userTeam.vue'
import {useBaseStore} from '@/stores/base'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
@ -52,7 +52,6 @@ const title = computed(() => list.value?.title
) )
useTitle(title) useTitle(title)
const store = useStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const configStore = useConfigStore() const configStore = useConfigStore()
@ -62,7 +61,7 @@ const userIsAdmin = computed(() => 'owner' in list.value && list.value.owner.id
async function loadList(listId: number) { async function loadList(listId: number) {
const listService = new ListService() const listService = new ListService()
const newList = await listService.get(new ListModel({id: listId})) const newList = await listService.get(new ListModel({id: listId}))
await store.dispatch(CURRENT_LIST, {list: newList}) await useBaseStore().handleSetCurrentList({list: newList})
list.value = newList list.value = newList
} }

View file

@ -71,7 +71,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed} from 'vue' import {computed} from 'vue'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useStore} from '@/store'
import Fancycheckbox from '@/components/input/fancycheckbox.vue' import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import ListCard from '@/components/list/partials/list-card.vue' import ListCard from '@/components/list/partials/list-card.vue'
@ -79,16 +78,18 @@ import ListCard from '@/components/list/partials/list-card.vue'
import {getNamespaceTitle} from '@/helpers/getNamespaceTitle' import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {useStorage} from '@vueuse/core' import {useStorage} from '@vueuse/core'
import {useBaseStore} from '@/stores/base'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
const {t} = useI18n() const {t} = useI18n()
const store = useStore() const baseStore = useBaseStore()
const namespaceStore = useNamespaceStore() const namespaceStore = useNamespaceStore()
useTitle(() => t('namespace.title')) useTitle(() => t('namespace.title'))
const showArchived = useStorage('showArchived', false) const showArchived = useStorage('showArchived', false)
const loading = computed(() => store.state.loading) const loading = computed(() => baseStore.loading) // FIXME: shouldn't this reference the namespace store?
const namespaces = computed(() => { const namespaces = computed(() => {
return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived) return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived)
// return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived).map(n => { // return namespaceStore.namespaces.filter(n => showArchived.value ? true : !n.isArchived).map(n => {

View file

@ -34,21 +34,21 @@
<script lang="ts" setup> <script lang="ts" setup>
import {ref, computed} from 'vue' import {ref, computed} from 'vue'
import {useStore} from '@/store'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useTitle} from '@vueuse/core' import {useTitle} from '@vueuse/core'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {LOGO_VISIBLE} from '@/store/mutation-types'
import {LIST_VIEWS, type ListView} from '@/types/ListView' import {LIST_VIEWS, type ListView} from '@/types/ListView'
import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
useTitle(t('sharing.authenticating')) useTitle(t('sharing.authenticating'))
function useAuth() { function useAuth() {
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -81,7 +81,7 @@ function useAuth() {
const logoVisible = route.query.logoVisible const logoVisible = route.query.logoVisible
? route.query.logoVisible === 'true' ? route.query.logoVisible === 'true'
: true : true
store.commit(LOGO_VISIBLE, logoVisible) baseStore.setLogoVisible(logoVisible)
const view = route.query.view && Object.values(LIST_VIEWS).includes(route.query.view as ListView) const view = route.query.view && Object.values(LIST_VIEWS).includes(route.query.view as ListView)
? route.query.view ? route.query.view

View file

@ -45,7 +45,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed, ref, watchEffect} from 'vue' import {computed, ref, watchEffect} from 'vue'
import {useStore} from '@/store'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
@ -56,13 +55,11 @@ import Fancycheckbox from '@/components/input/fancycheckbox.vue'
import SingleTaskInList from '@/components/tasks/partials/singleTaskInList.vue' import SingleTaskInList from '@/components/tasks/partials/singleTaskInList.vue'
import DatepickerWithRange from '@/components/date/datepickerWithRange.vue' import DatepickerWithRange from '@/components/date/datepickerWithRange.vue'
import {DATE_RANGES} from '@/components/date/dateRanges' import {DATE_RANGES} from '@/components/date/dateRanges'
import {LOADING, LOADING_MODULE} from '@/store/mutation-types'
import LlamaCool from '@/assets/llama-cool.svg?component' import LlamaCool from '@/assets/llama-cool.svg?component'
import type {ITask} from '@/modelTypes/ITask' import type {ITask} from '@/modelTypes/ITask'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
const store = useStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const taskStore = useTaskStore() const taskStore = useTaskStore()
const route = useRoute() const route = useRoute()
@ -109,7 +106,7 @@ const pageTitle = computed(() => {
}) })
const hasTasks = computed(() => tasks.value && tasks.value.length > 0) const hasTasks = computed(() => tasks.value && tasks.value.length > 0)
const userAuthenticated = computed(() => authStore.authenticated) const userAuthenticated = computed(() => authStore.authenticated)
const loading = computed(() => store.state[LOADING] && store.state[LOADING_MODULE] === 'tasks') const loading = computed(() => taskStore.isLoading)
interface dateStrings { interface dateStrings {
dateFrom: string, dateFrom: string,

View file

@ -452,7 +452,6 @@ import heading from '@/components/tasks/partials/heading.vue'
import Datepicker from '@/components/input/datepicker.vue' import Datepicker from '@/components/input/datepicker.vue'
import BaseButton from '@/components/base/BaseButton.vue' import BaseButton from '@/components/base/BaseButton.vue'
import TaskSubscription from '@/components/misc/subscription.vue' import TaskSubscription from '@/components/misc/subscription.vue'
import {CURRENT_LIST} from '@/store/mutation-types'
import {uploadFile} from '@/helpers/attachments' import {uploadFile} from '@/helpers/attachments'
import ChecklistSummary from '../../components/tasks/partials/checklist-summary.vue' import ChecklistSummary from '../../components/tasks/partials/checklist-summary.vue'
@ -462,6 +461,7 @@ import {getNamespaceTitle} from '@/helpers/getNamespaceTitle'
import {getListTitle} from '@/helpers/getListTitle' import {getListTitle} from '@/helpers/getListTitle'
import type {IList} from '@/modelTypes/IList' import type {IList} from '@/modelTypes/IList'
import {colorIsDark} from '@/helpers/color/colorIsDark' import {colorIsDark} from '@/helpers/color/colorIsDark'
import {useBaseStore} from '@/stores/base'
import {useNamespaceStore} from '@/stores/namespaces' import {useNamespaceStore} from '@/stores/namespaces'
import {useAttachmentStore} from '@/stores/attachments' import {useAttachmentStore} from '@/stores/attachments'
import {useTaskStore} from '@/stores/tasks' import {useTaskStore} from '@/stores/tasks'
@ -561,7 +561,7 @@ export default defineComponent({
handler(parent) { handler(parent) {
const parentList = parent !== null ? parent.list : null const parentList = parent !== null ? parent.list : null
if (parentList !== null) { if (parentList !== null) {
this.$store.dispatch(CURRENT_LIST, {list: parentList}) useBaseStore().handleSetCurrentList({list: parentList})
} }
}, },
immediate: true, immediate: true,
@ -576,7 +576,7 @@ export default defineComponent({
}, },
computed: { computed: {
currentList() { currentList() {
return this.$store.state[CURRENT_LIST] return useBaseStore().currentList
}, },
parent() { parent() {
if (!this.task.listId) { if (!this.task.listId) {

View file

@ -68,7 +68,7 @@
<x-button <x-button
@click="submit" @click="submit"
:loading="loading" :loading="isLoading"
tabindex="4" tabindex="4"
> >
{{ $t('user.auth.login') }} {{ $t('user.auth.login') }}
@ -104,17 +104,17 @@
<script lang="ts"> <script lang="ts">
import {defineComponent} from 'vue' import {defineComponent} from 'vue'
import {useDebounceFn} from '@vueuse/core' import {useDebounceFn} from '@vueuse/core'
import {mapState as mapStateVuex} from 'vuex'
import {mapState} from 'pinia' import {mapState} from 'pinia'
import {HTTPFactory} from '@/http-common' import {HTTPFactory} from '@/http-common'
import {LOADING} from '@/store/mutation-types'
import {getErrorText} from '@/message' import {getErrorText} from '@/message'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {redirectToProvider} from '../../helpers/redirectToProvider' import {redirectToProvider} from '../../helpers/redirectToProvider'
import {getLastVisited, clearLastVisited} from '../../helpers/saveLastVisited' import {getLastVisited, clearLastVisited} from '../../helpers/saveLastVisited'
import Password from '@/components/input/password.vue' import Password from '@/components/input/password.vue'
import { setTitle } from '@/helpers/setTitle' import {setTitle} from '@/helpers/setTitle'
import {useBaseStore} from '@/stores/base'
import {useConfigStore} from '@/stores/config' import {useConfigStore} from '@/stores/config'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
@ -172,8 +172,8 @@ export default defineComponent({
hasOpenIdProviders() { hasOpenIdProviders() {
return this.openidConnect.enabled && this.openidConnect.providers?.length > 0 return this.openidConnect.enabled && this.openidConnect.providers?.length > 0
}, },
...mapStateVuex({ ...mapState(useBaseStore, {
loading: LOADING, isLoading: state => state.loading,
}), }),
...mapState(useAuthStore, { ...mapState(useAuthStore, {
@ -197,11 +197,11 @@ export default defineComponent({
methods: { methods: {
setLoading() { setLoading() {
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
this.loading = true this.isLoading = true
}, 100) }, 100)
return () => { return () => {
clearTimeout(timeout) clearTimeout(timeout)
this.loading = false this.isLoading = false
} }
}, },

View file

@ -15,13 +15,14 @@ export default { name: 'Auth' }
<script setup lang="ts"> <script setup lang="ts">
import {ref, computed, onMounted} from 'vue' import {ref, computed, onMounted} from 'vue'
import {useStore} from '@/store'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {getErrorText} from '@/message' import {getErrorText} from '@/message'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {clearLastVisited, getLastVisited} from '@/helpers/saveLastVisited' import {clearLastVisited, getLastVisited} from '@/helpers/saveLastVisited'
import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
const {t} = useI18n({useScope: 'global'}) const {t} = useI18n({useScope: 'global'})
@ -29,10 +30,10 @@ const {t} = useI18n({useScope: 'global'})
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const loading = computed(() => store.state.loading) const loading = computed(() => baseStore.loading)
const errorMessage = ref('') const errorMessage = ref('')
async function authenticateWithCode() { async function authenticateWithCode() {

View file

@ -50,7 +50,7 @@
</div> </div>
<x-button <x-button
:loading="loading" :loading="isLoading"
id="register-submit" id="register-submit"
@click="submit" @click="submit"
class="mr-2" class="mr-2"
@ -73,12 +73,14 @@ import {useDebounceFn} from '@vueuse/core'
import {ref, reactive, toRaw, computed, onBeforeMount} from 'vue' import {ref, reactive, toRaw, computed, onBeforeMount} from 'vue'
import router from '@/router' import router from '@/router'
import {store} from '@/store'
import Message from '@/components/misc/message.vue' import Message from '@/components/misc/message.vue'
import {isEmail} from '@/helpers/isEmail' import {isEmail} from '@/helpers/isEmail'
import Password from '@/components/input/password.vue' import Password from '@/components/input/password.vue'
import {useBaseStore} from '@/stores/base'
import {useAuthStore} from '@/stores/auth' import {useAuthStore} from '@/stores/auth'
const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
// FIXME: use the `beforeEnter` hook of vue-router // FIXME: use the `beforeEnter` hook of vue-router
@ -95,7 +97,7 @@ const credentials = reactive({
password: '', password: '',
}) })
const loading = computed(() => store.state.loading) const isLoading = computed(() => baseStore.loading)
const errorMessage = ref('') const errorMessage = ref('')
const validatePasswordInitially = ref(false) const validatePasswordInitially = ref(false)

View file

@ -159,7 +159,6 @@ export default defineComponent({
<script setup lang="ts"> <script setup lang="ts">
import {computed, watch, ref} from 'vue' import {computed, watch, ref} from 'vue'
import {useI18n} from 'vue-i18n' import {useI18n} from 'vue-i18n'
import {useStore} from '@/store'
import {PrefixMode} from '@/modules/parseTaskText' import {PrefixMode} from '@/modules/parseTaskText'
@ -172,6 +171,8 @@ import {createRandomID} from '@/helpers/randomId'
import {success} from '@/message' import {success} from '@/message'
import {AuthenticatedHTTPFactory} from '@/http-common' import {AuthenticatedHTTPFactory} from '@/http-common'
import {useBaseStore} from '@/stores/base'
import {useColorScheme} from '@/composables/useColorScheme' import {useColorScheme} from '@/composables/useColorScheme'
import {useTitle} from '@/composables/useTitle' import {useTitle} from '@/composables/useTitle'
import {objectIsEmpty} from '@/helpers/objectIsEmpty' import {objectIsEmpty} from '@/helpers/objectIsEmpty'
@ -227,7 +228,7 @@ function getPlaySoundWhenDoneSetting() {
const playSoundWhenDone = ref(getPlaySoundWhenDoneSetting()) const playSoundWhenDone = ref(getPlaySoundWhenDoneSetting())
const quickAddMagicMode = ref(getQuickAddMagicMode()) const quickAddMagicMode = ref(getQuickAddMagicMode())
const store = useStore() const baseStore = useBaseStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const settings = ref({...authStore.settings}) const settings = ref({...authStore.settings})
const id = ref(createRandomID()) const id = ref(createRandomID())
@ -256,7 +257,7 @@ const defaultList = computed({
settings.value.defaultListId = l ? l.id : DEFAULT_LIST_ID settings.value.defaultListId = l ? l.id : DEFAULT_LIST_ID
}, },
}) })
const loading = computed(() => store.state.loading && store.state.loadingModule === 'general-settings') const loading = computed(() => baseStore.loading && baseStore.loadingModule === 'general-settings')
watch( watch(
playSoundWhenDone, playSoundWhenDone,