Compare commits
10 Commits
feature/lo
...
renovate/p
| Author | SHA1 | Date | |
|---|---|---|---|
| cef98c003c | |||
|
|
cbbc4c0372 | ||
|
|
c7e708cf7d | ||
|
|
6d3a30c799 | ||
|
|
4c972e1bc4 | ||
|
|
144571e448 | ||
|
|
a24c64da8f | ||
|
|
2faa03757c | ||
|
|
9cef2c4c97 | ||
|
|
ea6b141d42 |
4
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: Found something you weren't expecting? Report it here!
|
||||
labels: kind/bug
|
||||
type: Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@@ -49,4 +49,4 @@ body:
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If this issue involves the Web Interface, please provide one or more screenshots
|
||||
description: If this issue involves the Web Interface, please provide one or more screenshots
|
||||
5
frontend/env.config.d.ts
vendored
5
frontend/env.config.d.ts
vendored
@@ -1,4 +1 @@
|
||||
declare module 'postcss-easing-gradients' {
|
||||
import postcssEasingGradients from 'postcss-easing-gradients'
|
||||
export default postcssEasingGradients
|
||||
}
|
||||
declare module 'postcss-easing-gradients';
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
"is-touch-device": "1.0.1",
|
||||
"klona": "2.0.6",
|
||||
"lowlight": "3.3.0",
|
||||
"pinia": "2.3.0",
|
||||
"pinia": "2.3.1",
|
||||
"register-service-worker": "1.7.2",
|
||||
"sortablejs": "1.15.6",
|
||||
"tailwindcss": "3.4.17",
|
||||
@@ -130,7 +130,7 @@
|
||||
"@vue/tsconfig": "0.7.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
"browserslist": "4.24.4",
|
||||
"caniuse-lite": "1.0.30001692",
|
||||
"caniuse-lite": "1.0.30001695",
|
||||
"csstype": "3.1.3",
|
||||
"cypress": "14.0.0",
|
||||
"esbuild": "0.24.2",
|
||||
|
||||
82
frontend/pnpm-lock.yaml
generated
82
frontend/pnpm-lock.yaml
generated
@@ -45,7 +45,7 @@ importers:
|
||||
version: 7.120.3
|
||||
'@sentry/vue':
|
||||
specifier: 8.50.0
|
||||
version: 8.50.0(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
version: 8.50.0(pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@tiptap/core':
|
||||
specifier: 2.11.2
|
||||
version: 2.11.2(@tiptap/pm@2.11.2)
|
||||
@@ -152,8 +152,8 @@ importers:
|
||||
specifier: 3.3.0
|
||||
version: 3.3.0
|
||||
pinia:
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||
specifier: 2.3.1
|
||||
version: 2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||
register-service-worker:
|
||||
specifier: 1.7.2
|
||||
version: 1.7.2
|
||||
@@ -255,8 +255,8 @@ importers:
|
||||
specifier: 4.24.4
|
||||
version: 4.24.4
|
||||
caniuse-lite:
|
||||
specifier: 1.0.30001692
|
||||
version: 1.0.30001692
|
||||
specifier: 1.0.30001695
|
||||
version: 1.0.30001695
|
||||
csstype:
|
||||
specifier: 3.1.3
|
||||
version: 3.1.3
|
||||
@@ -1535,6 +1535,7 @@ packages:
|
||||
'@faker-js/faker@9.4.0':
|
||||
resolution: {integrity: sha512-85+k0AxaZSTowL0gXp8zYWDIrWclTbRPg/pm/V0dSFZ6W6D4lhcG3uuZl4zLsEKfEvs69xDbLN2cHQudwp95JA==}
|
||||
engines: {node: '>=18.0.0', npm: '>=9.0.0'}
|
||||
deprecated: Please update to a newer version
|
||||
|
||||
'@floating-ui/core@1.6.7':
|
||||
resolution: {integrity: sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==}
|
||||
@@ -1643,22 +1644,26 @@ packages:
|
||||
resolution: {integrity: sha512-NAmhw1l/llM0HZRpagR/ChJTNymW4ll6/4EDSJML5c8L5Hl/+k6UyF8EIgE6DeHpfheQujkSRngauViHqq6jJQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.0.0-rc.1':
|
||||
resolution: {integrity: sha512-TGw2uBfuTFTegZf/BHtUQBEKxl7Q/dVGLoqRIdw8lFsp9g/53sYn5iD+0HxIzdYjbWL6BTJMXCPUHp9PxDTRPw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.0.1':
|
||||
resolution: {integrity: sha512-5RFH8x+Mn3mbjcHXnb6KCXGiczBdiQkWkv99iiA0JpKrNuTAQeW59Pjq/uObMB0eR0shnKYGTkIJxum+DbL3sw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.0.0-rc.1':
|
||||
resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==}
|
||||
'@intlify/message-compiler@12.0.0-alpha.3':
|
||||
resolution: {integrity: sha512-mDDTN3gfYOHhBnpnlby19UHyvMaOnzdlpsIrxUfs44R/vCATfn8pMOkE8PXD2t410xkocEj3FpDcC9XC/0v4Dg==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.0.1':
|
||||
resolution: {integrity: sha512-lH164+aDDptHZ3dBDbIhRa1dOPQUp+83iugpc+1upTOWCnwyC1PVis6rSWNMMJ8VQxvtHQB9JMib48K55y0PvQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.2.8':
|
||||
resolution: {integrity: sha512-l6e4NZyUgv8VyXXH4DbuucFOBmxLF56C/mqh2tvApbzl2Hrhi1aTDcuv5TKdxzfHYmpO3UB0Cz04fgDT9vszfw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@12.0.0-alpha.3':
|
||||
resolution: {integrity: sha512-ryaNYBvxQjyJUmVuBBg+HHUsmGnfxcEUPR0NCeG4/K9N2qtyFE35C80S15IN6iYFE2MGWLN7HfOSyg0MXZIc9w==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@6.0.3':
|
||||
resolution: {integrity: sha512-9ZDjBlhUHtgjRl23TVcgfJttgu8cNepwVhWvOv3mUMRDAhjW0pur1mWKEUKr1I8PNwE4Gvv2IQ1xcl4RL0nG0g==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -2947,8 +2952,8 @@ packages:
|
||||
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-lite@1.0.30001692:
|
||||
resolution: {integrity: sha512-A95VKan0kdtrsnMubMKxEKUKImOPSuCpYgxSQBo036P5YYgVIcOYJEgt/txJWqObiRQeISNCfef9nvlQ0vbV7A==}
|
||||
caniuse-lite@1.0.30001695:
|
||||
resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==}
|
||||
|
||||
capital-case@1.0.4:
|
||||
resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
|
||||
@@ -3883,11 +3888,12 @@ packages:
|
||||
|
||||
glob@10.4.5:
|
||||
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
hasBin: true
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
global-dirs@2.1.0:
|
||||
resolution: {integrity: sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==}
|
||||
@@ -4691,6 +4697,7 @@ packages:
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
deprecated: Use your platform's native DOMException instead
|
||||
|
||||
node-fetch@2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
@@ -4959,8 +4966,8 @@ packages:
|
||||
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
pinia@2.3.0:
|
||||
resolution: {integrity: sha512-ohZj3jla0LL0OH5PlLTDMzqKiVw2XARmC1XYLdLWIPBMdhDW/123ZWr4zVAhtJm+aoSkFa13pYXskAvAscIkhQ==}
|
||||
pinia@2.3.1:
|
||||
resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==}
|
||||
peerDependencies:
|
||||
typescript: '>=4.4.4'
|
||||
vue: ^2.7.0 || ^3.5.11
|
||||
@@ -5313,7 +5320,7 @@ packages:
|
||||
puppeteer@13.7.0:
|
||||
resolution: {integrity: sha512-U1uufzBjz3+PkpCxFrWzh4OrMIdIb2ztzCu0YEPfRHjHswcSwHZswnK+WdsOQJsRV8WeTg3jLhJR4D867+fjsA==}
|
||||
engines: {node: '>=10.18.1'}
|
||||
deprecated: < 22.8.2 is no longer supported
|
||||
deprecated: < 24.15.0 is no longer supported
|
||||
|
||||
qs@6.13.0:
|
||||
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
|
||||
@@ -5753,6 +5760,7 @@ packages:
|
||||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
||||
|
||||
sourcemap-codec@1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
@@ -6436,6 +6444,7 @@ packages:
|
||||
vue-i18n@11.0.1:
|
||||
resolution: {integrity: sha512-pWAT8CusK8q9/EpN7V3oxwHwxWm6+Kp2PeTZmRGvdZTkUzMQDpbbmHp0TwQ8xw04XKm23cr6B4GL72y3W8Yekg==}
|
||||
engines: {node: '>= 16'}
|
||||
deprecated: This version is NOT deprecated. Previous deprecation was a mistake.
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
@@ -6511,6 +6520,7 @@ packages:
|
||||
whatwg-encoding@2.0.0:
|
||||
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
|
||||
|
||||
whatwg-mimetype@3.0.0:
|
||||
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
|
||||
@@ -8105,8 +8115,8 @@ snapshots:
|
||||
|
||||
'@intlify/bundle-utils@10.0.0(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.0.0-rc.1
|
||||
'@intlify/shared': 11.0.0-rc.1
|
||||
'@intlify/message-compiler': 12.0.0-alpha.3
|
||||
'@intlify/shared': 12.0.0-alpha.3
|
||||
acorn: 8.14.0
|
||||
escodegen: 2.1.0
|
||||
estree-walker: 2.0.2
|
||||
@@ -8122,26 +8132,28 @@ snapshots:
|
||||
'@intlify/message-compiler': 11.0.1
|
||||
'@intlify/shared': 11.0.1
|
||||
|
||||
'@intlify/message-compiler@11.0.0-rc.1':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.0.0-rc.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/message-compiler@11.0.1':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.0.1
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@11.0.0-rc.1': {}
|
||||
'@intlify/message-compiler@12.0.0-alpha.3':
|
||||
dependencies:
|
||||
'@intlify/shared': 12.0.0-alpha.3
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@11.0.1': {}
|
||||
|
||||
'@intlify/shared@11.2.8': {}
|
||||
|
||||
'@intlify/shared@12.0.0-alpha.3': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@6.0.3(@vue/compiler-dom@3.5.13)(eslint@9.18.0(jiti@1.21.6))(rollup@4.30.1)(typescript@5.7.3)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@9.18.0(jiti@1.21.6))
|
||||
'@intlify/bundle-utils': 10.0.0(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))
|
||||
'@intlify/shared': 11.0.1
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@intlify/shared': 11.2.8
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.13)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))
|
||||
'@rollup/pluginutils': 5.1.3(rollup@4.30.1)
|
||||
'@typescript-eslint/scope-manager': 8.18.2
|
||||
'@typescript-eslint/typescript-estree': 8.18.2(typescript@5.7.3)
|
||||
@@ -8163,11 +8175,11 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.0.1)(@vue/compiler-dom@3.5.13)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.8)(@vue/compiler-dom@3.5.13)(vue-i18n@11.0.1(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@babel/parser': 7.26.1
|
||||
optionalDependencies:
|
||||
'@intlify/shared': 11.0.1
|
||||
'@intlify/shared': 11.2.8
|
||||
'@vue/compiler-dom': 3.5.13
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
vue-i18n: 11.0.1(vue@3.5.13(typescript@5.7.3))
|
||||
@@ -8529,13 +8541,13 @@ snapshots:
|
||||
dependencies:
|
||||
'@sentry/types': 7.120.3
|
||||
|
||||
'@sentry/vue@8.50.0(pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
'@sentry/vue@8.50.0(pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))':
|
||||
dependencies:
|
||||
'@sentry/browser': 8.50.0
|
||||
'@sentry/core': 8.50.0
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
optionalDependencies:
|
||||
pinia: 2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||
pinia: 2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3))
|
||||
|
||||
'@sideway/address@4.1.5':
|
||||
dependencies:
|
||||
@@ -9349,7 +9361,7 @@ snapshots:
|
||||
autoprefixer@10.4.20(postcss@8.5.1):
|
||||
dependencies:
|
||||
browserslist: 4.24.4
|
||||
caniuse-lite: 1.0.30001692
|
||||
caniuse-lite: 1.0.30001695
|
||||
fraction.js: 4.3.7
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.1
|
||||
@@ -9450,7 +9462,7 @@ snapshots:
|
||||
|
||||
browserslist@4.24.4:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001692
|
||||
caniuse-lite: 1.0.30001695
|
||||
electron-to-chromium: 1.5.73
|
||||
node-releases: 2.0.19
|
||||
update-browserslist-db: 1.1.1(browserslist@4.24.4)
|
||||
@@ -9513,7 +9525,7 @@ snapshots:
|
||||
|
||||
camelcase@5.3.1: {}
|
||||
|
||||
caniuse-lite@1.0.30001692: {}
|
||||
caniuse-lite@1.0.30001695: {}
|
||||
|
||||
capital-case@1.0.4:
|
||||
dependencies:
|
||||
@@ -11705,7 +11717,7 @@ snapshots:
|
||||
|
||||
pify@2.3.0: {}
|
||||
|
||||
pinia@2.3.0(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)):
|
||||
pinia@2.3.1(typescript@5.7.3)(vue@3.5.13(typescript@5.7.3)):
|
||||
dependencies:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.13(typescript@5.7.3)
|
||||
|
||||
@@ -63,7 +63,7 @@ const motd = computed(() => configStore.motd)
|
||||
|
||||
const route = useRoute()
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
const title = computed(() => t(route.meta?.title as string || ''))
|
||||
const title = computed(() => route.meta?.title ? t(route.meta.title as string) : '')
|
||||
useTitle(() => title.value)
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<div
|
||||
:class="{ 'is-loading': projectService.loading, 'is-archived': currentProject?.isArchived}"
|
||||
class="loader-container"
|
||||
:class="{
|
||||
'is-loading': isLoadingProject,
|
||||
'is-archived': currentProject?.isArchived,
|
||||
}"
|
||||
>
|
||||
<h1 class="project-title-print">
|
||||
{{ getProjectTitle(currentProject) }}
|
||||
@@ -37,43 +40,37 @@
|
||||
</Message>
|
||||
</CustomTransition>
|
||||
|
||||
<slot v-if="loadedProjectId" />
|
||||
<slot v-if="!isLoadingProject" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import {useRoute} from 'vue-router'
|
||||
import {computed} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
import Message from '@/components/misc/Message.vue'
|
||||
import CustomTransition from '@/components/misc/CustomTransition.vue'
|
||||
|
||||
import ProjectModel from '@/models/project'
|
||||
import ProjectService from '@/services/project'
|
||||
|
||||
import {getProjectTitle} from '@/helpers/getProjectTitle'
|
||||
import {saveProjectToHistory} from '@/modules/projectHistory'
|
||||
import {useTitle} from '@/composables/useTitle'
|
||||
|
||||
import {useBaseStore} from '@/stores/base'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
|
||||
import type {IProject} from '@/modelTypes/IProject'
|
||||
import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
const props = defineProps<{
|
||||
isLoadingProject: boolean,
|
||||
projectId: IProject['id'],
|
||||
viewId: IProjectView['id'],
|
||||
}>()
|
||||
|
||||
const route = useRoute()
|
||||
const {t} = useI18n()
|
||||
|
||||
const baseStore = useBaseStore()
|
||||
const projectStore = useProjectStore()
|
||||
const projectService = ref(new ProjectService())
|
||||
const loadedProjectId = ref(0)
|
||||
|
||||
const currentProject = computed<IProject>(() => {
|
||||
return typeof baseStore.currentProject === 'undefined' ? {
|
||||
@@ -87,61 +84,6 @@ useTitle(() => currentProject.value?.id ? getProjectTitle(currentProject.value)
|
||||
|
||||
const views = computed(() => projectStore.projects[props.projectId]?.views)
|
||||
|
||||
// watchEffect would be called every time the prop would get a value assigned, even if that value was the same as before.
|
||||
// This resulted in loading and setting the project multiple times, even when navigating away from it.
|
||||
// This caused wired bugs where the project background would be set on the home page but only right after setting a new
|
||||
// project background and then navigating to home. It also highlighted the project in the menu and didn't allow changing any
|
||||
// of it, most likely due to the rights not being properly populated.
|
||||
watch(
|
||||
() => props.projectId,
|
||||
// loadProject
|
||||
async (projectIdToLoad: number) => {
|
||||
const projectData = {id: projectIdToLoad}
|
||||
saveProjectToHistory(projectData)
|
||||
|
||||
// Don't load the project if we either already loaded it or aren't dealing with a project at all currently and
|
||||
// the currently loaded project has the right set.
|
||||
if (
|
||||
(
|
||||
projectIdToLoad === loadedProjectId.value ||
|
||||
typeof projectIdToLoad === 'undefined' ||
|
||||
projectIdToLoad === currentProject.value?.id
|
||||
)
|
||||
&& typeof currentProject.value !== 'undefined' && currentProject.value.maxRight !== null
|
||||
) {
|
||||
loadedProjectId.value = projectIdToLoad
|
||||
return
|
||||
}
|
||||
|
||||
console.debug('Loading project, $route.params =', route.params, `, loadedProjectId = ${loadedProjectId.value}, currentProject = `, currentProject.value)
|
||||
|
||||
// Set the current project to the one we're about to load so that the title is already shown at the top
|
||||
loadedProjectId.value = 0
|
||||
const projectFromStore = projectStore.projects[projectData.id]
|
||||
if (projectFromStore) {
|
||||
baseStore.handleSetCurrentProject({project: projectFromStore, currentProjectViewId: props.viewId})
|
||||
}
|
||||
|
||||
// We create an extra project object instead of creating it in project.value because that would trigger a ui update which would result in bad ux.
|
||||
const project = new ProjectModel(projectData)
|
||||
try {
|
||||
const loadedProject = await projectService.value.get(project)
|
||||
baseStore.handleSetCurrentProject({project: loadedProject, currentProjectViewId: props.viewId})
|
||||
} finally {
|
||||
loadedProjectId.value = projectIdToLoad
|
||||
}
|
||||
},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.viewId,
|
||||
() => {
|
||||
baseStore.setCurrentProjectViewId(props.viewId)
|
||||
},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
function getViewTitle(view: IProjectView) {
|
||||
switch (view.title) {
|
||||
case 'List':
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<ProjectWrapper
|
||||
class="project-gantt"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:project-id="filters.projectId"
|
||||
:view-id
|
||||
>
|
||||
@@ -95,6 +96,7 @@ import type {IProjectView} from '@/modelTypes/IProjectView'
|
||||
type Options = Flatpickr.Options.Options
|
||||
|
||||
const props = defineProps<{
|
||||
isLoadingProject: boolean,
|
||||
route: RouteLocationNormalized
|
||||
viewId: IProjectView['id']
|
||||
}>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<ProjectWrapper
|
||||
class="project-kanban"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:project-id="projectId"
|
||||
:view-id
|
||||
>
|
||||
@@ -315,6 +316,7 @@ import TaskBucketService from '@/services/taskBucket'
|
||||
import TaskBucketModel from '@/models/taskBucket'
|
||||
|
||||
const props = defineProps<{
|
||||
isLoadingProject: boolean,
|
||||
projectId: number,
|
||||
viewId: IProjectView['id'],
|
||||
}>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<ProjectWrapper
|
||||
class="project-list"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:project-id="projectId"
|
||||
:view-id
|
||||
>
|
||||
@@ -123,6 +124,7 @@ import TaskPositionService from '@/services/taskPosition'
|
||||
import TaskPositionModel from '@/models/taskPosition'
|
||||
|
||||
const props = defineProps<{
|
||||
isLoadingProject: boolean,
|
||||
projectId: IProject['id'],
|
||||
viewId: IProjectView['id'],
|
||||
}>()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<ProjectWrapper
|
||||
class="project-table"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:project-id="projectId"
|
||||
:view-id
|
||||
>
|
||||
@@ -298,6 +299,7 @@ import { camelCase } from 'change-case'
|
||||
import {isSavedFilter} from '@/services/savedFilter'
|
||||
|
||||
const props = defineProps<{
|
||||
isLoadingProject: boolean,
|
||||
projectId: IProject['id'],
|
||||
viewId: IProjectView['id'],
|
||||
}>()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {computed} from 'vue'
|
||||
import {computed, toValue} from 'vue'
|
||||
|
||||
import {useTitle as useTitleVueUse, toValue, type UseTitleOptions, type ReadonlyRefOrGetter, type MaybeRef, type MaybeRefOrGetter} from '@vueuse/core'
|
||||
import {useTitle as useTitleVueUse, type UseTitleOptions, type ReadonlyRefOrGetter, type MaybeRef, type MaybeRefOrGetter} from '@vueuse/core'
|
||||
|
||||
export function useTitle(
|
||||
newTitle:
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, watch} from 'vue'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
import {computed, ref, shallowReactive, watch, watchEffect} from 'vue'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
|
||||
import {useBaseStore} from '@/stores/base'
|
||||
import {useProjectStore} from '@/stores/projects'
|
||||
import {useAuthStore} from '@/stores/auth'
|
||||
|
||||
import {saveProjectView} from '@/helpers/projectView'
|
||||
import ProjectService from '@/services/project'
|
||||
|
||||
import ProjectList from '@/components/project/views/ProjectList.vue'
|
||||
import ProjectGantt from '@/components/project/views/ProjectGantt.vue'
|
||||
import ProjectTable from '@/components/project/views/ProjectTable.vue'
|
||||
import ProjectKanban from '@/components/project/views/ProjectKanban.vue'
|
||||
import {useAuthStore} from '@/stores/auth'
|
||||
|
||||
import {DEFAULT_PROJECT_VIEW_SETTINGS} from '@/modelTypes/IProjectView'
|
||||
import {saveProjectToHistory} from '@/modules/projectHistory'
|
||||
|
||||
const props = defineProps<{
|
||||
projectId: number,
|
||||
@@ -17,8 +23,10 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
const baseStore = useBaseStore()
|
||||
const projectStore = useProjectStore()
|
||||
const authStore = useAuthStore()
|
||||
const route = useRoute()
|
||||
|
||||
const currentProject = computed(() => projectStore.projects[props.projectId])
|
||||
|
||||
@@ -26,19 +34,68 @@ const currentView = computed(() => {
|
||||
return currentProject.value?.views.find(v => v.id === props.viewId)
|
||||
})
|
||||
|
||||
const projectService = shallowReactive(new ProjectService())
|
||||
const isLoadingProject = computed(() => projectService.loading)
|
||||
const loadedProjectId = ref(0)
|
||||
|
||||
watch(
|
||||
() => props.projectId,
|
||||
// loadProject
|
||||
async (projectIdToLoad, oldProjectIdToLoad) => {
|
||||
|
||||
console.debug('Loading project, $route.params =', route.params, `, loadedProjectId = ${loadedProjectId.value}, currentProject = `, currentProject.value)
|
||||
|
||||
|
||||
if (projectIdToLoad !== oldProjectIdToLoad) {
|
||||
loadedProjectId.value = 0
|
||||
}
|
||||
|
||||
try {
|
||||
const loadedProject = await projectService.get({id: projectIdToLoad})
|
||||
|
||||
// Here, we only set the new project in the projectStore.
|
||||
// Setting that projet as the current one in the baseStore is handled by the watcher below.
|
||||
projectStore.setProject(loadedProject)
|
||||
} finally {
|
||||
loadedProjectId.value = projectIdToLoad
|
||||
}
|
||||
},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => [currentProject.value, props.viewId],
|
||||
([newCurrentProject, newViewId]) => {
|
||||
if (!newCurrentProject) {
|
||||
baseStore.handleSetCurrentProject({project: null})
|
||||
return
|
||||
}
|
||||
|
||||
baseStore.handleSetCurrentProject({
|
||||
project: newCurrentProject,
|
||||
currentProjectViewId: newViewId,
|
||||
})
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
)
|
||||
|
||||
function redirectToDefaultViewIfNecessary() {
|
||||
if (props.viewId === 0 || !projectStore.projects[props.projectId]?.views.find(v => v.id === props.viewId)) {
|
||||
if (props.viewId === 0 || !currentView.value) {
|
||||
// Ideally, we would do that in the router redirect, but the projects (and therefore, the views)
|
||||
// are not always loaded then.
|
||||
|
||||
const defaultView = authStore.settings.frontendSettings.defaultView
|
||||
|
||||
let view
|
||||
if (authStore.settings.frontendSettings.defaultView !== DEFAULT_PROJECT_VIEW_SETTINGS.FIRST) {
|
||||
view = projectStore.projects[props.projectId]?.views.find(v => v.viewKind === authStore.settings.frontendSettings.defaultView)
|
||||
if (defaultView !== DEFAULT_PROJECT_VIEW_SETTINGS.FIRST) {
|
||||
view = currentProject.value?.views.find(v => v.viewKind === defaultView)
|
||||
}
|
||||
|
||||
// Use the first view as fallback if the default view is not available
|
||||
if (view === undefined && projectStore.projects[props.projectId]?.views?.length > 0) {
|
||||
view = projectStore.projects[props.projectId]?.views[0]
|
||||
if (view === undefined && currentProject.value?.views?.length > 0) {
|
||||
view = currentProject.value?.views[0]
|
||||
}
|
||||
|
||||
if (view) {
|
||||
@@ -60,39 +117,39 @@ watch(
|
||||
)
|
||||
|
||||
watch(
|
||||
() => projectStore.projects[props.projectId],
|
||||
currentProject,
|
||||
redirectToDefaultViewIfNecessary,
|
||||
)
|
||||
|
||||
// using a watcher instead of beforeEnter because beforeEnter is not called when only the viewId changes
|
||||
watch(
|
||||
() => [props.projectId, props.viewId],
|
||||
() => saveProjectView(props.projectId, props.viewId),
|
||||
{immediate: true},
|
||||
)
|
||||
watchEffect(() => saveProjectToHistory({id: props.projectId}))
|
||||
watchEffect(() => saveProjectView(props.projectId, props.viewId))
|
||||
|
||||
const route = useRoute()
|
||||
watchEffect(() => baseStore.setCurrentProjectViewId(props.viewId))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ProjectList
|
||||
v-if="currentView?.viewKind === 'list'"
|
||||
:project-id="projectId"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:view-id
|
||||
/>
|
||||
<ProjectGantt
|
||||
v-if="currentView?.viewKind === 'gantt'"
|
||||
:route
|
||||
:is-loading-project="isLoadingProject"
|
||||
:view-id
|
||||
/>
|
||||
<ProjectTable
|
||||
v-if="currentView?.viewKind === 'table'"
|
||||
:project-id="projectId"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:view-id
|
||||
/>
|
||||
<ProjectKanban
|
||||
v-if="currentView?.viewKind === 'kanban'"
|
||||
:project-id="projectId"
|
||||
:is-loading-project="isLoadingProject"
|
||||
:view-id
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
"@tsconfig/node22/tsconfig.json",
|
||||
"@vue/tsconfig/tsconfig.json"
|
||||
],
|
||||
"include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
|
||||
"include": [
|
||||
"env.config.d.ts",
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
|
||||
@@ -184,7 +184,7 @@ export default defineConfig(({mode}) => {
|
||||
},
|
||||
}),
|
||||
vueDevTools({
|
||||
launchEditor: env.VUE_DEVTOOLS_LAUNCH_EDITOR || 'code'
|
||||
launchEditor: env.VUE_DEVTOOLS_LAUNCH_EDITOR || 'code',
|
||||
}),
|
||||
viteSentry(getSentryConfig(env)),
|
||||
],
|
||||
|
||||
2
go.mod
2
go.mod
@@ -67,7 +67,7 @@ require (
|
||||
github.com/tkuchiki/go-timezone v0.2.3
|
||||
github.com/typesense/typesense-go/v2 v2.0.0
|
||||
github.com/ulule/limiter/v3 v3.11.2
|
||||
github.com/wneessen/go-mail v0.6.0
|
||||
github.com/wneessen/go-mail v0.6.1
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/image v0.23.0
|
||||
|
||||
2
go.sum
2
go.sum
@@ -1377,6 +1377,8 @@ github.com/wneessen/go-mail v0.5.2 h1:MZKwgHJoRboLJ+EHMLuHpZc95wo+u1xViL/4XSswDT
|
||||
github.com/wneessen/go-mail v0.5.2/go.mod h1:kRroJvEq2hOSEPFRiKjN7Csrz0G1w+RpiGR3b6yo+Ck=
|
||||
github.com/wneessen/go-mail v0.6.0 h1:wO7EeJ8RL6DD+aycFGntil6b11g3FNQpQQQC1gkm97Y=
|
||||
github.com/wneessen/go-mail v0.6.0/go.mod h1:G702XlFhzHV0Z4w9j2VsH5K9dJDvj0hx+yOOp1oX9vc=
|
||||
github.com/wneessen/go-mail v0.6.1 h1:cDGqlGuEEhdILRe53VFzmM9WBk8Xh/QMvbO0oxrNJB4=
|
||||
github.com/wneessen/go-mail v0.6.1/go.mod h1:G702XlFhzHV0Z4w9j2VsH5K9dJDvj0hx+yOOp1oX9vc=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
|
||||
Reference in New Issue
Block a user