From 5eb2f46d8e94982885d0c678a7b5382d29cb60fb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 31 Aug 2025 09:44:11 +0000 Subject: [PATCH 001/202] chore(deps): update dependency unplugin-vue-components to v29 --- frontend/package-lock.json | 14 +++++++------- frontend/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8c79d95cd3..68b5cb1bef 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -101,7 +101,7 @@ "prettier": "3.6.2", "sass": "1.78.0", "source-map": "0.7.4", - "unplugin-vue-components": "28.8.0", + "unplugin-vue-components": "29.0.0", "vite": "6.3.5", "vite-plugin-comlink": "5.3.0", "vite-plugin-vue2-svg": "0.4.0", @@ -11664,9 +11664,9 @@ } }, "node_modules/unplugin-vue-components": { - "version": "28.8.0", - "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-28.8.0.tgz", - "integrity": "sha512-2Q6ZongpoQzuXDK0ZsVzMoshH0MWZQ1pzVL538G7oIDKRTVzHjppBDS8aB99SADGHN3lpGU7frraCG6yWNoL5Q==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-29.0.0.tgz", + "integrity": "sha512-M2DX44g4/jvBkB0V6uwqTbkTd5DMRHpeGoi/cIKwGG4HPuNxLbe8zoTStB2n12hoDiWc9I1PIRQruRWExNXHlQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11723,9 +11723,9 @@ } }, "node_modules/unplugin-vue-components/node_modules/unplugin": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.8.tgz", - "integrity": "sha512-lkaSIlxceytPyt9yfb1h7L9jDFqwMqvUZeGsKB7Z8QrvAO3xZv2S+xMQQYzxk0AGJHcQhbcvhKEstrMy99jnuQ==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.9.tgz", + "integrity": "sha512-2dcbZq6aprwXTkzptq3k5qm5B8cvpjG9ynPd5fyM2wDJuuF7PeUK64Sxf0d+X1ZyDOeGydbNzMqBSIVlH8GIfA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 9089a6b139..f7f432983c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -114,7 +114,7 @@ "prettier": "3.6.2", "sass": "1.78.0", "source-map": "0.7.4", - "unplugin-vue-components": "28.8.0", + "unplugin-vue-components": "29.0.0", "vite": "6.3.5", "vite-plugin-comlink": "5.3.0", "vite-plugin-vue2-svg": "0.4.0", From f7e0f8fd83f0d1e4481f4ccd0164a1b196284e37 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:13:59 +0000 Subject: [PATCH 002/202] fix(deps): update vue-minor-print-pdf to v3.5.21 --- pdf/package-lock.json | 120 ++++++++++++++++++++-------------------- pdf/package.json | 12 ++-- print/package-lock.json | 120 ++++++++++++++++++++-------------------- print/package.json | 12 ++-- 4 files changed, 132 insertions(+), 132 deletions(-) diff --git a/pdf/package-lock.json b/pdf/package-lock.json index 71f67f4509..bdc7095d03 100644 --- a/pdf/package-lock.json +++ b/pdf/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "@ecamp3/client-pdf", "dependencies": { - "@vue/runtime-core": "3.5.20", + "@vue/runtime-core": "3.5.21", "html-entities": "2.6.0", "html-parse-stringify": "3.0.1" }, @@ -19,12 +19,12 @@ "@vitejs/plugin-vue": "6.0.1", "@vitest/coverage-v8": "3.2.4", "@vue/babel-preset-app": "5.0.9", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", "@vue/eslint-config-prettier": "10.2.0", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21", "@vue/test-utils": "2.4.6", "css": "3.0.0", "dayjs": "1.11.18", @@ -3598,57 +3598,57 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", - "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", + "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", - "@vue/shared": "3.5.20", + "@vue/shared": "3.5.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", - "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", + "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-core": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz", - "integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", + "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", - "@vue/compiler-core": "3.5.20", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/compiler-core": "3.5.21", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.17", + "magic-string": "^0.30.18", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz", - "integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", + "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-dom": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/eslint-config-prettier": { @@ -3667,55 +3667,55 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.20.tgz", - "integrity": "sha512-hS8l8x4cl1fmZpSQX/NXlqWKARqEsNmfkwOIYqtR2F616NGfsLUm0G6FQBK6uDKUCVyi1YOL8Xmt/RkZcd/jYQ==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", + "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.20" + "@vue/shared": "3.5.21" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.20.tgz", - "integrity": "sha512-vyQRiH5uSZlOa+4I/t4Qw/SsD/gbth0SW2J7oMeVlMFMAmsG1rwDD6ok0VMmjXY3eI0iHNSSOBilEDW98PLRKw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", + "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/reactivity": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.20.tgz", - "integrity": "sha512-KBHzPld/Djw3im0CQ7tGCpgRedryIn4CcAl047EhFTCCPT2xFf4e8j6WeKLgEEoqPSl9TYqShc3Q6tpWpz/Xgw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", + "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/runtime-core": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/reactivity": "3.5.21", + "@vue/runtime-core": "3.5.21", + "@vue/shared": "3.5.21", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.20.tgz", - "integrity": "sha512-HthAS0lZJDH21HFJBVNTtx+ULcIbJQRpjSVomVjfyPkFSpCwvsPTA+jIzOaUm3Hrqx36ozBHePztQFg6pj5aKg==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", + "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21" }, "peerDependencies": { - "vue": "3.5.20" + "vue": "3.5.21" } }, "node_modules/@vue/shared": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", - "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", + "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==", "license": "MIT" }, "node_modules/@vue/test-utils": { @@ -7531,18 +7531,18 @@ } }, "node_modules/vue": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.20.tgz", - "integrity": "sha512-2sBz0x/wis5TkF1XZ2vH25zWq3G1bFEPOfkBcx2ikowmphoQsPH6X0V3mmPCXA2K1N/XGTnifVyDQP4GfDDeQw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", + "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21" }, "peerDependencies": { "typescript": "*" diff --git a/pdf/package.json b/pdf/package.json index 96e51dd02c..003cac4097 100644 --- a/pdf/package.json +++ b/pdf/package.json @@ -18,7 +18,7 @@ "lint:check:prettier": "prettier --check --ignore-path .prettierignore **/*.{css,scss,json,mjs}" }, "dependencies": { - "@vue/runtime-core": "3.5.20", + "@vue/runtime-core": "3.5.21", "html-entities": "2.6.0", "html-parse-stringify": "3.0.1" }, @@ -40,12 +40,12 @@ "@vitejs/plugin-vue": "6.0.1", "@vitest/coverage-v8": "3.2.4", "@vue/babel-preset-app": "5.0.9", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", "@vue/eslint-config-prettier": "10.2.0", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21", "@vue/test-utils": "2.4.6", "css": "3.0.0", "dayjs": "1.11.18", diff --git a/print/package-lock.json b/print/package-lock.json index fe741180f8..8315dd2e90 100644 --- a/print/package-lock.json +++ b/print/package-lock.json @@ -30,11 +30,11 @@ "@tailwindcss/typography": "0.5.16", "@typescript-eslint/eslint-plugin": "8.41.0", "@vitest/coverage-v8": "3.2.4", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21", "@vue/test-utils": "2.4.6", "eslint": "9.34.0", "eslint-config-prettier": "10.1.8", @@ -49,7 +49,7 @@ "vite-plugin-eslint2": "5.0.4", "vite-svg-loader": "5.1.0", "vitest": "3.2.4", - "vue": "3.5.20" + "vue": "3.5.21" } }, "node_modules/@alloc/quick-lru": { @@ -6910,53 +6910,53 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", - "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", + "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", - "@vue/shared": "3.5.20", + "@vue/shared": "3.5.21", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", - "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", + "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-core": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.20.tgz", - "integrity": "sha512-SFcxapQc0/feWiSBfkGsa1v4DOrnMAQSYuvDMpEaxbpH5dKbnEM5KobSNSgU+1MbHCl+9ftm7oQWxvwDB6iBfw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", + "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.28.3", - "@vue/compiler-core": "3.5.20", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/compiler-core": "3.5.21", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21", "estree-walker": "^2.0.2", - "magic-string": "^0.30.17", + "magic-string": "^0.30.18", "postcss": "^8.5.6", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.20.tgz", - "integrity": "sha512-RSl5XAMc5YFUXpDQi+UQDdVjH9FnEpLDHIALg5J0ITHxkEzJ8uQLlo7CIbjPYqmZtt6w0TsIPbo1izYXwDG7JA==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", + "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-dom": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/compiler-vue2": { @@ -7046,53 +7046,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.20.tgz", - "integrity": "sha512-hS8l8x4cl1fmZpSQX/NXlqWKARqEsNmfkwOIYqtR2F616NGfsLUm0G6FQBK6uDKUCVyi1YOL8Xmt/RkZcd/jYQ==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", + "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.20" + "@vue/shared": "3.5.21" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.20.tgz", - "integrity": "sha512-vyQRiH5uSZlOa+4I/t4Qw/SsD/gbth0SW2J7oMeVlMFMAmsG1rwDD6ok0VMmjXY3eI0iHNSSOBilEDW98PLRKw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", + "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/reactivity": "3.5.21", + "@vue/shared": "3.5.21" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.20.tgz", - "integrity": "sha512-KBHzPld/Djw3im0CQ7tGCpgRedryIn4CcAl047EhFTCCPT2xFf4e8j6WeKLgEEoqPSl9TYqShc3Q6tpWpz/Xgw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", + "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.20", - "@vue/runtime-core": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/reactivity": "3.5.21", + "@vue/runtime-core": "3.5.21", + "@vue/shared": "3.5.21", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.20.tgz", - "integrity": "sha512-HthAS0lZJDH21HFJBVNTtx+ULcIbJQRpjSVomVjfyPkFSpCwvsPTA+jIzOaUm3Hrqx36ozBHePztQFg6pj5aKg==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", + "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21" }, "peerDependencies": { - "vue": "3.5.20" + "vue": "3.5.21" } }, "node_modules/@vue/shared": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", - "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", + "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==", "license": "MIT" }, "node_modules/@vue/test-utils": { @@ -20149,16 +20149,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.20.tgz", - "integrity": "sha512-2sBz0x/wis5TkF1XZ2vH25zWq3G1bFEPOfkBcx2ikowmphoQsPH6X0V3mmPCXA2K1N/XGTnifVyDQP4GfDDeQw==", + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", + "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20" + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21" }, "peerDependencies": { "typescript": "*" diff --git a/print/package.json b/print/package.json index 05bf50c115..223a391315 100644 --- a/print/package.json +++ b/print/package.json @@ -40,11 +40,11 @@ "@tailwindcss/typography": "0.5.16", "@typescript-eslint/eslint-plugin": "8.41.0", "@vitest/coverage-v8": "3.2.4", - "@vue/compiler-dom": "3.5.20", - "@vue/compiler-sfc": "3.5.20", - "@vue/runtime-dom": "3.5.20", - "@vue/server-renderer": "3.5.20", - "@vue/shared": "3.5.20", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21", "@vue/test-utils": "2.4.6", "eslint": "9.34.0", "eslint-config-prettier": "10.1.8", @@ -59,7 +59,7 @@ "vite-plugin-eslint2": "5.0.4", "vite-svg-loader": "5.1.0", "vitest": "3.2.4", - "vue": "3.5.20" + "vue": "3.5.21" }, "overrides": { "uri-js": "npm:uri-js-replace" From 29b6fd4f127f45251f113da6251aa5c1a8ec42c3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 18:14:08 +0000 Subject: [PATCH 003/202] chore(deps): update dependency @typescript-eslint/eslint-plugin to v8.42.0 --- print/package-lock.json | 110 ++++++++++++++++++++-------------------- print/package.json | 2 +- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/print/package-lock.json b/print/package-lock.json index fe741180f8..24de997652 100644 --- a/print/package-lock.json +++ b/print/package-lock.json @@ -28,7 +28,7 @@ "@nuxtjs/i18n": "10.0.6", "@nuxtjs/tailwindcss": "6.14.0", "@tailwindcss/typography": "0.5.16", - "@typescript-eslint/eslint-plugin": "8.41.0", + "@typescript-eslint/eslint-plugin": "8.42.0", "@vitest/coverage-v8": "3.2.4", "@vue/compiler-dom": "3.5.20", "@vue/compiler-sfc": "3.5.20", @@ -6037,17 +6037,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz", - "integrity": "sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.42.0.tgz", + "integrity": "sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.41.0", - "@typescript-eslint/type-utils": "8.41.0", - "@typescript-eslint/utils": "8.41.0", - "@typescript-eslint/visitor-keys": "8.41.0", + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/type-utils": "8.42.0", + "@typescript-eslint/utils": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -6061,22 +6061,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.41.0", + "@typescript-eslint/parser": "^8.42.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.41.0.tgz", - "integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.42.0.tgz", + "integrity": "sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.41.0", - "@typescript-eslint/types": "8.41.0", - "@typescript-eslint/typescript-estree": "8.41.0", - "@typescript-eslint/visitor-keys": "8.41.0", + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4" }, "engines": { @@ -6092,14 +6092,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.41.0.tgz", - "integrity": "sha512-b8V9SdGBQzQdjJ/IO3eDifGpDBJfvrNTp2QD9P2BeqWTGrRibgfgIlBSw6z3b6R7dPzg752tOs4u/7yCLxksSQ==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.42.0.tgz", + "integrity": "sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.41.0", - "@typescript-eslint/types": "^8.41.0", + "@typescript-eslint/tsconfig-utils": "^8.42.0", + "@typescript-eslint/types": "^8.42.0", "debug": "^4.3.4" }, "engines": { @@ -6114,14 +6114,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.41.0.tgz", - "integrity": "sha512-n6m05bXn/Cd6DZDGyrpXrELCPVaTnLdPToyhBoFkLIMznRUQUEQdSp96s/pcWSQdqOhrgR1mzJ+yItK7T+WPMQ==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.42.0.tgz", + "integrity": "sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.41.0", - "@typescript-eslint/visitor-keys": "8.41.0" + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6132,9 +6132,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.41.0.tgz", - "integrity": "sha512-TDhxYFPUYRFxFhuU5hTIJk+auzM/wKvWgoNYOPcOf6i4ReYlOoYN8q1dV5kOTjNQNJgzWN3TUUQMtlLOcUgdUw==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.42.0.tgz", + "integrity": "sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==", "dev": true, "license": "MIT", "engines": { @@ -6149,15 +6149,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.41.0.tgz", - "integrity": "sha512-63qt1h91vg3KsjVVonFJWjgSK7pZHSQFKH6uwqxAH9bBrsyRhO6ONoKyXxyVBzG1lJnFAJcKAcxLS54N1ee1OQ==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.42.0.tgz", + "integrity": "sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.41.0", - "@typescript-eslint/typescript-estree": "8.41.0", - "@typescript-eslint/utils": "8.41.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0", + "@typescript-eslint/utils": "8.42.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -6174,9 +6174,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.41.0.tgz", - "integrity": "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.42.0.tgz", + "integrity": "sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==", "dev": true, "license": "MIT", "engines": { @@ -6188,16 +6188,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.41.0.tgz", - "integrity": "sha512-D43UwUYJmGhuwHfY7MtNKRZMmfd8+p/eNSfFe6tH5mbVDto+VQCayeAt35rOx3Cs6wxD16DQtIKw/YXxt5E0UQ==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.42.0.tgz", + "integrity": "sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.41.0", - "@typescript-eslint/tsconfig-utils": "8.41.0", - "@typescript-eslint/types": "8.41.0", - "@typescript-eslint/visitor-keys": "8.41.0", + "@typescript-eslint/project-service": "8.42.0", + "@typescript-eslint/tsconfig-utils": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/visitor-keys": "8.42.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -6217,16 +6217,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.41.0.tgz", - "integrity": "sha512-udbCVstxZ5jiPIXrdH+BZWnPatjlYwJuJkDA4Tbo3WyYLh8NvB+h/bKeSZHDOFKfphsZYJQqaFtLeXEqurQn1A==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.42.0.tgz", + "integrity": "sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.41.0", - "@typescript-eslint/types": "8.41.0", - "@typescript-eslint/typescript-estree": "8.41.0" + "@typescript-eslint/scope-manager": "8.42.0", + "@typescript-eslint/types": "8.42.0", + "@typescript-eslint/typescript-estree": "8.42.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6241,13 +6241,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.41.0.tgz", - "integrity": "sha512-+GeGMebMCy0elMNg67LRNoVnUFPIm37iu5CmHESVx56/9Jsfdpsvbv605DQ81Pi/x11IdKUsS5nzgTYbCQU9fg==", + "version": "8.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.42.0.tgz", + "integrity": "sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.41.0", + "@typescript-eslint/types": "8.42.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { diff --git a/print/package.json b/print/package.json index 05bf50c115..bce63fa056 100644 --- a/print/package.json +++ b/print/package.json @@ -38,7 +38,7 @@ "@nuxtjs/i18n": "10.0.6", "@nuxtjs/tailwindcss": "6.14.0", "@tailwindcss/typography": "0.5.16", - "@typescript-eslint/eslint-plugin": "8.41.0", + "@typescript-eslint/eslint-plugin": "8.42.0", "@vitest/coverage-v8": "3.2.4", "@vue/compiler-dom": "3.5.20", "@vue/compiler-sfc": "3.5.20", From b04a6dc474c6d9ef027b36fae5f6a76867cf783a Mon Sep 17 00:00:00 2001 From: BacLuc Date: Fri, 1 Aug 2025 00:38:41 +0200 Subject: [PATCH 004/202] CI: parallelize docker build And simplify adding new image. Now you just have to add a docker compose with an image name and a build section. Also unset the image of api for dev, some people had problems when there was an image defined which cannot be downloaded. Populate the buildArgValues in the build-and-push step because passing secrets between jobs seems to be discouraged by github. https://github.com/orgs/community/discussions/37942 --- .docker-hub/docker-compose.yml | 28 ++ .github/workflows/reusable-build-and-push.yml | 242 +++++++++++++----- .../workflows/reusable-e2e-tests-build.yml | 2 +- docker-compose.override.yml | 1 + docker-compose.yml | 2 +- 5 files changed, 204 insertions(+), 71 deletions(-) create mode 100644 .docker-hub/docker-compose.yml diff --git a/.docker-hub/docker-compose.yml b/.docker-hub/docker-compose.yml new file mode 100644 index 0000000000..71c36fe104 --- /dev/null +++ b/.docker-hub/docker-compose.yml @@ -0,0 +1,28 @@ +services: + frontend-image: + image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-frontend:${VERSION:-latest} + build: + context: ../ + dockerfile: .docker-hub/frontend/Dockerfile + # they have to be registered in GitHub under exactly this name in secrets or vars + args: + SENTRY_AUTH_TOKEN: ${SENTRY_AUTH_TOKEN:-} + SENTRY_ORG: ${SENTRY_ORG:-} + SENTRY_FRONTEND_PROJECT: ${SENTRY_FRONTEND_PROJECT:-} + SENTRY_RELEASE_NAME: ${RELEASE_NAME:-} + print-image: + image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-print:${VERSION:-latest} + build: + context: ../ + dockerfile: .docker-hub/print/Dockerfile + # they have to be registered in GitHub under exactly this name in secrets or vars + args: + SENTRY_AUTH_TOKEN: ${SENTRY_AUTH_TOKEN:-} + SENTRY_ORG: ${SENTRY_ORG:-} + SENTRY_PRINT_PROJECT: ${SENTRY_PRINT_PROJECT:-} + SENTRY_RELEASE_NAME: ${RELEASE_NAME:-} + varnish-image: + image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-varnish:${VERSION:-latest} + build: + context: ../ + dockerfile: .docker-hub/varnish/Dockerfile diff --git a/.github/workflows/reusable-build-and-push.yml b/.github/workflows/reusable-build-and-push.yml index bcb4d9fac7..7caaf08b84 100644 --- a/.github/workflows/reusable-build-and-push.yml +++ b/.github/workflows/reusable-build-and-push.yml @@ -1,6 +1,7 @@ -name: '[reusable only] Build images and push to registry' +name: "[reusable only] Build images and push to registry" on: + workflow_dispatch: workflow_call: inputs: tag: @@ -17,14 +18,135 @@ on: required: true SENTRY_AUTH_TOKEN: +env: + DOCKER_BUILDKIT: 1 + COMPOSE_DOCKER_CLI_BUILD: 1 + jobs: - build-and-push: - name: Build images and push + build-info: runs-on: ubuntu-latest + outputs: + repo-owner: ${{ steps.repo-owner.outputs.result }} + tags: ${{ steps.image-tags.outputs.image-tags }} + build-config: ${{ steps.build-info.outputs.result }} steps: + #github forces lower case for the image name + - name: Get lowercase repo owner name + uses: actions/github-script@v7 + id: repo-owner + with: + result-encoding: string + script: | + return context.repo.owner.toLowerCase() + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Set nightly tag if commit was on main + id: add-nightly-tag + if: startsWith(github.ref, 'refs/heads/devel') + run: | + echo "nightly-tag=nightly" | tr -d "\n" >> $GITHUB_OUTPUT + + - name: Set latest tag if its a tag + id: add-latest-tag + if: startsWith(github.ref, 'refs/tags/') + run: | + echo "latest-tag=latest" | tr -d "\n" >> $GITHUB_OUTPUT + + - uses: actions/github-script@v7 + id: get-tag + if: startsWith(github.ref, 'refs/tags/') with: - ref: ${{ inputs.sha }} + result-encoding: string + script: | + return context.payload.ref.replace('refs/tags/', '') + + - name: concat tags to list + id: image-tags + run: | + TAGS=$(cat <<-END + [ + "${{ inputs.sha || github.sha }}", + "${{ steps.add-nightly-tag.outputs.nightly-tag }}", + "${{ steps.add-latest-tag.outputs.latest-tag }}", + "${{ steps.get-tag.outputs.result }}" + ] + END + ) + TAGS=$(echo $TAGS | jq -c 'map(select(length > 0))') + echo "image-tags=$TAGS" | tr -d "\n" >> $GITHUB_OUTPUT + + - name: Get build info + id: build-info + run: | + set -x + sudo snap install yq + + export REPO_NAME=$(basename $(pwd)) + echo "services:" > /tmp/docker-compose.yml + for i in $(find . -name docker-compose.yml); do + docker compose -f $i config | yq '.services | select(.[].build != null and .[].image != null)' | sed 's/^/ /' >> /tmp/docker-compose.yml + done + + cat /tmp/docker-compose.yml + + yq_pipe='.services' + yq_pipe=$yq_pipe'| to_entries[]' + yq_pipe=$yq_pipe'| select(.value.build != null and .value.image != null)' + yq_pipe=$yq_pipe'| .value.build.image=.value.image' + yq_pipe=$yq_pipe'| .value.build.service=.key' + yq_pipe=$yq_pipe'| .value.build' + yq_pipe=$yq_pipe'| .dockerfile=.context + "/" + .dockerfile' + yq_pipe=$yq_pipe'| [.]' + cat /tmp/docker-compose.yml | yq "$yq_pipe" + BUILD_INFO=$(cat /tmp/docker-compose.yml | yq "$yq_pipe" -o=json) + BUILD_INFO=$(echo $BUILD_INFO | jq -c -s add | sed "s|:local||g") + echo $BUILD_INFO + echo "result=$BUILD_INFO" | tr -d "\n" >> $GITHUB_OUTPUT + env: + REPO_OWNER: ${{ vars.DOCKER_HUB_USERNAME || steps.repo-owner.outputs.result }} + VERSION: local + + build-and-push: + runs-on: ubuntu-latest + name: "Build and push image ${{ matrix.build-config.service }}" + needs: + - build-info + strategy: + fail-fast: false + matrix: + build-config: ${{ fromJSON(needs.build-info.outputs.build-config) }} + env: + tags: ${{ needs.build-info.outputs.tags }} + repo-owner: ${{ needs.build-info.outputs.repo-owner }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - run: | + echo "inputs:" + cat <<-HEREDOC + ${{ toJSON(inputs) }} + HEREDOC + + echo "build config:" + cat <<-HEREDOC + ${{ toJSON(matrix.build-config) }} + HEREDOC + + echo "build tags:" + cat <<-HEREDOC + ${{ env.tags }} + HEREDOC + + echo "build repo owner:" + cat <<-HEREDOC + ${{ env.repo-owner }} + HEREDOC + + if [ ! echo "${{ matrix.build-config.image }}" | grep -Eq '^[a-zA-Z0-9._/-]+$' ]; then + echo "Error: Invalid Docker image name '${{ matrix.build-config.image }}'." + exit 1 + fi - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -32,76 +154,58 @@ jobs: - name: Login to DockerHub uses: docker/login-action@v3 with: - username: ${{ vars.DOCKER_HUB_USERNAME }} + username: ${{ vars.DOCKER_HUB_USERNAME || env.repo-owner }} password: ${{ secrets.DOCKER_HUB_PASSWORD }} - - name: Build and push frontend docker image - uses: docker/build-push-action@v6 + - uses: actions/github-script@v7 + id: expand-tags with: - push: true - file: .docker-hub/frontend/Dockerfile - tags: | - ${{ ((inputs.tag != '') && format('{0}/ecamp3-frontend:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }} - ${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-frontend:${{ inputs.sha }} - context: . - build-args: | - SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_ORG=${{ vars.SENTRY_ORG }} - SENTRY_FRONTEND_PROJECT=${{ vars.SENTRY_FRONTEND_PROJECT }} - SENTRY_RELEASE_NAME=${{ inputs.sha }} - cache-from: type=gha,scope=frontend - cache-to: type=gha,scope=frontend,mode=max - - - name: Build and push api docker image - uses: docker/build-push-action@v6 + script: | + return JSON.parse('${{ env.tags }}').map(tag => `${{ matrix.build-config.image }}:${ tag }`) + + - name: populate build args from secrets/vars + id: populate-build-args + uses: actions/github-script@v7 with: - push: true - file: api/Dockerfile - tags: | - ${{ ((inputs.tag != '') && format('{0}/ecamp3-api:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }} - ${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-api:${{ inputs.sha }} - context: './api' - target: frankenphp_prod - cache-from: type=gha,scope=api - cache-to: type=gha,scope=api,mode=max - - - name: Build and push print docker image + script: | + const buildArgValues = { + "SENTRY_AUTH_TOKEN" : "${{ secrets.SENTRY_AUTH_TOKEN }}", + "SENTRY_FRONTEND_PROJECT" : "${{ vars.SENTRY_FRONTEND_PROJECT }}", + "SENTRY_ORG" : "${{ vars.SENTRY_ORG }}", + "SENTRY_PRINT_PROJECT" : "${{ vars.SENTRY_PRINT_PROJECT }}", + "SENTRY_RELEASE_NAME" : "${{ inputs.sha }}", + } + const args = JSON.parse(`${{ toJSON(matrix.build-config.args) }}`) + let result = "" + for (const arg in args) { + if (buildArgValues[arg]) { + args[arg] = buildArgValues[arg] + } + } + return args + + - name: transform build args + id: transform-build-args + run: | + set -x + echo 'result<> $GITHUB_OUTPUT + echo '${{ steps.populate-build-args.outputs.result }}' | yq -p json >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + cat $GITHUB_OUTPUT + + - name: debug output + run: | + echo "result: ${{ steps.transform-build-args.outputs.result }}" + echo "result: ${{ toJSON(steps.transform-build-args.outputs) }}" + + - name: Build and push image uses: docker/build-push-action@v6 with: push: true - file: .docker-hub/print/Dockerfile - tags: | - ${{ ((inputs.tag != '') && format('{0}/ecamp3-print:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }} - ${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-print:${{ inputs.sha }} - context: . + file: ${{ matrix.build-config.dockerfile }} + tags: ${{ join(fromJSON(steps.expand-tags.outputs.result)) }} + context: ${{ matrix.build-config.context }} build-args: | - SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }} - SENTRY_ORG=${{ vars.SENTRY_ORG }} - SENTRY_PRINT_PROJECT=${{ vars.SENTRY_PRINT_PROJECT }} - SENTRY_RELEASE_NAME=${{ inputs.sha }} - cache-from: type=gha,scope=print - cache-to: type=gha,scope=print,mode=max - - - name: Build and push varnish docker image - uses: docker/build-push-action@v6 - with: - push: true - file: .docker-hub/varnish/Dockerfile - tags: | - ${{ ((inputs.tag != '') && format('{0}/ecamp3-varnish:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }} - ${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-varnish:${{ inputs.sha }} - context: . - cache-from: type=gha,scope=varnish - cache-to: type=gha,scope=varnish,mode=max - - - name: Build and push db-backup-restore docker image - uses: docker/build-push-action@v6 - with: - push: true - file: .helm/ecamp3/files/db-backup-restore-image/Dockerfile - tags: | - ${{ ((inputs.tag != '') && format('{0}/ecamp3-db-backup-restore:{1}', vars.DOCKER_HUB_USERNAME, inputs.tag) || '') }} - ${{ vars.DOCKER_HUB_USERNAME }}/ecamp3-db-backup-restore:${{ inputs.sha }} - context: . - cache-from: type=gha,scope=db-backup-restore - cache-to: type=gha,scope=db-backup-restore,mode=max + ${{ steps.transform-build-args.outputs.result }} + cache-from: type=gha,scope=${{ matrix.build-config.image }} + cache-to: type=gha,scope=${{ matrix.build-config.image }},mode=max diff --git a/.github/workflows/reusable-e2e-tests-build.yml b/.github/workflows/reusable-e2e-tests-build.yml index 5500b8a011..a7d34f98e2 100644 --- a/.github/workflows/reusable-e2e-tests-build.yml +++ b/.github/workflows/reusable-e2e-tests-build.yml @@ -25,7 +25,7 @@ jobs: load: true target: frankenphp_prod builder: ${{ steps.buildx.outputs.name }} - tags: ecamp/ecamp3-dev-api + tags: docker.io/ecamp/ecamp3-api:latest cache-from: type=gha,scope=api cache-to: type=gha,scope=api,mode=max outputs: type=docker,dest=/tmp/ecamp3-dev-api.tar diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 27143a7265..429c499a71 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,5 +1,6 @@ services: api: + image: '' build: target: frankenphp_dev volumes: diff --git a/docker-compose.yml b/docker-compose.yml index 6d793a3e0c..a0b218d3ae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,7 @@ services: - pdf api: - image: ecamp/ecamp3-dev-api + image: ${REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-api:${VERSION:-latest} build: context: ./api target: frankenphp_prod From 96c3a3497446e9da6f5dcbf628279556899ca91a Mon Sep 17 00:00:00 2001 From: BacLuc Date: Fri, 1 Aug 2025 11:35:27 +0200 Subject: [PATCH 005/202] CI: only build and push images if they changed --- .github/workflows/reusable-build-and-push.yml | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-build-and-push.yml b/.github/workflows/reusable-build-and-push.yml index 7caaf08b84..1de5c55e2c 100644 --- a/.github/workflows/reusable-build-and-push.yml +++ b/.github/workflows/reusable-build-and-push.yml @@ -121,6 +121,8 @@ jobs: repo-owner: ${{ needs.build-info.outputs.repo-owner }} steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + fetch-depth: 100 - run: | echo "inputs:" @@ -157,13 +159,52 @@ jobs: username: ${{ vars.DOCKER_HUB_USERNAME || env.repo-owner }} password: ${{ secrets.DOCKER_HUB_PASSWORD }} + - name: find latest commit for image tag + id: get-latest-commit + run: | + set -x + context=$( echo '${{ toJSON(matrix.build-config) }}' | jq -r '.context' | sed "s|$PWD|.|g") + echo "context: $context" + dockerfile=$( echo '${{ toJSON(matrix.build-config) }}' | jq -r '.dockerfile' | sed "s|$PWD|.|g") + echo "dockerfile: $dockerfile" + git log --stat -n 1 $context $dockerfile + latest_commit=$(git log --pretty=format:"%H" -n 1 $context $dockerfile) + echo "latest_commit: $latest_commit" + echo "result=$latest_commit" | tr -d "\n" >> $GITHUB_OUTPUT + + - name: check if image already exists + id: check-image + run: | + set +e + docker pull ${{ matrix.build-config.image }}:${{ steps.get-latest-commit.outputs.result }} + image_exists=$? + set -e + if ([ $image_exists -eq 0 ]); then + echo "image already exists" + echo "result=true" | tr -d "\n" >> $GITHUB_OUTPUT + else + echo "image does not exist" + echo "result=false" | tr -d "\n" >> $GITHUB_OUTPUT + fi + + - name: Add latest commit to image tag if image does not exist + id: add-latest-commit-to-tags-if-image-does-not-exist + uses: actions/github-script@v7 + with: + script: | + if (!${{ steps.check-image.outputs.result }}) { + return [...JSON.parse('${{ env.tags }}'), '${{ steps.get-latest-commit.outputs.result }}'] + } + return JSON.parse('${{ env.tags }}') + - uses: actions/github-script@v7 id: expand-tags with: script: | - return JSON.parse('${{ env.tags }}').map(tag => `${{ matrix.build-config.image }}:${ tag }`) + return JSON.parse('${{ steps.add-latest-commit-to-tags-if-image-does-not-exist.outputs.result }}').map(tag => `${{ matrix.build-config.image }}:${ tag }`) - name: populate build args from secrets/vars + if: steps.check-image.outputs.result == 'false' id: populate-build-args uses: actions/github-script@v7 with: @@ -185,6 +226,7 @@ jobs: return args - name: transform build args + if: steps.check-image.outputs.result == 'false' id: transform-build-args run: | set -x @@ -193,13 +235,15 @@ jobs: echo 'EOF' >> $GITHUB_OUTPUT cat $GITHUB_OUTPUT - - name: debug output + - name: debug transform build args output + if: steps.check-image.outputs.result == 'false' run: | echo "result: ${{ steps.transform-build-args.outputs.result }}" echo "result: ${{ toJSON(steps.transform-build-args.outputs) }}" - name: Build and push image uses: docker/build-push-action@v6 + if: steps.check-image.outputs.result == 'false' with: push: true file: ${{ matrix.build-config.dockerfile }} @@ -209,3 +253,11 @@ jobs: ${{ steps.transform-build-args.outputs.result }} cache-from: type=gha,scope=${{ matrix.build-config.image }} cache-to: type=gha,scope=${{ matrix.build-config.image }},mode=max + + - name: Retag and push images + if: steps.check-image.outputs.result == 'true' + run: | + for tag in $(echo '${{ env.tags }}' | jq -r '.[]'); do + docker tag ${{ matrix.build-config.image }}:${{ steps.get-latest-commit.outputs.result }} ${{ matrix.build-config.image }}:${tag} + docker push ${{ matrix.build-config.image }}:${tag} + done From 7333a3d3b83d0adc68ca0048dac755d5cf54e8f1 Mon Sep 17 00:00:00 2001 From: carlobeltrame Date: Wed, 20 Aug 2025 17:21:44 +0200 Subject: [PATCH 006/202] Display progress of printing pdf Fixes #5069 --- common/locales/de.json | 17 +- common/locales/en.json | 15 +- common/locales/fr.json | 15 +- common/locales/it.json | 15 +- frontend/eslint.config.mjs | 2 +- frontend/package-lock.json | 292 ++++++++++++++++++ frontend/package.json | 3 +- .../patches/@react-pdf+layout+4.4.0.patch | 17 + .../print/__tests__/repairPrintConfig.spec.js | 231 ++++++++++++++ .../config/DialogScheduleEntryFilter.vue | 16 +- .../print-client/DownloadClientPdfButton.vue | 35 ++- .../DownloadClientPdfListItem.vue | 19 +- .../print/print-client/PrintPreviewClient.vue | 30 +- .../print/print-client/generatePdf.js | 7 +- .../print/print-client/generatePdfMixin.js | 68 +++- .../print/print-client/renderPdf.js | 6 +- .../print/print-client/renderPdf.worker.js | 4 +- .../src/components/print/repairPrintConfig.js | 1 + frontend/src/locales/de.json | 13 +- pdf/eslint.config.mjs | 2 +- pdf/src/CampPrint.vue | 3 + pdf/src/PdfComponent.js | 12 + pdf/src/campPrint/summary/Story.vue | 2 +- pdf/src/campPrint/summary/SummaryPeriod.vue | 2 +- .../entry/SafetyConsiderations.vue | 5 +- .../campPrint/tableOfContents/entry/Story.vue | 2 +- pdf/src/index.js | 2 +- .../story_overview.spec.json.snap | 4 +- pdf/src/renderer/index.js | 6 +- pdf/src/renderer/reactPdfRenderer.js | 23 +- pdf/src/renderer/vueRenderer.js | 3 +- .../Toc/TocSafetyConsiderations.vue | 2 +- print/components/Toc/TocStory.vue | 2 +- print/components/summary/SummaryPeriod.vue | 2 +- print/eslint.config.mjs | 2 +- 35 files changed, 799 insertions(+), 81 deletions(-) create mode 100644 frontend/patches/@react-pdf+layout+4.4.0.patch diff --git a/common/locales/de.json b/common/locales/de.json index 0d5d4474de..54b884ec9b 100644 --- a/common/locales/de.json +++ b/common/locales/de.json @@ -262,8 +262,11 @@ "shortScheduleEntryDescription": "Tag {dayNumber} {startTime}" }, "print": { + "activity": { + "title": "Einzelne Aktivität" + }, "activityList": { - "title": "Aktivitätsliste" + "title": "Aktivitätenliste" }, "config": { "periods": "Lagerabschnitt(e)" @@ -283,13 +286,11 @@ "program": { "title": "Detailprogramm" }, - "summary": { - "safetyConsiderations": { - "title": "Sicherheitsüberlegungen" - }, - "storycontext": { - "title": "Geschichte" - } + "safetyConsiderations": { + "title": "Sicherheitsüberlegungen" + }, + "story": { + "title": "Geschichte" }, "toc": { "title": "Inhaltsverzeichnis" diff --git a/common/locales/en.json b/common/locales/en.json index 69bf6d9c0b..d59e6f5bbb 100644 --- a/common/locales/en.json +++ b/common/locales/en.json @@ -262,6 +262,9 @@ "shortScheduleEntryDescription": "day {dayNumber} {startTime}" }, "print": { + "activity": { + "title": "Single activity" + }, "activityList": { "title": "Activity list" }, @@ -283,13 +286,11 @@ "program": { "title": "Program" }, - "summary": { - "safetyConsiderations": { - "title": "Safety considerations" - }, - "storycontext": { - "title": "Story" - } + "safetyConsiderations": { + "title": "Safety considerations" + }, + "story": { + "title": "Story" }, "toc": { "title": "Table of contents" diff --git a/common/locales/fr.json b/common/locales/fr.json index 2b3f1c257f..9b53d4f44e 100644 --- a/common/locales/fr.json +++ b/common/locales/fr.json @@ -262,6 +262,9 @@ "shortScheduleEntryDescription": "jour{dayNumber} {startTime}" }, "print": { + "activity": { + "title": "Activité" + }, "activityList": { "title": "Liste d'activités" }, @@ -283,13 +286,11 @@ "program": { "title": "Programme" }, - "summary": { - "safetyConsiderations": { - "title": "Considérations sur la sécurité" - }, - "storycontext": { - "title": "Histoire" - } + "safetyConsiderations": { + "title": "Considérations sur la sécurité" + }, + "story": { + "title": "Histoire" }, "toc": { "title": "Table des matières" diff --git a/common/locales/it.json b/common/locales/it.json index a35244b580..0861ef1088 100644 --- a/common/locales/it.json +++ b/common/locales/it.json @@ -222,6 +222,9 @@ } }, "print": { + "activity": { + "title": "Attività" + }, "config": { "periods": "Sezione/i portante/i" }, @@ -234,13 +237,11 @@ "program": { "title": "Programma" }, - "summary": { - "safetyConsiderations": { - "title": "Considerazioni sulla sicurezza" - }, - "storycontext": { - "title": "Storia" - } + "safetyConsiderations": { + "title": "Considerazioni sulla sicurezza" + }, + "story": { + "title": "Storia" }, "toc": { "title": "Indice dei contenuti" diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index 594de35aa8..8c2987bc7b 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -79,7 +79,7 @@ export default [ 'error', { ignoreKeysRegex: - '^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|summary|toc|activityList))\\..+', + '^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|story|safetyConsiderations|toc|activityList))\\..+', translationKeyPropRegex: '[a-zA-Z0-9]-i18n-key$', }, ], diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c2941ffa7b..0d7ae451ad 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -98,6 +98,7 @@ "jest-serializer-vue-tjw": "3.20.0", "jsdom": "26.1.0", "lint-staged": "16.1.6", + "patch-package": "8.0.0", "prettier": "3.6.2", "sass": "1.78.0", "source-map": "0.7.4", @@ -4744,6 +4745,13 @@ "vue-template-compiler": "^2.x" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/@zxcvbn-ts/core": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@zxcvbn-ts/core/-/core-3.0.4.tgz", @@ -4999,6 +5007,16 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -5530,6 +5548,22 @@ "node": ">= 6" } }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -7092,6 +7126,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -7219,6 +7263,22 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -7948,6 +8008,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -8218,6 +8294,19 @@ "node": ">=0.10.0" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -8548,6 +8637,26 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -8568,6 +8677,29 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -8591,6 +8723,16 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -9080,6 +9222,16 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", @@ -9379,6 +9531,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -9403,6 +9572,16 @@ "integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==", "license": "MIT" }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -9529,6 +9708,50 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/patch-package": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", + "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10352,6 +10575,42 @@ "dev": true, "license": "MIT" }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "4.49.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz", @@ -10667,6 +10926,16 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -11296,6 +11565,19 @@ "dev": true, "license": "MIT" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -11513,6 +11795,16 @@ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", "license": "MIT" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unplugin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 4f3d55fe27..e66085727a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "test:unit": "vitest run --coverage", "test:unit:debug": "node --inspect-brk=0.0.0.0:9229 ./node_modules/.bin/vitest --no-cache --runInBand", "test:unit:watch": "vitest --watch", - "postinstall": "./scripts/install-twemoji.sh" + "postinstall": "./scripts/install-twemoji.sh && patch-package" }, "dependencies": { "@intlify/core": "11.1.11", @@ -111,6 +111,7 @@ "jest-serializer-vue-tjw": "3.20.0", "jsdom": "26.1.0", "lint-staged": "16.1.6", + "patch-package": "8.0.0", "prettier": "3.6.2", "sass": "1.78.0", "source-map": "0.7.4", diff --git a/frontend/patches/@react-pdf+layout+4.4.0.patch b/frontend/patches/@react-pdf+layout+4.4.0.patch new file mode 100644 index 0000000000..d835c38dd1 --- /dev/null +++ b/frontend/patches/@react-pdf+layout+4.4.0.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/@react-pdf/layout/lib/index.js b/node_modules/@react-pdf/layout/lib/index.js +index b318728..5e9efed 100644 +--- a/node_modules/@react-pdf/layout/lib/index.js ++++ b/node_modules/@react-pdf/layout/lib/index.js +@@ -2717,10 +2717,12 @@ const paginate = (page, pageNumber, fontStore, yoga) => { + return []; + if (page.props?.wrap === false) + return [page]; ++ dispatchEvent(new Event('layoutPage')); + let splittedPage = splitPage(page, pageNumber, fontStore, yoga); + const pages = [splittedPage[0]]; + let nextPage = splittedPage[1]; + while (nextPage !== null) { ++ dispatchEvent(new Event('layoutPage')); + splittedPage = splitPage(nextPage, pageNumber + pages.length, fontStore, yoga); + pages.push(splittedPage[0]); + nextPage = splittedPage[1]; diff --git a/frontend/src/components/print/__tests__/repairPrintConfig.spec.js b/frontend/src/components/print/__tests__/repairPrintConfig.spec.js index ecb6f043af..e6ef25191d 100644 --- a/frontend/src/components/print/__tests__/repairPrintConfig.spec.js +++ b/frontend/src/components/print/__tests__/repairPrintConfig.spec.js @@ -95,6 +95,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, } const defaultContents = [ { @@ -1157,6 +1158,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -1184,6 +1186,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -1249,6 +1252,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -1296,6 +1300,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -1342,6 +1347,7 @@ describe('repairConfig', () => { day: [], category: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -1389,6 +1395,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: ['/camp_collaborations/00000000'], + activityCount: 0, }, }, }, @@ -1435,6 +1442,7 @@ describe('repairConfig', () => { day: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -1482,6 +1490,7 @@ describe('repairConfig', () => { category: ['/categories/00000000'], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -1528,6 +1537,7 @@ describe('repairConfig', () => { category: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -1575,6 +1585,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -1621,6 +1632,7 @@ describe('repairConfig', () => { day: [], category: [], responsible: [], + activityCount: 0, }, }, }, @@ -1668,6 +1680,53 @@ describe('repairConfig', () => { category: [], progressLabel: ['/progress_labels/00000000'], responsible: [], + activityCount: 0, + }, + }, + }, + ], + documentName: 'test camp', + language: 'en-GB', + } + + // when + const result = repairConfig(config, ...args) + + // then + expect(result).toEqual({ + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'Program', + options: { + periods: ['/periods/1a2b3c4d'], + dayOverview: false, + filter: defaultFilter, + }, + }, + ], + documentName: 'test camp', + options: { pageNumbers: false }, + language: 'en-GB', + }) + }) + + test('adds dummy activityCount if missing', () => { + // given + const config = { + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'Program', + options: { + periods: ['/periods/1a2b3c4d'], + dayOverview: false, + filter: { + period: null, + day: [], + category: [], + progressLabel: [], + responsible: [], }, }, }, @@ -1911,6 +1970,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -1938,6 +1998,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -2003,6 +2064,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2050,6 +2112,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2096,6 +2159,7 @@ describe('repairConfig', () => { day: [], category: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -2143,6 +2207,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: ['/camp_collaborations/00000000'], + activityCount: 0, }, }, }, @@ -2189,6 +2254,7 @@ describe('repairConfig', () => { day: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -2236,6 +2302,7 @@ describe('repairConfig', () => { category: ['/categories/00000000'], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2282,6 +2349,7 @@ describe('repairConfig', () => { category: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -2329,6 +2397,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2375,6 +2444,7 @@ describe('repairConfig', () => { day: [], category: [], responsible: [], + activityCount: 0, }, }, }, @@ -2422,6 +2492,53 @@ describe('repairConfig', () => { category: [], progressLabel: ['/progress_labels/00000000'], responsible: [], + activityCount: 0, + }, + }, + }, + ], + documentName: 'test camp', + language: 'en-GB', + } + + // when + const result = repairConfig(config, ...args) + + // then + expect(result).toEqual({ + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'Story', + options: { + periods: ['/periods/1a2b3c4d'], + contentType: 'Storycontext', + filter: defaultFilter, + }, + }, + ], + documentName: 'test camp', + options: { pageNumbers: false }, + language: 'en-GB', + }) + }) + + test('adds dummy activityCount if missing', () => { + // given + const config = { + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'Story', + options: { + periods: ['/periods/1a2b3c4d'], + contentType: 'Storycontext', + filter: { + period: null, + day: [], + category: [], + progressLabel: [], + responsible: [], }, }, }, @@ -2673,6 +2790,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -2700,6 +2818,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -2765,6 +2884,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2812,6 +2932,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -2858,6 +2979,7 @@ describe('repairConfig', () => { day: [], category: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -2905,6 +3027,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: ['/camp_collaborations/00000000'], + activityCount: 0, }, }, }, @@ -2951,6 +3074,7 @@ describe('repairConfig', () => { day: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -2998,6 +3122,7 @@ describe('repairConfig', () => { category: ['/categories/00000000'], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3044,6 +3169,7 @@ describe('repairConfig', () => { category: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -3091,6 +3217,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3137,6 +3264,7 @@ describe('repairConfig', () => { day: [], category: [], responsible: [], + activityCount: 0, }, }, }, @@ -3184,6 +3312,53 @@ describe('repairConfig', () => { category: [], progressLabel: ['/progress_labels/00000000'], responsible: [], + activityCount: 0, + }, + }, + }, + ], + documentName: 'test camp', + language: 'en-GB', + } + + // when + const result = repairConfig(config, ...args) + + // then + expect(result).toEqual({ + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'SafetyConsiderations', + options: { + periods: ['/periods/1a2b3c4d'], + contentType: 'SafetyConsiderations', + filter: defaultFilter, + }, + }, + ], + documentName: 'test camp', + options: { pageNumbers: false }, + language: 'en-GB', + }) + }) + + test('adds dummy activityCount if missing', () => { + // given + const config = { + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'SafetyConsiderations', + options: { + periods: ['/periods/1a2b3c4d'], + contentType: 'SafetyConsiderations', + filter: { + period: null, + day: [], + category: [], + progressLabel: [], + responsible: [], }, }, }, @@ -3409,6 +3584,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -3435,6 +3611,7 @@ describe('repairConfig', () => { category: ['/categories/1a2b3c4d'], progressLabel: ['/progress_labels/1a2b3c4d'], responsible: ['/camp_collaborations/1a2b3c4d'], + activityCount: 0, }, }, }, @@ -3497,6 +3674,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3542,6 +3720,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3586,6 +3765,7 @@ describe('repairConfig', () => { day: [], category: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -3631,6 +3811,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: ['/camp_collaborations/00000000'], + activityCount: 0, }, }, }, @@ -3675,6 +3856,7 @@ describe('repairConfig', () => { day: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -3720,6 +3902,7 @@ describe('repairConfig', () => { category: ['/categories/00000000'], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3764,6 +3947,7 @@ describe('repairConfig', () => { category: [], responsible: [], progressLabel: [], + activityCount: 0, }, }, }, @@ -3809,6 +3993,7 @@ describe('repairConfig', () => { category: [], progressLabel: [], responsible: [], + activityCount: 0, }, }, }, @@ -3853,6 +4038,7 @@ describe('repairConfig', () => { day: [], category: [], responsible: [], + activityCount: 0, }, }, }, @@ -3898,6 +4084,51 @@ describe('repairConfig', () => { category: [], progressLabel: ['/progress_labels/00000000'], responsible: [], + activityCount: 0, + }, + }, + }, + ], + documentName: 'test camp', + language: 'en-GB', + } + + // when + const result = repairConfig(config, ...args) + + // then + expect(result).toEqual({ + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'ActivityList', + options: { + periods: ['/periods/1a2b3c4d'], + filter: defaultFilter, + }, + }, + ], + documentName: 'test camp', + options: { pageNumbers: false }, + language: 'en-GB', + }) + }) + + test('adds dummy activityCount if missing', () => { + // given + const config = { + camp: '/camps/1a2b3c4d', + contents: [ + { + type: 'ActivityList', + options: { + periods: ['/periods/1a2b3c4d'], + filter: { + period: null, + day: [], + category: [], + progressLabel: [], + responsible: [], }, }, }, diff --git a/frontend/src/components/print/config/DialogScheduleEntryFilter.vue b/frontend/src/components/print/config/DialogScheduleEntryFilter.vue index 590b7a00f7..93c96a0721 100644 --- a/frontend/src/components/print/config/DialogScheduleEntryFilter.vue +++ b/frontend/src/components/print/config/DialogScheduleEntryFilter.vue @@ -56,13 +56,16 @@ export default { } }, computed: { + filteredCount() { + return this.filterFn(this.localFilter).length + }, activatorLabel() { if (this.anyFilter) return this.$tc( 'components.print.config.dialogScheduleEntryFilter.filterActive', 1, { - filtered: this.filterFn(this.localFilter).length, + filtered: this.filteredCount, total: this.filterFn({}).length, } ) @@ -79,7 +82,7 @@ export default { 'components.print.config.dialogScheduleEntryFilter.resultCount', 1, { - filtered: this.filterFn(this.localFilter).length, + filtered: this.filteredCount, total: this.filterFn({}).length, } ) @@ -96,6 +99,15 @@ export default { ) }, }, + watch: { + filteredCount: { + handler(val) { + this.localFilter.activityCount = val + this.$emit('input', this.localFilter) + }, + immediate: true, + }, + }, methods: { emit(dialogOpen) { if (dialogOpen) return // only emit when closing dialog diff --git a/frontend/src/components/print/print-client/DownloadClientPdfButton.vue b/frontend/src/components/print/print-client/DownloadClientPdfButton.vue index f72b67c835..54310b6e19 100644 --- a/frontend/src/components/print/print-client/DownloadClientPdfButton.vue +++ b/frontend/src/components/print/print-client/DownloadClientPdfButton.vue @@ -1,11 +1,20 @@ @@ -17,3 +26,25 @@ export default { mixins: [generatePdfMixin], } + diff --git a/frontend/src/components/print/print-client/DownloadClientPdfListItem.vue b/frontend/src/components/print/print-client/DownloadClientPdfListItem.vue index d737eb67c1..8a0bee99fe 100644 --- a/frontend/src/components/print/print-client/DownloadClientPdfListItem.vue +++ b/frontend/src/components/print/print-client/DownloadClientPdfListItem.vue @@ -1,9 +1,20 @@ From 7743719e6094221f0743559b4636cb26ad2e9ca8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 03:57:12 +0000 Subject: [PATCH 028/202] Update dependency eslint-plugin-vue-scoped-css to v2.12.0 --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- print/package-lock.json | 8 ++++---- print/package.json | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7e9f47407a..bc4d647e59 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -92,7 +92,7 @@ "eslint-plugin-prettier": "5.5.4", "eslint-plugin-promise": "7.2.1", "eslint-plugin-vue": "10.4.0", - "eslint-plugin-vue-scoped-css": "2.11.0", + "eslint-plugin-vue-scoped-css": "2.12.0", "flush-promises": "1.0.2", "globals": "16.3.0", "jest-serializer-vue-tjw": "3.20.0", @@ -6754,9 +6754,9 @@ } }, "node_modules/eslint-plugin-vue-scoped-css": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.11.0.tgz", - "integrity": "sha512-rrJgLY8iroTIUMSyxhyhJzFcRxABbk3gFrOLkl41F9G1VBqNNpDShyf6PmDoBEWDk07/bJlnqYlvnQ3giUrRYQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.12.0.tgz", + "integrity": "sha512-gEbuvYetNbsPA0IsmERFkVC2/vOHCInfFekNSOsAxWI/7C/bc8PoLal+fRibWfnzWryY6iL8YoluMtrEqWRj1A==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 6df429ccc8..4818145823 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -105,7 +105,7 @@ "eslint-plugin-prettier": "5.5.4", "eslint-plugin-promise": "7.2.1", "eslint-plugin-vue": "10.4.0", - "eslint-plugin-vue-scoped-css": "2.11.0", + "eslint-plugin-vue-scoped-css": "2.12.0", "flush-promises": "1.0.2", "globals": "16.3.0", "jest-serializer-vue-tjw": "3.20.0", diff --git a/print/package-lock.json b/print/package-lock.json index 4ca02dc8bd..57a91d6c8c 100644 --- a/print/package-lock.json +++ b/print/package-lock.json @@ -41,7 +41,7 @@ "eslint-plugin-local-rules": "3.0.2", "eslint-plugin-prettier": "5.5.4", "eslint-plugin-vue": "10.4.0", - "eslint-plugin-vue-scoped-css": "2.11.0", + "eslint-plugin-vue-scoped-css": "2.12.0", "globals": "16.3.0", "nuxt": "4.1.0", "prettier": "3.6.2", @@ -9056,9 +9056,9 @@ } }, "node_modules/eslint-plugin-vue-scoped-css": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.11.0.tgz", - "integrity": "sha512-rrJgLY8iroTIUMSyxhyhJzFcRxABbk3gFrOLkl41F9G1VBqNNpDShyf6PmDoBEWDk07/bJlnqYlvnQ3giUrRYQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.12.0.tgz", + "integrity": "sha512-gEbuvYetNbsPA0IsmERFkVC2/vOHCInfFekNSOsAxWI/7C/bc8PoLal+fRibWfnzWryY6iL8YoluMtrEqWRj1A==", "dev": true, "license": "MIT", "dependencies": { diff --git a/print/package.json b/print/package.json index 9c708965ec..37c95d769a 100644 --- a/print/package.json +++ b/print/package.json @@ -51,7 +51,7 @@ "eslint-plugin-local-rules": "3.0.2", "eslint-plugin-prettier": "5.5.4", "eslint-plugin-vue": "10.4.0", - "eslint-plugin-vue-scoped-css": "2.11.0", + "eslint-plugin-vue-scoped-css": "2.12.0", "globals": "16.3.0", "nuxt": "4.1.0", "prettier": "3.6.2", From fea24670fba6762b12eef4474c4ec11a5f254f0b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 10:56:15 +0000 Subject: [PATCH 029/202] Update dependency @types/node to v22.18.1 --- .ops/aws-setup/package-lock.json | 8 ++++---- .ops/aws-setup/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ops/aws-setup/package-lock.json b/.ops/aws-setup/package-lock.json index 1d0abc5358..b1e1f01da0 100644 --- a/.ops/aws-setup/package-lock.json +++ b/.ops/aws-setup/package-lock.json @@ -14,7 +14,7 @@ "@babel/eslint-parser": "7.28.0", "@eslint/compat": "1.3.2", "@eslint/js": "9.34.0", - "@types/node": "22.18.0", + "@types/node": "22.18.1", "eslint": "9.34.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-n": "17.21.3", @@ -2865,9 +2865,9 @@ } }, "node_modules/@types/node": { - "version": "22.18.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", - "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", + "version": "22.18.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.1.tgz", + "integrity": "sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" diff --git a/.ops/aws-setup/package.json b/.ops/aws-setup/package.json index a7d5ac4e8c..86f9978002 100644 --- a/.ops/aws-setup/package.json +++ b/.ops/aws-setup/package.json @@ -18,7 +18,7 @@ "@babel/eslint-parser": "7.28.0", "@eslint/compat": "1.3.2", "@eslint/js": "9.34.0", - "@types/node": "22.18.0", + "@types/node": "22.18.1", "eslint": "9.34.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-n": "17.21.3", From a57edc40823e5ed4281001d1e92a8edb51891581 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 10:59:39 +0000 Subject: [PATCH 030/202] Lock file maintenance --- .ops/aws-setup/package-lock.json | 6 ++-- api/composer.lock | 12 ++++---- e2e/package-lock.json | 12 ++++---- frontend/package-lock.json | 6 ++-- pdf/package-lock.json | 6 ++-- print/package-lock.json | 52 ++++++++++++++++++++------------ translation/package-lock.json | 6 ++-- 7 files changed, 57 insertions(+), 43 deletions(-) diff --git a/.ops/aws-setup/package-lock.json b/.ops/aws-setup/package-lock.json index 1d0abc5358..7f260cea82 100644 --- a/.ops/aws-setup/package-lock.json +++ b/.ops/aws-setup/package-lock.json @@ -3508,9 +3508,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.213", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", - "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "version": "1.5.214", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", + "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", "dev": true, "license": "ISC", "peer": true diff --git a/api/composer.lock b/api/composer.lock index 392219dc34..69ef6a2d7f 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -5734,16 +5734,16 @@ }, { "name": "sentry/sentry", - "version": "4.15.1", + "version": "4.15.2", "source": { "type": "git", "url": "https://github.com/getsentry/sentry-php.git", - "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6" + "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/0d09baf3700869ec4b723c95eb466de56c3d74b6", - "reference": "0d09baf3700869ec4b723c95eb466de56c3d74b6", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/61a2d918e8424b6de4a2e265c15133a00c17db51", + "reference": "61a2d918e8424b6de4a2e265c15133a00c17db51", "shasum": "" }, "require": { @@ -5807,7 +5807,7 @@ ], "support": { "issues": "https://github.com/getsentry/sentry-php/issues", - "source": "https://github.com/getsentry/sentry-php/tree/4.15.1" + "source": "https://github.com/getsentry/sentry-php/tree/4.15.2" }, "funding": [ { @@ -5819,7 +5819,7 @@ "type": "custom" } ], - "time": "2025-08-28T15:45:14+00:00" + "time": "2025-09-03T07:23:48+00:00" }, { "name": "sentry/sentry-symfony", diff --git a/e2e/package-lock.json b/e2e/package-lock.json index 5dced2eb59..4ea79b6959 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -863,9 +863,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", "dev": true, "license": "MIT", "optional": true, @@ -1735,9 +1735,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.213", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", - "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "version": "1.5.214", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", + "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", "dev": true, "license": "ISC", "peer": true diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bc4d647e59..80ed27a174 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6285,9 +6285,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.213", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", - "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "version": "1.5.214", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", + "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", "dev": true, "license": "ISC" }, diff --git a/pdf/package-lock.json b/pdf/package-lock.json index 5a3ad8fb66..68b2ed2ac2 100644 --- a/pdf/package-lock.json +++ b/pdf/package-lock.json @@ -4563,9 +4563,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.213", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", - "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "version": "1.5.214", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", + "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", "dev": true, "license": "ISC" }, diff --git a/print/package-lock.json b/print/package-lock.json index 57a91d6c8c..b2e4c2f887 100644 --- a/print/package-lock.json +++ b/print/package-lock.json @@ -5240,9 +5240,9 @@ } }, "node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", "license": "MIT", "dependencies": { "undici-types": "~7.10.0" @@ -8481,9 +8481,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.213", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", - "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "version": "1.5.214", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz", + "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==", "dev": true, "license": "ISC" }, @@ -12317,6 +12317,20 @@ "node": ">= 12" } }, + "node_modules/nitropack/node_modules/unenv": { + "version": "2.0.0-rc.20", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.20.tgz", + "integrity": "sha512-8tn4tAl9vD5nWoggAAPz28vf0FY8+pQAayhU94qD+ZkIbVKCBAH/E1MWEEmhb9Whn5EgouYVfBJB20RsTLRDdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "exsolve": "^1.0.7", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "ufo": "^1.6.1" + } + }, "node_modules/nitropack/node_modules/unplugin-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz", @@ -12434,9 +12448,9 @@ } }, "node_modules/node-mock-http": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.2.tgz", - "integrity": "sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz", + "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==", "dev": true, "license": "MIT" }, @@ -15929,9 +15943,9 @@ } }, "node_modules/sirv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", "dependencies": { @@ -17203,9 +17217,9 @@ "license": "MIT" }, "node_modules/unenv": { - "version": "2.0.0-rc.20", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.20.tgz", - "integrity": "sha512-8tn4tAl9vD5nWoggAAPz28vf0FY8+pQAayhU94qD+ZkIbVKCBAH/E1MWEEmhb9Whn5EgouYVfBJB20RsTLRDdg==", + "version": "2.0.0-rc.21", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.21.tgz", + "integrity": "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==", "dev": true, "license": "MIT", "dependencies": { @@ -17402,9 +17416,9 @@ } }, "node_modules/unstorage": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.0.tgz", - "integrity": "sha512-l9Z7lBiwtNp8ZmcoZ/dmPkFXFdtEdZtTZafCSnEIj3YvtkXeGAtL2rN8MQFy/0cs4eOLpuRJMp9ivdug7TCvww==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.1.tgz", + "integrity": "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ==", "dev": true, "license": "MIT", "dependencies": { @@ -17430,7 +17444,7 @@ "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", - "@vercel/functions": "^2.2.12", + "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", diff --git a/translation/package-lock.json b/translation/package-lock.json index b9ee94b59f..23a7e9d3b3 100644 --- a/translation/package-lock.json +++ b/translation/package-lock.json @@ -10,9 +10,9 @@ } }, "node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", "license": "MIT", "dependencies": { "undici-types": "~7.10.0" From 1f00c0cc78a007a66dee0b6ee6a70f4ed49f8ce7 Mon Sep 17 00:00:00 2001 From: Pirmin Mattmann Date: Thu, 4 Sep 2025 22:06:15 +0200 Subject: [PATCH 031/202] no v-html, improve config --- .../components/form/base/EAutocomplete.vue | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/form/base/EAutocomplete.vue b/frontend/src/components/form/base/EAutocomplete.vue index 0aca9e9189..502cdd97f5 100644 --- a/frontend/src/components/form/base/EAutocomplete.vue +++ b/frontend/src/components/form/base/EAutocomplete.vue @@ -27,13 +27,10 @@ - - + + {{ part.text }} + {{ part.text }} + @@ -65,31 +62,38 @@ export default { }, data() { return { - fuzzy: new uFuzzy({ intraMode: 1 }), + fuzzy: new uFuzzy({ intraMode: 1 }), search: null, + searchInfos: new Map() } }, methods: { tokensFilter(item, queryText, itemText) { - const idxs = this.fuzzy.filter([itemText], queryText) + const [idxs, info, order] = this.fuzzy.search([itemText], queryText, true, 1e3) + this.searchInfos.set(item.value, info); return idxs && idxs.length > 0 }, - - renderHighlighted(text) { - if (!this.search) return text - - const info = this.fuzzy.info([0], [text], this.search) - return uFuzzy.highlight( - text, info.ranges[0], (s, m) => { - return m - ? '' + s + '' - : '' + s + '' + + renderHighlighted(item) { + if (this.search) { + if (this.searchInfos.has(item.value)) { + const info = this.searchInfos.get(item.value) + if (info) { + return uFuzzy.highlight( + item.text, + info.ranges[0], + (p, m) => ({ h:m, text:p }), + [], + (a, p) => { a.push(p) } + ) + } } - ) - - }, + } + return [{ h:false, text: item.text }] + } } } + diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 4c0834874f..0c93244a16 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -116,6 +116,20 @@ "campSettings": { "title": "Beschreibung" }, + "campSharingSettings": { + "copyCampLink": "Öffentlichen Link zum Lager kopieren", + "notShared": { + "description": "Link-Freigabe ist nicht aktiviert. Nur Personen im {team} können das Programm und die Daten in diesem Lager ansehen.", + "title": "Lager öffentlich freigeben" + }, + "publicCampUrl": "Sharing-Link zum Lager", + "shared": { + "description": "Alle Personen, die den Link zum Lager kennen, können das Programm, das Team, die Materiallisten und Verantwortlichkeiten und alles andere in diesem Lager ansehen. Nur Personen im {team} können Daten ändern.", + "title": "Lager ist öffentlich freigegeben" + }, + "team": "Team", + "title": "Lager teilen" + }, "createCampPeriods": { "add": "Weiteren Lagerabschnitt hinzufügen" }, @@ -786,14 +800,10 @@ "navigation": { "desktop": { "navTopbar": { - "admin": "Admin", "campIsLoading": "Lager wird geladen", - "checklist": "Checkliste", "material": "Material", - "print": "Drucken", "program": "Programm", - "story": "Geschichte", - "team": "Team" + "story": "Geschichte" } }, "mobile": { diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 26c2e8c2eb..0bcf3b5206 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -116,6 +116,20 @@ "campSettings": { "title": "Settings" }, + "campSharingSettings": { + "copyCampLink": "Copy public link to the camp", + "notShared": { + "description": "Link sharing is not active. Only people in the {team} can see the programme and data in this camp.", + "title": "Share camp publicly" + }, + "publicCampUrl": "Public camp link", + "shared": { + "description": "All people who know the link to the camp can see the programme, team, material lists, responsibilities and all other data in this camp. Only people in the {team} can change data.", + "title": "Camp is shared publicly" + }, + "team": "team", + "title": "Sharing settings" + }, "createCampPeriods": { "add": "Add a period" }, @@ -786,14 +800,11 @@ "navigation": { "desktop": { "navTopbar": { - "admin": "Admin", "campIsLoading": "Camp is loading", "checklist": "Checklist", "material": "Materials", - "print": "Print", "program": "Program", - "story": "Story", - "team": "Team" + "story": "Story" } }, "mobile": { diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index a51ca2d1e2..08825ae2a3 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -763,14 +763,11 @@ "navigation": { "desktop": { "navTopbar": { - "admin": "Admin", "campIsLoading": "Le camp est en cours de chargement", "checklist": "Check-list", "material": "Matériel", - "print": "Imprimer", "program": "Programme", - "story": "Histoire", - "team": "Team" + "story": "Histoire" } }, "mobile": { diff --git a/frontend/src/locales/it.json b/frontend/src/locales/it.json index 0abde0d6eb..f4df2894bf 100644 --- a/frontend/src/locales/it.json +++ b/frontend/src/locales/it.json @@ -650,13 +650,10 @@ "navigation": { "desktop": { "navTopbar": { - "admin": "Admin", "campIsLoading": "Il campo sta caricando", "material": "Material", - "print": "Stampa", "program": "Programm", - "story": "Storia", - "team": "Team" + "story": "Storia" } }, "mobile": { diff --git a/frontend/src/locales/rm.json b/frontend/src/locales/rm.json index 10f235f61b..7d76764969 100644 --- a/frontend/src/locales/rm.json +++ b/frontend/src/locales/rm.json @@ -588,13 +588,10 @@ "navigation": { "desktop": { "navTopbar": { - "admin": "Admin", "campIsLoading": "Il champ vegn chargià", "material": "Material", - "print": "Stampar", "program": "Program", - "story": "Istorgia", - "team": "Team" + "story": "Istorgia" } }, "mobile": { diff --git a/frontend/src/mixins/apiPropsMixin.js b/frontend/src/mixins/apiPropsMixin.js index 8f9db65bcc..8e056d1559 100644 --- a/frontend/src/mixins/apiPropsMixin.js +++ b/frontend/src/mixins/apiPropsMixin.js @@ -10,7 +10,7 @@ export const apiPropsMixin = { /* field path and URI for saving back to API */ path: { type: String, required: true }, - /* load devault value from apiObject (via ApiForm injection) */ + /* load default value from apiObject (via ApiForm injection) */ uri: { type: String, required: false, diff --git a/frontend/src/router.js b/frontend/src/router.js index 0c6afd0333..812c7a632d 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -813,7 +813,7 @@ function getContentLayout(route) { /** * @param camp - * @param subroute {'admin' | 'dashboard' | 'program' | 'material' | 'story' | 'home' | 'collaborators' | 'print' } + * @param subroute {'admin' | 'dashboard' | 'program' | 'material' | 'story' | 'home' | 'print' } * @param query */ export function campRoute(camp, subroute = 'dashboard', query = {}) { diff --git a/frontend/src/views/Camps.vue b/frontend/src/views/Camps.vue index e8ebfb5b60..ba9afb3d94 100644 --- a/frontend/src/views/Camps.vue +++ b/frontend/src/views/Camps.vue @@ -78,7 +78,6 @@ + + diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 0c93244a16..f6b476f947 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -58,6 +58,12 @@ }, "campMembers": { "title": "Mitglieder" + }, + "footerSharedCamp": { + "outsider": "Du arbeitest in diesem Lager nicht mit:", + "outsiderDescription": "Du kannst keine Daten ändern, aber das Programm anschauen und kopieren.", + "shared": "Lager ist öffentlich freigegeben:", + "sharedDescription": "Alle Personen, die über den Link verfügen, können sämtliche Daten im Lager einsehen." } }, "campAdmin": { diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 0bcf3b5206..034c971fa4 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -58,6 +58,12 @@ }, "campMembers": { "title": "Members" + }, + "footerSharedCamp": { + "outsider": "Not participating in this camp:", + "outsiderDescription": "You cannot change any data, but you may look at and copy the programme.", + "shared": "Camp is shared publicly:", + "sharedDescription": "Any person who has the link can see all data in this camp." } }, "campAdmin": { diff --git a/frontend/src/mixins/campRoleMixin.js b/frontend/src/mixins/campRoleMixin.js index a8b5232536..83fbe7f4e9 100644 --- a/frontend/src/mixins/campRoleMixin.js +++ b/frontend/src/mixins/campRoleMixin.js @@ -13,7 +13,7 @@ export const campRoleMixin = { return this.role === 'member' }, isOutsider() { - return !this.role + return this.camp && typeof this._campCollaborations === 'function' && !this.role }, role() { const currentUserLink = this.$store.getters.getLoggedInUser?._meta.self @@ -25,6 +25,7 @@ export const campRoleMixin = { return result?.role }, _campCollaborations() { + if (!this.camp) return [] if (typeof this.camp.campCollaborations !== 'function') { return [] } @@ -37,11 +38,4 @@ export const campRoleMixin = { return this.camp }, }, - mounted() { - if (typeof this.camp !== 'object' && typeof this.camp !== 'function') { - throw new Error( - 'User of the campRoleMixin must expose a camp as object proxy or function' - ) - } - }, } From e3e2e4c5f0419b9492093647678c4196ea5de2da Mon Sep 17 00:00:00 2001 From: carlobeltrame Date: Wed, 3 Sep 2025 14:43:19 +0200 Subject: [PATCH 193/202] Mark shared camps on camp list --- frontend/src/components/camp/CampListItem.vue | 14 ++++++++++++-- frontend/src/locales/de.json | 3 +++ frontend/src/locales/en.json | 3 +++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/camp/CampListItem.vue b/frontend/src/components/camp/CampListItem.vue index 5b28ccf631..66fcc2a1df 100644 --- a/frontend/src/components/camp/CampListItem.vue +++ b/frontend/src/components/camp/CampListItem.vue @@ -3,6 +3,16 @@ {{ camp.title }} + {{ $tc('components.camp.campListItem.public') }} + {{ date }} @@ -14,7 +24,7 @@ diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index f6b476f947..f1ce028047 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -56,6 +56,9 @@ "campInvitations": { "title": "Einladen" }, + "campListItem": { + "public": "Öffentlich" + }, "campMembers": { "title": "Mitglieder" }, diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 034c971fa4..9ac3e6f791 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -56,6 +56,9 @@ "campInvitations": { "title": "Invite" }, + "campListItem": { + "public": "public" + }, "campMembers": { "title": "Members" }, From 0fdf4dff61470a848b35b7e39e989c7c341fefeb Mon Sep 17 00:00:00 2001 From: carlobeltrame Date: Wed, 3 Sep 2025 15:29:55 +0200 Subject: [PATCH 194/202] Keep track of when and who last set the isShared flag --- .../schema/Version20250903125914.php | 33 +++++++++++++++ api/src/Entity/Camp.php | 20 +++++++++ api/src/State/CampUpdateProcessor.php | 41 +++++++++++++++++++ .../__tests__/dateHelperUTCFormatted.spec.js | 18 +++++++- .../helpers/__tests__/userDisplayName.spec.js | 2 + common/helpers/userDisplayName.js | 2 +- .../campAdmin/CampSharingSettings.vue | 15 +++++++ frontend/src/locales/de.json | 1 + frontend/src/locales/en.json | 1 + 9 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 api/migrations/schema/Version20250903125914.php create mode 100644 api/src/State/CampUpdateProcessor.php diff --git a/api/migrations/schema/Version20250903125914.php b/api/migrations/schema/Version20250903125914.php new file mode 100644 index 0000000000..d0122be5c2 --- /dev/null +++ b/api/migrations/schema/Version20250903125914.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE camp ADD sharedSince TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); + $this->addSql('ALTER TABLE camp ADD sharedById VARCHAR(16) DEFAULT NULL'); + $this->addSql('ALTER TABLE camp ADD CONSTRAINT FK_C19442304B2BC976 FOREIGN KEY (sharedById) REFERENCES "user" (id) NOT DEFERRABLE'); + $this->addSql('CREATE INDEX IDX_C19442304B2BC976 ON camp (sharedById)'); + } + + public function down(Schema $schema): void { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE camp DROP CONSTRAINT FK_C19442304B2BC976'); + $this->addSql('DROP INDEX IDX_C19442304B2BC976'); + $this->addSql('ALTER TABLE camp DROP sharedSince'); + $this->addSql('ALTER TABLE camp DROP sharedById'); + } +} diff --git a/api/src/Entity/Camp.php b/api/src/Entity/Camp.php index c13ee99fa4..95f42af351 100644 --- a/api/src/Entity/Camp.php +++ b/api/src/Entity/Camp.php @@ -16,6 +16,7 @@ use App\Serializer\Normalizer\RelatedCollectionLink; use App\State\CampCreateProcessor; use App\State\CampRemoveProcessor; +use App\State\CampUpdateProcessor; use App\Util\EntityMap; use App\Validator\AssertContainsAtLeastOneManager; use Doctrine\Common\Collections\ArrayCollection; @@ -38,6 +39,7 @@ normalizationContext: self::ITEM_NORMALIZATION_CONTEXT, ), new Patch( + processor: CampUpdateProcessor::class, security: 'is_granted("CAMP_MEMBER", object) or is_granted("CAMP_MANAGER", object)', denormalizationContext: ['groups' => ['write', 'update']], normalizationContext: self::ITEM_NORMALIZATION_CONTEXT, @@ -196,6 +198,24 @@ class Camp extends BaseEntity implements BelongsToCampInterface, CopyFromPrototy #[ORM\Column(type: 'boolean', nullable: false, options: ['default' => false])] public bool $isShared = false; + /** + * Date and time when the camp was last set to be shared publicly. + */ + #[ApiProperty(example: '2025-10-01T00:00:00+00:00', required: true, openapiContext: ['format' => 'date-time'])] + #[Groups(['read'])] + #[ORM\Column(type: 'datetime', nullable: true)] + public ?\DateTimeInterface $sharedSince = null; + + /** + * The person who last set the camp to be shared publicly. + */ + #[Assert\DisableAutoMapping] + #[ApiProperty(writable: false)] + #[Groups(['read'])] + #[ORM\ManyToOne(targetEntity: User::class)] + #[ORM\JoinColumn(nullable: true)] + public ?User $sharedBy = null; + /** * Whether this camp may serve as a template for creating other camps. */ diff --git a/api/src/State/CampUpdateProcessor.php b/api/src/State/CampUpdateProcessor.php new file mode 100644 index 0000000000..59fae193e9 --- /dev/null +++ b/api/src/State/CampUpdateProcessor.php @@ -0,0 +1,41 @@ + + */ +class CampUpdateProcessor extends AbstractPersistProcessor { + public function __construct( + ProcessorInterface $decorated, + private Security $security, + ) { + $sharingChangeListener = PropertyChangeListener::of( + extractProperty: fn (Camp $data) => $data->isShared, + beforeAction: fn (Camp $data) => $this->onBeforeStatusChange($data), + ); + + parent::__construct( + $decorated, + propertyChangeListeners: [ + $sharingChangeListener, + ] + ); + } + + public function onBeforeStatusChange(Camp $data): Camp { + if (true == $data->isShared) { + $data->sharedSince = new \DateTime(); + $data->sharedBy = $this->security->getUser(); + } + + return $data; + } +} diff --git a/common/helpers/__tests__/dateHelperUTCFormatted.spec.js b/common/helpers/__tests__/dateHelperUTCFormatted.spec.js index 7d645be2b3..ea937383fe 100644 --- a/common/helpers/__tests__/dateHelperUTCFormatted.spec.js +++ b/common/helpers/__tests__/dateHelperUTCFormatted.spec.js @@ -1,6 +1,10 @@ -import { describe, expect, it } from "vitest"; +import { describe, expect, it } from 'vitest' import { + dateLong, dateRange, + dateShort, + hourLong, + hourShort, rangeLongEnd, rangeShort, timeDurationShort, @@ -95,3 +99,15 @@ describe('dateRange', () => { ).toEqual('Tu 1.1. - We 01/02/2019') }) }) + +describe.each([ + ['dateShort', dateShort, 'Tu 1.1.'], + ['dateLong', dateLong, 'Tu 01/01/2019'], + ['hourShort', hourShort, '20:00'], + ['hourLong', hourLong, '20:00']])('%s', (name, func, expected) => { + it('should format dateTime', () => { + expect( + func('2019-01-01T20:00:00.000Z', tcMock) + ).toEqual(expected) + }) +}) diff --git a/common/helpers/__tests__/userDisplayName.spec.js b/common/helpers/__tests__/userDisplayName.spec.js index 72a7a429c4..6f7e736966 100644 --- a/common/helpers/__tests__/userDisplayName.spec.js +++ b/common/helpers/__tests__/userDisplayName.spec.js @@ -7,6 +7,8 @@ describe('userDisplayName', () => { [{ displayName: 'test' }, 'test'], [{ displayName: 'test', _meta: {} }, 'test'], [{ _meta: { loading: true } }, ''], + [null, ''], + [undefined, ''], ])('maps %p to %p', (input, expected) => { expect(userDisplayName(input)).toEqual(expected) }) diff --git a/common/helpers/userDisplayName.js b/common/helpers/userDisplayName.js index 7f44be53ce..ed064a0fd1 100644 --- a/common/helpers/userDisplayName.js +++ b/common/helpers/userDisplayName.js @@ -2,5 +2,5 @@ * Returns a display name for a user */ export default function (user) { - return user.displayName || '' + return user?.displayName || '' } diff --git a/frontend/src/components/campAdmin/CampSharingSettings.vue b/frontend/src/components/campAdmin/CampSharingSettings.vue index 6028037b52..b6abd35772 100644 --- a/frontend/src/components/campAdmin/CampSharingSettings.vue +++ b/frontend/src/components/campAdmin/CampSharingSettings.vue @@ -24,6 +24,12 @@ }} + {{ + $tc('components.campAdmin.campSharingSettings.sharedSince', 1, { + sharedSince, + sharedBy, + }) + }} @@ -61,6 +67,7 @@ import ContentGroup from '@/components/layout/ContentGroup.vue' import ApiForm from '../form/api/ApiForm.vue' import router, { adminRoute, campRoute } from '@/router.js' import { campRoleMixin } from '@/mixins/campRoleMixin.js' +import userDisplayName from '@/common/helpers/userDisplayName.js' export default { name: 'CampSharingSettings', @@ -83,6 +90,14 @@ export default { campUrl() { return window.location.origin + router.resolve(campRoute(this.camp)).href }, + sharedSince() { + return this.$date(this.camp.sharedSince).format( + this.$tc('global.datetime.dateTimeLong') + ) + }, + sharedBy() { + return userDisplayName(this.camp.sharedBy()) + }, }, methods: { async copyCampUrlToClipboard() { diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index f1ce028047..9d65610f37 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -136,6 +136,7 @@ "description": "Alle Personen, die den Link zum Lager kennen, können das Programm, das Team, die Materiallisten und Verantwortlichkeiten und alles andere in diesem Lager ansehen. Nur Personen im {team} können Daten ändern.", "title": "Lager ist öffentlich freigegeben" }, + "sharedSince": "Zuletzt freigegeben am {sharedSince} von {sharedBy}", "team": "Team", "title": "Lager teilen" }, diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 9ac3e6f791..21b576161f 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -136,6 +136,7 @@ "description": "All people who know the link to the camp can see the programme, team, material lists, responsibilities and all other data in this camp. Only people in the {team} can change data.", "title": "Camp is shared publicly" }, + "sharedSince": "Currently shared since {sharedSince} by {sharedBy}", "team": "team", "title": "Sharing settings" }, From 5c995cb92bdf3063921c0425b75f81a923ebffe1 Mon Sep 17 00:00:00 2001 From: carlobeltrame Date: Wed, 3 Sep 2025 17:35:28 +0200 Subject: [PATCH 195/202] Filter away shared camps in the API requests --- .../Filter/CampCollaboratorFilter.php | 76 +++++++++++++++++++ .../Doctrine/Filter/ContentNodeCampFilter.php | 3 - .../Filter/ContentNodePeriodFilter.php | 3 - api/src/Entity/Camp.php | 2 + api/src/Entity/Period.php | 2 + .../src/components/campAdmin/CampPeriods.vue | 2 +- .../PromptCollaboratorDeactivate.vue | 5 +- frontend/src/views/Camps.vue | 29 +++---- 8 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 api/src/Doctrine/Filter/CampCollaboratorFilter.php diff --git a/api/src/Doctrine/Filter/CampCollaboratorFilter.php b/api/src/Doctrine/Filter/CampCollaboratorFilter.php new file mode 100644 index 0000000000..1d6cf26462 --- /dev/null +++ b/api/src/Doctrine/Filter/CampCollaboratorFilter.php @@ -0,0 +1,76 @@ + [ + 'property' => self::QUERY_PARAM_NAME, + 'type' => Type::BUILTIN_TYPE_STRING, + 'required' => false, + ]]; + } + + protected function filterProperty( + string $property, + $value, + QueryBuilder $queryBuilder, + QueryNameGeneratorInterface $queryNameGenerator, + string $resourceClass, + ?Operation $operation = null, + array $context = [] + ): void { + if (!class_implements($resourceClass, BelongsToCampInterface::class)) { + throw new \Exception("CampCollaboratorFilter can only be applied to entities which implement BelongsToCampInterface (received: {$resourceClass})."); + } + + if (self::QUERY_PARAM_NAME !== $property) { + return; + } + + $campAlias = Camp::class === $resourceClass ? + $queryBuilder->getRootAliases()[0] : + $this->queryBuilderHelper->findOrAddInnerRootJoinAlias($queryBuilder, $queryNameGenerator, 'camp'); + + // load user from query parameter value + $collaborator = $this->iriConverter->getResourceFromIri($value); + + $campsQry = $queryBuilder->getEntityManager()->createQueryBuilder(); + $campsQry->select('identity(cc.camp)'); + $campsQry->from(CampCollaboration::class, 'cc'); + $campsQry->andWhere('cc.user = :collaborator'); + $campsQry->andWhere('cc.status = :status_established'); + + $queryBuilder->andWhere($queryBuilder->expr()->in($campAlias, $campsQry->getDQL())); + $queryBuilder->setParameter('collaborator', $collaborator); + $queryBuilder->setParameter('status_established', CampCollaboration::STATUS_ESTABLISHED); + } +} diff --git a/api/src/Doctrine/Filter/ContentNodeCampFilter.php b/api/src/Doctrine/Filter/ContentNodeCampFilter.php index a21e282019..7263a7bb7e 100644 --- a/api/src/Doctrine/Filter/ContentNodeCampFilter.php +++ b/api/src/Doctrine/Filter/ContentNodeCampFilter.php @@ -8,7 +8,6 @@ use ApiPlatform\Metadata\Operation; use App\Entity\Activity; use App\Entity\ContentNode; -use App\Repository\FiltersByCampCollaboration; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; use Psr\Log\LoggerInterface; @@ -16,8 +15,6 @@ use Symfony\Component\TypeInfo\Type; final class ContentNodeCampFilter extends AbstractFilter { - use FiltersByCampCollaboration; - public const CAMP_QUERY_NAME = 'camp'; public function __construct( diff --git a/api/src/Doctrine/Filter/ContentNodePeriodFilter.php b/api/src/Doctrine/Filter/ContentNodePeriodFilter.php index d9a21a6424..7f3ba0a474 100644 --- a/api/src/Doctrine/Filter/ContentNodePeriodFilter.php +++ b/api/src/Doctrine/Filter/ContentNodePeriodFilter.php @@ -8,7 +8,6 @@ use ApiPlatform\Metadata\Operation; use App\Entity\Activity; use App\Entity\ContentNode; -use App\Repository\FiltersByCampCollaboration; use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ManagerRegistry; @@ -17,8 +16,6 @@ use Symfony\Component\TypeInfo\Type; final class ContentNodePeriodFilter extends AbstractFilter { - use FiltersByCampCollaboration; - public const PERIOD_QUERY_NAME = 'period'; public function __construct( diff --git a/api/src/Entity/Camp.php b/api/src/Entity/Camp.php index 95f42af351..05549f6fda 100644 --- a/api/src/Entity/Camp.php +++ b/api/src/Entity/Camp.php @@ -11,6 +11,7 @@ use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Post; +use App\Doctrine\Filter\CampCollaboratorFilter; use App\InputFilter; use App\Repository\CampRepository; use App\Serializer\Normalizer\RelatedCollectionLink; @@ -64,6 +65,7 @@ normalizationContext: ['groups' => ['read']] )] #[ApiFilter(filterClass: SearchFilter::class, properties: ['isPrototype'])] +#[ApiFilter(filterClass: CampCollaboratorFilter::class)] #[ORM\Entity(repositoryClass: CampRepository::class)] #[ORM\Index(columns: ['isPrototype'])] #[ORM\Index(columns: ['isShared'])] diff --git a/api/src/Entity/Period.php b/api/src/Entity/Period.php index 4713f40436..3dc019376a 100644 --- a/api/src/Entity/Period.php +++ b/api/src/Entity/Period.php @@ -11,6 +11,7 @@ use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\Patch; use ApiPlatform\Metadata\Post; +use App\Doctrine\Filter\CampCollaboratorFilter; use App\InputFilter; use App\Repository\PeriodRepository; use App\Serializer\Normalizer\RelatedCollectionLink; @@ -62,6 +63,7 @@ order: ['start'] )] #[ApiFilter(filterClass: SearchFilter::class, properties: ['camp'])] +#[ApiFilter(filterClass: CampCollaboratorFilter::class)] #[ORM\Entity(repositoryClass: PeriodRepository::class)] class Period extends BaseEntity implements BelongsToCampInterface { public const ITEM_NORMALIZATION_CONTEXT = [ diff --git a/frontend/src/components/campAdmin/CampPeriods.vue b/frontend/src/components/campAdmin/CampPeriods.vue index e20e1d1f94..0fe563e7fb 100644 --- a/frontend/src/components/campAdmin/CampPeriods.vue +++ b/frontend/src/components/campAdmin/CampPeriods.vue @@ -4,7 +4,7 @@ Displays all periods of a single camp and allows to edit them & create new ones