diff --git a/.gitattributes b/.gitattributes index e03d96cd..9a0a204a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,9 @@ *.sh text eol=lf scripts/check-naming-and-style.sh text eol=lf .githooks/pre-commit text eol=lf + +# Batch files must be CRLF. cmd.exe parses a lone LF inconsistently around +# labels and goto, so an LF-only .cmd can run its happy path and then jump +# nowhere on the error path - which is the path that matters in a promote +# script. +*.cmd text eol=crlf diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index db0f47aa..848e3026 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -151,6 +151,56 @@ Tests are required for: - New plugin hooks (contract test) - Schema migrations (before/after data integrity) +## Branches: what belongs on main, and what does not + +`main` is the product every site runs and the publication mirror exports. +`` branches hold work that is not ready for other sites to see. There are +two: `wj` here, and `wilm` on the corporate GitHub, where the other site +develops the .NET endpoint agent. + +A site branch is not a fork. Both feed `main`, and the sooner they do it the +cheaper it is. A branch the dev box cannot see is still a branch: `wilm` is not +visible from here because this machine has no GitHub account, which is why +`fetch-wilm-branch.cmd` on the share exists to bring it back for review. + +**Most work is product.** ADR-015 gives site differences three homes on `main`: +a setting with a neutral default, seed data, or a site-namespaced directory +(`scripts/site_imports//`, which the style gate exempts). That is the only +site-specific home in the tree, so a site branch is about TIMING, not locality: +things that are not ready yet, rather than things that are permanently ours. + +Say which at commit time, with a trailer, because the decision does not survive +being deferred - months later it is a list of subject lines and a guess: + +```bash +git commit -m "Add the thing" -m "Scope: product" # main should have it +git commit -m "Add the thing" -m "Scope: site" # this site alone +``` + +Then: + +```bash +tools/wj-status.sh # what is unpromoted, and where it belongs +tools/promote-to-main.sh --dry-run # what files would reach main +tools/promote-to-main.sh [ ...] # oldest first; runs main's gates +tools/git-push.sh main # you push, deliberately +``` + +Windows equivalents are `tools\git-push.cmd` and `tools\promote-to-main.cmd`. + +Promotion cherry-picks NAMED commits rather than merging the branch. Merging +takes the site work along with the product work, which is how a site branch +quietly becomes the product. + +**The failure to watch for is not what you think.** Promoting something +site-specific by accident is caught by the ADR-015 gate on the way into `main`. +The real risk is product work sitting on a site branch until bringing it back is +a port rather than a merge - one such round trip cost a MySQL dialect fix, a +contract violation and a plugin install. + +So rebase the site branch on `main` often, and promote as you go rather than in +one batch at the end. + ## Code review checklist - [ ] No underscores in table or column names diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c069d5c7..ae76dfb7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,8 +12,8 @@ "@fullcalendar/core": "^6.1.20", "@fullcalendar/daygrid": "^6.1.20", "@fullcalendar/vue3": "^6.1.20", - "axios": "^1.6.0", - "dompurify": "^3.4.11", + "axios": "^1.20.0", + "dompurify": "^3.4.14", "jsbarcode": "^3.12.3", "jspdf": "^4.2.1", "leaflet": "^1.9.4", @@ -1456,14 +1456,37 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", - "license": "MIT", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" } }, "node_modules/balanced-match": { @@ -1701,7 +1724,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "dependencies": { "ms": "^2.1.3" }, @@ -1754,9 +1776,9 @@ "license": "MIT" }, "node_modules/dompurify": { - "version": "3.4.11", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", - "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.14.tgz", + "integrity": "sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -1972,16 +1994,15 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -2008,16 +2029,15 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -2154,10 +2174,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dependencies": { "function-bind": "^1.1.2" }, @@ -2469,20 +2488,18 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -2698,9 +2715,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "funding": [ { "type": "opencollective", @@ -2715,9 +2732,8 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2742,10 +2758,12 @@ "dev": true }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "engines": { + "node": ">=10" + } }, "node_modules/punycode": { "version": "2.3.1", diff --git a/frontend/package.json b/frontend/package.json index ef5c7cb2..c518a9a9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,8 +19,8 @@ "@fullcalendar/core": "^6.1.20", "@fullcalendar/daygrid": "^6.1.20", "@fullcalendar/vue3": "^6.1.20", - "axios": "^1.6.0", - "dompurify": "^3.4.11", + "axios": "^1.20.0", + "dompurify": "^3.4.14", "jsbarcode": "^3.12.3", "jspdf": "^4.2.1", "leaflet": "^1.9.4", diff --git a/frontend/src/components/AssetRelationships.vue b/frontend/src/components/AssetRelationships.vue index 5aaf4afc..279d2d90 100644 --- a/frontend/src/components/AssetRelationships.vue +++ b/frontend/src/components/AssetRelationships.vue @@ -1,16 +1,32 @@ +