chore: merge main into feat/rfc

This commit is contained in:
Robert Sparks 2023-10-12 15:11:02 -05:00
commit ab931f0510
No known key found for this signature in database
GPG key ID: 6E2A6A5775F91318
106 changed files with 1139 additions and 782 deletions

View file

@ -20,20 +20,20 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Push - name: Docker Build & Push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: docker/base.Dockerfile file: docker/base.Dockerfile

View file

@ -22,20 +22,20 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Push - name: Docker Build & Push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: dev/celery/Dockerfile file: dev/celery/Dockerfile

View file

@ -24,20 +24,20 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Push - name: Docker Build & Push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: dev/mq/Dockerfile file: dev/mq/Dockerfile

View file

@ -32,14 +32,14 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker Build & Push - name: Docker Build & Push
uses: docker/build-push-action@v4 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: dev/shared-assets-sync/Dockerfile file: dev/shared-assets-sync/Dockerfile

View file

@ -45,9 +45,9 @@ jobs:
echo "Running tests..." echo "Running tests..."
if [[ "x${{ github.event.inputs.ignoreLowerCoverage }}" == "xtrue" ]]; then if [[ "x${{ github.event.inputs.ignoreLowerCoverage }}" == "xtrue" ]]; then
echo "Lower coverage failures will be ignored." echo "Lower coverage failures will be ignored."
./ietf/manage.py test --validate-html-harder --settings=settings_test --ignore-lower-coverage ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test --ignore-lower-coverage
else else
./ietf/manage.py test --validate-html-harder --settings=settings_test ./ietf/manage.py test -v2 --validate-html-harder --settings=settings_test
fi fi
coverage xml coverage xml

236
.pnp.cjs generated
View file

@ -39,7 +39,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/icalendar", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/icalendar", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/interaction", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/interaction", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/list", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/list", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.9"],\
["@fullcalendar/timegrid", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/timegrid", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@parcel/optimizer-data-url", "npm:2.9.3"],\ ["@parcel/optimizer-data-url", "npm:2.9.3"],\
@ -48,25 +48,25 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@popperjs/core", "npm:2.11.8"],\ ["@popperjs/core", "npm:2.11.8"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.4"],\ ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.4"],\
["@twuni/emojify", "npm:1.0.2"],\ ["@twuni/emojify", "npm:1.0.2"],\
["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.3"],\ ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.4"],\
["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.1"],\ ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.2"],\
["bootstrap-icons", "npm:1.10.5"],\ ["bootstrap-icons", "npm:1.11.1"],\
["browser-fs-access", "npm:0.34.1"],\ ["browser-fs-access", "npm:0.35.0"],\
["browserlist", "npm:1.0.1"],\ ["browserlist", "npm:1.0.1"],\
["c8", "npm:8.0.1"],\ ["c8", "npm:8.0.1"],\
["caniuse-lite", "npm:1.0.30001519"],\ ["caniuse-lite", "npm:1.0.30001538"],\
["d3", "npm:7.8.5"],\ ["d3", "npm:7.8.5"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\ ["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\
["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\ ["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\
["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\ ["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\
["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.0.2"],\ ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.1.0"],\
["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\ ["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\ ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\
["file-saver", "npm:2.0.5"],\ ["file-saver", "npm:2.0.5"],\
["highcharts", "npm:11.1.0"],\ ["highcharts", "npm:11.1.0"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.3.0"],\ ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.4.0"],\
["ical.js", "npm:1.5.0"],\ ["ical.js", "npm:1.5.0"],\
["jquery", "npm:3.7.1"],\ ["jquery", "npm:3.7.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\
@ -74,7 +74,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\ ["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\ ["lodash", "npm:4.17.21"],\
["lodash-es", "npm:4.17.21"],\ ["lodash-es", "npm:4.17.21"],\
["luxon", "npm:3.4.0"],\ ["luxon", "npm:3.4.3"],\
["moment", "npm:2.29.4"],\ ["moment", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.43"],\ ["moment-timezone", "npm:0.5.43"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
@ -84,7 +84,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.6"],\ ["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.6"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\ ["pug", "npm:3.0.2"],\
["sass", "npm:1.66.1"],\ ["sass", "npm:1.67.0"],\
["seedrandom", "npm:3.0.5"],\ ["seedrandom", "npm:3.0.5"],\
["select2", "npm:4.1.0-rc.0"],\ ["select2", "npm:4.1.0-rc.0"],\
["select2-bootstrap-5-theme", "npm:1.3.0"],\ ["select2-bootstrap-5-theme", "npm:1.3.0"],\
@ -438,12 +438,12 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0", {\ ["virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0", {\
"packageLocation": "./.yarn/__virtual__/@eslint-community-eslint-utils-virtual-01223f6a8e/0/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip/node_modules/@eslint-community/eslint-utils/",\ "packageLocation": "./.yarn/__virtual__/@eslint-community-eslint-utils-virtual-3145c9a18a/0/cache/@eslint-community-eslint-utils-npm-4.4.0-d1791bd5a3-cdfe3ae42b.zip/node_modules/@eslint-community/eslint-utils/",\
"packageDependencies": [\ "packageDependencies": [\
["@eslint-community/eslint-utils", "virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0"],\ ["@eslint-community/eslint-utils", "virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-visitor-keys", "npm:3.3.0"]\ ["eslint-visitor-keys", "npm:3.3.0"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
@ -488,10 +488,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["@eslint/js", [\ ["@eslint/js", [\
["npm:8.48.0", {\ ["npm:8.49.0", {\
"packageLocation": "./.yarn/cache/@eslint-js-npm-8.48.0-cee42a7097-b2755f9c0e.zip/node_modules/@eslint/js/",\ "packageLocation": "./.yarn/cache/@eslint-js-npm-8.49.0-e8f6510b47-a6601807c8.zip/node_modules/@eslint/js/",\
"packageDependencies": [\ "packageDependencies": [\
["@eslint/js", "npm:8.48.0"]\ ["@eslint/js", "npm:8.49.0"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -651,21 +651,21 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["@fullcalendar/luxon3", [\ ["@fullcalendar/luxon3", [\
["npm:6.1.8", {\ ["npm:6.1.9", {\
"packageLocation": "./.yarn/cache/@fullcalendar-luxon3-npm-6.1.8-7f233a53e1-7e84200641.zip/node_modules/@fullcalendar/luxon3/",\ "packageLocation": "./.yarn/cache/@fullcalendar-luxon3-npm-6.1.9-d79fc8f961-25122126e2.zip/node_modules/@fullcalendar/luxon3/",\
"packageDependencies": [\ "packageDependencies": [\
["@fullcalendar/luxon3", "npm:6.1.8"]\ ["@fullcalendar/luxon3", "npm:6.1.9"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.9", {\
"packageLocation": "./.yarn/__virtual__/@fullcalendar-luxon3-virtual-3a7af6083c/0/cache/@fullcalendar-luxon3-npm-6.1.8-7f233a53e1-7e84200641.zip/node_modules/@fullcalendar/luxon3/",\ "packageLocation": "./.yarn/__virtual__/@fullcalendar-luxon3-virtual-2026214153/0/cache/@fullcalendar-luxon3-npm-6.1.9-d79fc8f961-25122126e2.zip/node_modules/@fullcalendar/luxon3/",\
"packageDependencies": [\ "packageDependencies": [\
["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.9"],\
["@fullcalendar/core", "npm:6.1.8"],\ ["@fullcalendar/core", "npm:6.1.8"],\
["@types/fullcalendar__core", null],\ ["@types/fullcalendar__core", null],\
["@types/luxon", null],\ ["@types/luxon", null],\
["luxon", "npm:3.4.0"]\ ["luxon", "npm:3.4.3"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
"@fullcalendar/core",\ "@fullcalendar/core",\
@ -745,10 +745,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["@humanwhocodes/config-array", [\ ["@humanwhocodes/config-array", [\
["npm:0.11.10", {\ ["npm:0.11.11", {\
"packageLocation": "./.yarn/cache/@humanwhocodes-config-array-npm-0.11.10-7b63df9e7f-1b1302e240.zip/node_modules/@humanwhocodes/config-array/",\ "packageLocation": "./.yarn/cache/@humanwhocodes-config-array-npm-0.11.11-e3582554ee-db84507375.zip/node_modules/@humanwhocodes/config-array/",\
"packageDependencies": [\ "packageDependencies": [\
["@humanwhocodes/config-array", "npm:0.11.10"],\ ["@humanwhocodes/config-array", "npm:0.11.11"],\
["@humanwhocodes/object-schema", "npm:1.2.1"],\ ["@humanwhocodes/object-schema", "npm:1.2.1"],\
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\ ["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
["minimatch", "npm:3.1.2"]\ ["minimatch", "npm:3.1.2"]\
@ -2389,10 +2389,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:0f17270113a645b9ccd471681c6953a9ecf2cc875b79eb96d26d7cb579b1f042c2aaab59d6799ee85bf4e9b312f464a118c211e37c33fa47b3e11095c49e32d7#npm:2.0.0", {\ ["virtual:baa02fb51e75f1f03e1ff0c1be104192da948332a9fd904d571b0b912d6ac16a98b4b63cb9465421728b6af4a1bb50f995b9b5018f7f90329de80b4a8ff40be4#npm:2.0.0", {\
"packageLocation": "./.yarn/__virtual__/@sidvind-better-ajv-errors-virtual-148105bc23/0/cache/@sidvind-better-ajv-errors-npm-2.0.0-3531bddef9-12b0d87855.zip/node_modules/@sidvind/better-ajv-errors/",\ "packageLocation": "./.yarn/__virtual__/@sidvind-better-ajv-errors-virtual-0c74a59d49/0/cache/@sidvind-better-ajv-errors-npm-2.0.0-3531bddef9-12b0d87855.zip/node_modules/@sidvind/better-ajv-errors/",\
"packageDependencies": [\ "packageDependencies": [\
["@sidvind/better-ajv-errors", "virtual:0f17270113a645b9ccd471681c6953a9ecf2cc875b79eb96d26d7cb579b1f042c2aaab59d6799ee85bf4e9b312f464a118c211e37c33fa47b3e11095c49e32d7#npm:2.0.0"],\ ["@sidvind/better-ajv-errors", "virtual:baa02fb51e75f1f03e1ff0c1be104192da948332a9fd904d571b0b912d6ac16a98b4b63cb9465421728b6af4a1bb50f995b9b5018f7f90329de80b4a8ff40be4#npm:2.0.0"],\
["@babel/code-frame", "npm:7.16.7"],\ ["@babel/code-frame", "npm:7.16.7"],\
["@types/ajv", null],\ ["@types/ajv", null],\
["ajv", "npm:8.11.0"],\ ["ajv", "npm:8.11.0"],\
@ -2638,17 +2638,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["@vitejs/plugin-vue", [\ ["@vitejs/plugin-vue", [\
["npm:4.3.3", {\ ["npm:4.3.4", {\
"packageLocation": "./.yarn/cache/@vitejs-plugin-vue-npm-4.3.3-ffc8f9f2ac-17f8d73708.zip/node_modules/@vitejs/plugin-vue/",\ "packageLocation": "./.yarn/cache/@vitejs-plugin-vue-npm-4.3.4-0e0b5c48a9-95bf6c85c0.zip/node_modules/@vitejs/plugin-vue/",\
"packageDependencies": [\ "packageDependencies": [\
["@vitejs/plugin-vue", "npm:4.3.3"]\ ["@vitejs/plugin-vue", "npm:4.3.4"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.3", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.4", {\
"packageLocation": "./.yarn/__virtual__/@vitejs-plugin-vue-virtual-c26a0d639a/0/cache/@vitejs-plugin-vue-npm-4.3.3-ffc8f9f2ac-17f8d73708.zip/node_modules/@vitejs/plugin-vue/",\ "packageLocation": "./.yarn/__virtual__/@vitejs-plugin-vue-virtual-d66cb5aa6a/0/cache/@vitejs-plugin-vue-npm-4.3.4-0e0b5c48a9-95bf6c85c0.zip/node_modules/@vitejs/plugin-vue/",\
"packageDependencies": [\ "packageDependencies": [\
["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.3"],\ ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.4"],\
["@types/vite", null],\ ["@types/vite", null],\
["@types/vue", null],\ ["@types/vue", null],\
["vite", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.4.9"],\ ["vite", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.4.9"],\
@ -3191,10 +3191,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["npm:5.3.1", {\ ["npm:5.3.2", {\
"packageLocation": "./.yarn/cache/bootstrap-npm-5.3.1-9ad45c2765-f8176376aa.zip/node_modules/bootstrap/",\ "packageLocation": "./.yarn/cache/bootstrap-npm-5.3.2-20b391b636-d5580b253d.zip/node_modules/bootstrap/",\
"packageDependencies": [\ "packageDependencies": [\
["bootstrap", "npm:5.3.1"]\ ["bootstrap", "npm:5.3.2"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
@ -3211,10 +3211,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.1", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.2", {\
"packageLocation": "./.yarn/__virtual__/bootstrap-virtual-94a6bfc3bc/0/cache/bootstrap-npm-5.3.1-9ad45c2765-f8176376aa.zip/node_modules/bootstrap/",\ "packageLocation": "./.yarn/__virtual__/bootstrap-virtual-b366fabcb3/0/cache/bootstrap-npm-5.3.2-20b391b636-d5580b253d.zip/node_modules/bootstrap/",\
"packageDependencies": [\ "packageDependencies": [\
["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.1"],\ ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.2"],\
["@popperjs/core", "npm:2.11.8"],\ ["@popperjs/core", "npm:2.11.8"],\
["@types/popperjs__core", null]\ ["@types/popperjs__core", null]\
],\ ],\
@ -3226,10 +3226,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["bootstrap-icons", [\ ["bootstrap-icons", [\
["npm:1.10.5", {\ ["npm:1.11.1", {\
"packageLocation": "./.yarn/cache/bootstrap-icons-npm-1.10.5-36f80ab074-8a0cfbd237.zip/node_modules/bootstrap-icons/",\ "packageLocation": "./.yarn/cache/bootstrap-icons-npm-1.11.1-9f55aea76a-d78ff24a83.zip/node_modules/bootstrap-icons/",\
"packageDependencies": [\ "packageDependencies": [\
["bootstrap-icons", "npm:1.10.5"]\ ["bootstrap-icons", "npm:1.11.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -3264,10 +3264,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["browser-fs-access", [\ ["browser-fs-access", [\
["npm:0.34.1", {\ ["npm:0.35.0", {\
"packageLocation": "./.yarn/cache/browser-fs-access-npm-0.34.1-7fcd7d9328-339865241c.zip/node_modules/browser-fs-access/",\ "packageLocation": "./.yarn/cache/browser-fs-access-npm-0.35.0-1577b5a7ba-5f3bf1ec17.zip/node_modules/browser-fs-access/",\
"packageDependencies": [\ "packageDependencies": [\
["browser-fs-access", "npm:0.34.1"]\ ["browser-fs-access", "npm:0.35.0"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -3382,10 +3382,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\ }],\
["npm:1.0.30001519", {\ ["npm:1.0.30001538", {\
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001519-1d6b5bc825-66085133ed.zip/node_modules/caniuse-lite/",\ "packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001538-68bfe8259b-94c5d55757.zip/node_modules/caniuse-lite/",\
"packageDependencies": [\ "packageDependencies": [\
["caniuse-lite", "npm:1.0.30001519"]\ ["caniuse-lite", "npm:1.0.30001538"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -4630,15 +4630,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["eslint", [\ ["eslint", [\
["npm:8.48.0", {\ ["npm:8.49.0", {\
"packageLocation": "./.yarn/cache/eslint-npm-8.48.0-0dd1c36629-f20b359a4f.zip/node_modules/eslint/",\ "packageLocation": "./.yarn/cache/eslint-npm-8.49.0-1b802e43a1-4dfe257e1e.zip/node_modules/eslint/",\
"packageDependencies": [\ "packageDependencies": [\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["@eslint-community/eslint-utils", "virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0"],\ ["@eslint-community/eslint-utils", "virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0"],\
["@eslint-community/regexpp", "npm:4.8.0"],\ ["@eslint-community/regexpp", "npm:4.8.0"],\
["@eslint/eslintrc", "npm:2.1.2"],\ ["@eslint/eslintrc", "npm:2.1.2"],\
["@eslint/js", "npm:8.48.0"],\ ["@eslint/js", "npm:8.49.0"],\
["@humanwhocodes/config-array", "npm:0.11.10"],\ ["@humanwhocodes/config-array", "npm:0.11.11"],\
["@humanwhocodes/module-importer", "npm:1.0.1"],\ ["@humanwhocodes/module-importer", "npm:1.0.1"],\
["@nodelib/fs.walk", "npm:1.2.8"],\ ["@nodelib/fs.walk", "npm:1.2.8"],\
["ajv", "npm:6.12.6"],\ ["ajv", "npm:6.12.6"],\
@ -4691,9 +4691,9 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/eslint-plugin-import", null],\ ["@types/eslint-plugin-import", null],\
["@types/eslint-plugin-n", null],\ ["@types/eslint-plugin-n", null],\
["@types/eslint-plugin-promise", null],\ ["@types/eslint-plugin-promise", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\ ["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\
["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.0.2"],\ ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.1.0"],\
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"]\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
@ -4740,7 +4740,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@types/typescript-eslint__parser", null],\ ["@types/typescript-eslint__parser", null],\
["@typescript-eslint/parser", null],\ ["@typescript-eslint/parser", null],\
["debug", "virtual:65bed195431eadffc59e2238eb20cc12d9a1665bc7458ce780a9320ff795091b03cb5c4c2094938315ddd967b5b02c0f1df67b3ed435c69b7457092b7cc06ed8#npm:3.2.7"],\ ["debug", "virtual:65bed195431eadffc59e2238eb20cc12d9a1665bc7458ce780a9320ff795091b03cb5c4c2094938315ddd967b5b02c0f1df67b3ed435c69b7457092b7cc06ed8#npm:3.2.7"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-import-resolver-node", "npm:0.3.7"],\ ["eslint-import-resolver-node", "npm:0.3.7"],\
["eslint-import-resolver-typescript", null],\ ["eslint-import-resolver-typescript", null],\
["eslint-import-resolver-webpack", null]\ ["eslint-import-resolver-webpack", null]\
@ -4773,7 +4773,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\ ["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["globals", "npm:13.21.0"]\ ["globals", "npm:13.21.0"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
@ -4796,7 +4796,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-es", "virtual:5cccaf00e87dfff96dbbb5eaf7a3055373358b8114d6a1adfb32f54ed6b40ba06068d3aa1fdd8062899a0cad040f68c17cc6b72bac2cdbe9700f3d6330d112f3#npm:3.0.1"],\ ["eslint-plugin-es", "virtual:5cccaf00e87dfff96dbbb5eaf7a3055373358b8114d6a1adfb32f54ed6b40ba06068d3aa1fdd8062899a0cad040f68c17cc6b72bac2cdbe9700f3d6330d112f3#npm:3.0.1"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-utils", "npm:2.1.0"],\ ["eslint-utils", "npm:2.1.0"],\
["regexpp", "npm:3.2.0"]\ ["regexpp", "npm:3.2.0"]\
],\ ],\
@ -4815,14 +4815,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:40d6f5c942a7ef0ae65f54bca96af56e7db0d52fb7321d7f8d1da62ed519e1f8c80fdfb1299383ab8a4a5e7182ecc1d4bae33d806b79817d62ed4ad091e77615#npm:7.1.0", {\ ["virtual:9781ae938be7131b5685249f65c2d227d13395e62123d3b23a131614e18b016978a73fff3ac8d9c3709f25fa05a3e0f4cdf798416576354013fb49b6cd33487d#npm:7.1.0", {\
"packageLocation": "./.yarn/__virtual__/eslint-plugin-es-x-virtual-3346953c48/0/cache/eslint-plugin-es-x-npm-7.1.0-35735e8bbc-a19924313c.zip/node_modules/eslint-plugin-es-x/",\ "packageLocation": "./.yarn/__virtual__/eslint-plugin-es-x-virtual-276ea3759f/0/cache/eslint-plugin-es-x-npm-7.1.0-35735e8bbc-a19924313c.zip/node_modules/eslint-plugin-es-x/",\
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-es-x", "virtual:40d6f5c942a7ef0ae65f54bca96af56e7db0d52fb7321d7f8d1da62ed519e1f8c80fdfb1299383ab8a4a5e7182ecc1d4bae33d806b79817d62ed4ad091e77615#npm:7.1.0"],\ ["eslint-plugin-es-x", "virtual:9781ae938be7131b5685249f65c2d227d13395e62123d3b23a131614e18b016978a73fff3ac8d9c3709f25fa05a3e0f4cdf798416576354013fb49b6cd33487d#npm:7.1.0"],\
["@eslint-community/eslint-utils", "virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0"],\ ["@eslint-community/eslint-utils", "virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0"],\
["@eslint-community/regexpp", "npm:4.5.1"],\ ["@eslint-community/regexpp", "npm:4.5.1"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"]\ ["eslint", "npm:8.49.0"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
"@types/eslint",\ "@types/eslint",\
@ -4852,7 +4852,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["array.prototype.flatmap", "npm:1.3.1"],\ ["array.prototype.flatmap", "npm:1.3.1"],\
["debug", "virtual:65bed195431eadffc59e2238eb20cc12d9a1665bc7458ce780a9320ff795091b03cb5c4c2094938315ddd967b5b02c0f1df67b3ed435c69b7457092b7cc06ed8#npm:3.2.7"],\ ["debug", "virtual:65bed195431eadffc59e2238eb20cc12d9a1665bc7458ce780a9320ff795091b03cb5c4c2094938315ddd967b5b02c0f1df67b3ed435c69b7457092b7cc06ed8#npm:3.2.7"],\
["doctrine", "npm:2.1.0"],\ ["doctrine", "npm:2.1.0"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-import-resolver-node", "npm:0.3.7"],\ ["eslint-import-resolver-node", "npm:0.3.7"],\
["eslint-module-utils", "virtual:ef2ff17f0affe5aeeb05f2e27f2212e975bb78d898c026b74cc62e05a17de36abb35a54f0831f2ff5fced26e6128bfc2c0cf332f7c60149823619b008d0ea480#npm:2.8.0"],\ ["eslint-module-utils", "virtual:ef2ff17f0affe5aeeb05f2e27f2212e975bb78d898c026b74cc62e05a17de36abb35a54f0831f2ff5fced26e6128bfc2c0cf332f7c60149823619b008d0ea480#npm:2.8.0"],\
["has", "npm:1.0.3"],\ ["has", "npm:1.0.3"],\
@ -4875,22 +4875,23 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["eslint-plugin-n", [\ ["eslint-plugin-n", [\
["npm:16.0.2", {\ ["npm:16.1.0", {\
"packageLocation": "./.yarn/cache/eslint-plugin-n-npm-16.0.2-6a256d6ab7-44cffe32a3.zip/node_modules/eslint-plugin-n/",\ "packageLocation": "./.yarn/cache/eslint-plugin-n-npm-16.1.0-d4092716f8-6b70bf8eec.zip/node_modules/eslint-plugin-n/",\
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-n", "npm:16.0.2"]\ ["eslint-plugin-n", "npm:16.1.0"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.0.2", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.1.0", {\
"packageLocation": "./.yarn/__virtual__/eslint-plugin-n-virtual-40d6f5c942/0/cache/eslint-plugin-n-npm-16.0.2-6a256d6ab7-44cffe32a3.zip/node_modules/eslint-plugin-n/",\ "packageLocation": "./.yarn/__virtual__/eslint-plugin-n-virtual-9781ae938b/0/cache/eslint-plugin-n-npm-16.1.0-d4092716f8-6b70bf8eec.zip/node_modules/eslint-plugin-n/",\
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.0.2"],\ ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.1.0"],\
["@eslint-community/eslint-utils", "virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0"],\ ["@eslint-community/eslint-utils", "virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["builtins", "npm:5.0.1"],\ ["builtins", "npm:5.0.1"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-plugin-es-x", "virtual:40d6f5c942a7ef0ae65f54bca96af56e7db0d52fb7321d7f8d1da62ed519e1f8c80fdfb1299383ab8a4a5e7182ecc1d4bae33d806b79817d62ed4ad091e77615#npm:7.1.0"],\ ["eslint-plugin-es-x", "virtual:9781ae938be7131b5685249f65c2d227d13395e62123d3b23a131614e18b016978a73fff3ac8d9c3709f25fa05a3e0f4cdf798416576354013fb49b6cd33487d#npm:7.1.0"],\
["get-tsconfig", "npm:4.7.2"],\
["ignore", "npm:5.2.4"],\ ["ignore", "npm:5.2.4"],\
["is-core-module", "npm:2.12.1"],\ ["is-core-module", "npm:2.12.1"],\
["minimatch", "npm:3.1.2"],\ ["minimatch", "npm:3.1.2"],\
@ -4917,7 +4918,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\ ["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-plugin-es", "virtual:5cccaf00e87dfff96dbbb5eaf7a3055373358b8114d6a1adfb32f54ed6b40ba06068d3aa1fdd8062899a0cad040f68c17cc6b72bac2cdbe9700f3d6330d112f3#npm:3.0.1"],\ ["eslint-plugin-es", "virtual:5cccaf00e87dfff96dbbb5eaf7a3055373358b8114d6a1adfb32f54ed6b40ba06068d3aa1fdd8062899a0cad040f68c17cc6b72bac2cdbe9700f3d6330d112f3#npm:3.0.1"],\
["eslint-utils", "npm:2.1.0"],\ ["eslint-utils", "npm:2.1.0"],\
["ignore", "npm:5.2.0"],\ ["ignore", "npm:5.2.0"],\
@ -4945,7 +4946,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"]\ ["eslint", "npm:8.49.0"]\
],\ ],\
"packagePeers": [\ "packagePeers": [\
"@types/eslint",\ "@types/eslint",\
@ -4966,9 +4967,9 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./.yarn/__virtual__/eslint-plugin-vue-virtual-e39e5d6bef/0/cache/eslint-plugin-vue-npm-9.17.0-c32115eab8-2ef53a0387.zip/node_modules/eslint-plugin-vue/",\ "packageLocation": "./.yarn/__virtual__/eslint-plugin-vue-virtual-e39e5d6bef/0/cache/eslint-plugin-vue-npm-9.17.0-c32115eab8-2ef53a0387.zip/node_modules/eslint-plugin-vue/",\
"packageDependencies": [\ "packageDependencies": [\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\ ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\
["@eslint-community/eslint-utils", "virtual:0dd1c3662912d25464a284caa5dbde8cc315ca056be4ded44d6f67e20c4895461cf49fc7bff27c35f254bdb0924477031e3e50d50a333908daaff17dcf43b01d#npm:4.4.0"],\ ["@eslint-community/eslint-utils", "virtual:1b802e43a1d6cfd4888588e031e9b9539c10922666207f02b37e1572beffa71b5952c5b88bdcc1e2ff0080ea3baa9b39a63225d9ea667488d5ab782bed5718c7#npm:4.4.0"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["natural-compare", "npm:1.4.0"],\ ["natural-compare", "npm:1.4.0"],\
["nth-check", "npm:2.1.1"],\ ["nth-check", "npm:2.1.1"],\
["postcss-selector-parser", "npm:6.0.13"],\ ["postcss-selector-parser", "npm:6.0.13"],\
@ -5420,6 +5421,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
]],\ ]],\
["get-tsconfig", [\
["npm:4.7.2", {\
"packageLocation": "./.yarn/cache/get-tsconfig-npm-4.7.2-8fbccd9fcf-1723589032.zip/node_modules/get-tsconfig/",\
"packageDependencies": [\
["get-tsconfig", "npm:4.7.2"],\
["resolve-pkg-maps", "npm:1.0.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["glob", [\ ["glob", [\
["npm:10.2.4", {\ ["npm:10.2.4", {\
"packageLocation": "./.yarn/cache/glob-npm-10.2.4-49f715fccc-29845faaa1.zip/node_modules/glob/",\ "packageLocation": "./.yarn/cache/glob-npm-10.2.4-49f715fccc-29845faaa1.zip/node_modules/glob/",\
@ -5651,20 +5662,20 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["html-validate", [\ ["html-validate", [\
["npm:8.3.0", {\ ["npm:8.4.0", {\
"packageLocation": "./.yarn/cache/html-validate-npm-8.3.0-71b7ba49e2-fd96a96fa7.zip/node_modules/html-validate/",\ "packageLocation": "./.yarn/cache/html-validate-npm-8.4.0-4d1a9d1021-5a063e3bb0.zip/node_modules/html-validate/",\
"packageDependencies": [\ "packageDependencies": [\
["html-validate", "npm:8.3.0"]\ ["html-validate", "npm:8.4.0"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.3.0", {\ ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.4.0", {\
"packageLocation": "./.yarn/__virtual__/html-validate-virtual-0f17270113/0/cache/html-validate-npm-8.3.0-71b7ba49e2-fd96a96fa7.zip/node_modules/html-validate/",\ "packageLocation": "./.yarn/__virtual__/html-validate-virtual-baa02fb51e/0/cache/html-validate-npm-8.4.0-4d1a9d1021-5a063e3bb0.zip/node_modules/html-validate/",\
"packageDependencies": [\ "packageDependencies": [\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.3.0"],\ ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.4.0"],\
["@babel/code-frame", "npm:7.16.7"],\ ["@babel/code-frame", "npm:7.16.7"],\
["@html-validate/stylish", "npm:4.1.0"],\ ["@html-validate/stylish", "npm:4.1.0"],\
["@sidvind/better-ajv-errors", "virtual:0f17270113a645b9ccd471681c6953a9ecf2cc875b79eb96d26d7cb579b1f042c2aaab59d6799ee85bf4e9b312f464a118c211e37c33fa47b3e11095c49e32d7#npm:2.0.0"],\ ["@sidvind/better-ajv-errors", "virtual:baa02fb51e75f1f03e1ff0c1be104192da948332a9fd904d571b0b912d6ac16a98b4b63cb9465421728b6af4a1bb50f995b9b5018f7f90329de80b4a8ff40be4#npm:2.0.0"],\
["@types/jest", null],\ ["@types/jest", null],\
["@types/jest-diff", null],\ ["@types/jest-diff", null],\
["@types/jest-snapshot", null],\ ["@types/jest-snapshot", null],\
@ -6701,10 +6712,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["luxon", [\ ["luxon", [\
["npm:3.4.0", {\ ["npm:3.4.3", {\
"packageLocation": "./.yarn/cache/luxon-npm-3.4.0-8e0b97226e-ca9b6d0e0a.zip/node_modules/luxon/",\ "packageLocation": "./.yarn/cache/luxon-npm-3.4.3-1b54517fa6-3eade81506.zip/node_modules/luxon/",\
"packageDependencies": [\ "packageDependencies": [\
["luxon", "npm:3.4.0"]\ ["luxon", "npm:3.4.3"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
@ -8043,6 +8054,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
]],\ ]],\
["resolve-pkg-maps", [\
["npm:1.0.0", {\
"packageLocation": "./.yarn/cache/resolve-pkg-maps-npm-1.0.0-135b70c854-1012afc566.zip/node_modules/resolve-pkg-maps/",\
"packageDependencies": [\
["resolve-pkg-maps", "npm:1.0.0"]\
],\
"linkType": "HARD"\
}]\
]],\
["retry", [\ ["retry", [\
["npm:0.12.0", {\ ["npm:0.12.0", {\
"packageLocation": "./.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip/node_modules/retry/",\ "packageLocation": "./.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip/node_modules/retry/",\
@ -8101,7 +8121,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@fullcalendar/icalendar", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/icalendar", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/interaction", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/interaction", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/list", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/list", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/luxon3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.9"],\
["@fullcalendar/timegrid", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/timegrid", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\ ["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.8"],\
["@parcel/optimizer-data-url", "npm:2.9.3"],\ ["@parcel/optimizer-data-url", "npm:2.9.3"],\
@ -8110,25 +8130,25 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@popperjs/core", "npm:2.11.8"],\ ["@popperjs/core", "npm:2.11.8"],\
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.4"],\ ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.4"],\
["@twuni/emojify", "npm:1.0.2"],\ ["@twuni/emojify", "npm:1.0.2"],\
["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.3"],\ ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.3.4"],\
["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.1"],\ ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.2"],\
["bootstrap-icons", "npm:1.10.5"],\ ["bootstrap-icons", "npm:1.11.1"],\
["browser-fs-access", "npm:0.34.1"],\ ["browser-fs-access", "npm:0.35.0"],\
["browserlist", "npm:1.0.1"],\ ["browserlist", "npm:1.0.1"],\
["c8", "npm:8.0.1"],\ ["c8", "npm:8.0.1"],\
["caniuse-lite", "npm:1.0.30001519"],\ ["caniuse-lite", "npm:1.0.30001538"],\
["d3", "npm:7.8.5"],\ ["d3", "npm:7.8.5"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\ ["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\
["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\ ["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.14.0"],\
["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\ ["eslint-plugin-import", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.28.1"],\
["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.0.2"],\ ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.1.0"],\
["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\ ["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\ ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.17.0"],\
["file-saver", "npm:2.0.5"],\ ["file-saver", "npm:2.0.5"],\
["highcharts", "npm:11.1.0"],\ ["highcharts", "npm:11.1.0"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.3.0"],\ ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.4.0"],\
["ical.js", "npm:1.5.0"],\ ["ical.js", "npm:1.5.0"],\
["jquery", "npm:3.7.1"],\ ["jquery", "npm:3.7.1"],\
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\
@ -8136,7 +8156,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["list.js", "npm:2.3.1"],\ ["list.js", "npm:2.3.1"],\
["lodash", "npm:4.17.21"],\ ["lodash", "npm:4.17.21"],\
["lodash-es", "npm:4.17.21"],\ ["lodash-es", "npm:4.17.21"],\
["luxon", "npm:3.4.0"],\ ["luxon", "npm:3.4.3"],\
["moment", "npm:2.29.4"],\ ["moment", "npm:2.29.4"],\
["moment-timezone", "npm:0.5.43"],\ ["moment-timezone", "npm:0.5.43"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
@ -8146,7 +8166,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.6"],\ ["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.6"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\ ["pug", "npm:3.0.2"],\
["sass", "npm:1.66.1"],\ ["sass", "npm:1.67.0"],\
["seedrandom", "npm:3.0.5"],\ ["seedrandom", "npm:3.0.5"],\
["select2", "npm:4.1.0-rc.0"],\ ["select2", "npm:4.1.0-rc.0"],\
["select2-bootstrap-5-theme", "npm:1.3.0"],\ ["select2-bootstrap-5-theme", "npm:1.3.0"],\
@ -8243,10 +8263,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}],\ }],\
["npm:1.66.1", {\ ["npm:1.67.0", {\
"packageLocation": "./.yarn/cache/sass-npm-1.66.1-563acb4a8f-74fc11d0fc.zip/node_modules/sass/",\ "packageLocation": "./.yarn/cache/sass-npm-1.67.0-d0fceb9574-9e7566e8b7.zip/node_modules/sass/",\
"packageDependencies": [\ "packageDependencies": [\
["sass", "npm:1.66.1"],\ ["sass", "npm:1.67.0"],\
["chokidar", "npm:3.5.3"],\ ["chokidar", "npm:3.5.3"],\
["immutable", "npm:4.0.0"],\ ["immutable", "npm:4.0.0"],\
["source-map-js", "npm:1.0.2"]\ ["source-map-js", "npm:1.0.2"]\
@ -9029,7 +9049,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["lightningcss", null],\ ["lightningcss", null],\
["postcss", "npm:8.4.27"],\ ["postcss", "npm:8.4.27"],\
["rollup", "npm:3.28.0"],\ ["rollup", "npm:3.28.0"],\
["sass", "npm:1.66.1"],\ ["sass", "npm:1.67.0"],\
["stylus", null],\ ["stylus", null],\
["sugarss", null],\ ["sugarss", null],\
["terser", null]\ ["terser", null]\
@ -9162,7 +9182,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["vue-eslint-parser", "virtual:e39e5d6bef7a93bd3b21c5c9ba6ef825c92fc73c8d9c9e01699e1dc11e40fd3bc150ba16509e2cf59495cb098c32b2e4a85c0c21802fddeffc3208b01f4f5a16#npm:9.3.1"],\ ["vue-eslint-parser", "virtual:e39e5d6bef7a93bd3b21c5c9ba6ef825c92fc73c8d9c9e01699e1dc11e40fd3bc150ba16509e2cf59495cb098c32b2e4a85c0c21802fddeffc3208b01f4f5a16#npm:9.3.1"],\
["@types/eslint", null],\ ["@types/eslint", null],\
["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\ ["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\
["eslint", "npm:8.48.0"],\ ["eslint", "npm:8.49.0"],\
["eslint-scope", "npm:7.1.1"],\ ["eslint-scope", "npm:7.1.1"],\
["eslint-visitor-keys", "npm:3.3.0"],\ ["eslint-visitor-keys", "npm:3.3.0"],\
["espree", "npm:9.3.2"],\ ["espree", "npm:9.3.2"],\

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -9,15 +9,15 @@
"version": "1.0.0", "version": "1.0.0",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@actions/core": "1.10.0", "@actions/core": "1.10.1",
"@actions/github": "5.1.1", "@actions/github": "5.1.1",
"chart.js": "3.5.1", "chart.js": "3.5.1",
"chartjs-node-canvas": "4.1.6", "chartjs-node-canvas": "4.1.6",
"lodash": "4.17.21", "lodash": "4.17.21",
"luxon": "3.4.0" "luxon": "3.4.3"
}, },
"devDependencies": { "devDependencies": {
"eslint": "8.48.0", "eslint": "8.49.0",
"eslint-config-standard": "17.1.0", "eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.28.1",
"eslint-plugin-node": "11.1.0", "eslint-plugin-node": "11.1.0",
@ -35,9 +35,9 @@
} }
}, },
"node_modules/@actions/core": { "node_modules/@actions/core": {
"version": "1.10.0", "version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2" "uuid": "^8.3.2"
@ -120,18 +120,18 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "8.48.0", "version": "8.49.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz",
"integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.10", "version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@humanwhocodes/object-schema": "^1.2.1", "@humanwhocodes/object-schema": "^1.2.1",
@ -1765,16 +1765,16 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "8.48.0", "version": "8.49.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz",
"integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2", "@eslint/eslintrc": "^2.1.2",
"@eslint/js": "8.48.0", "@eslint/js": "8.49.0",
"@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.12.4", "ajv": "^6.12.4",
@ -3550,9 +3550,9 @@
} }
}, },
"node_modules/luxon": { "node_modules/luxon": {
"version": "3.4.0", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-7eDo4Pt7aGhoCheGFIuq4Xa2fJm4ZpmldpGhjTYBNUYNCN6TIEP6v7chwwwt3KRp7YR+rghbfvjyo3V5y9hgBw==", "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
@ -6080,9 +6080,9 @@
"dev": true "dev": true
}, },
"@actions/core": { "@actions/core": {
"version": "1.10.0", "version": "1.10.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.1.tgz",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "integrity": "sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==",
"requires": { "requires": {
"@actions/http-client": "^2.0.1", "@actions/http-client": "^2.0.1",
"uuid": "^8.3.2" "uuid": "^8.3.2"
@ -6147,15 +6147,15 @@
} }
}, },
"@eslint/js": { "@eslint/js": {
"version": "8.48.0", "version": "8.49.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz",
"integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==",
"dev": true "dev": true
}, },
"@humanwhocodes/config-array": { "@humanwhocodes/config-array": {
"version": "0.11.10", "version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@humanwhocodes/object-schema": "^1.2.1", "@humanwhocodes/object-schema": "^1.2.1",
@ -7373,16 +7373,16 @@
"dev": true "dev": true
}, },
"eslint": { "eslint": {
"version": "8.48.0", "version": "8.49.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz",
"integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.2", "@eslint/eslintrc": "^2.1.2",
"@eslint/js": "8.48.0", "@eslint/js": "8.49.0",
"@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/config-array": "^0.11.11",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.12.4", "ajv": "^6.12.4",
@ -8658,9 +8658,9 @@
} }
}, },
"luxon": { "luxon": {
"version": "3.4.0", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-7eDo4Pt7aGhoCheGFIuq4Xa2fJm4ZpmldpGhjTYBNUYNCN6TIEP6v7chwwwt3KRp7YR+rghbfvjyo3V5y9hgBw==" "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg=="
}, },
"make-dir": { "make-dir": {
"version": "3.1.0", "version": "3.1.0",

View file

@ -6,15 +6,15 @@
"author": "IETF Trust", "author": "IETF Trust",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@actions/core": "1.10.0", "@actions/core": "1.10.1",
"@actions/github": "5.1.1", "@actions/github": "5.1.1",
"chart.js": "3.5.1", "chart.js": "3.5.1",
"chartjs-node-canvas": "4.1.6", "chartjs-node-canvas": "4.1.6",
"lodash": "4.17.21", "lodash": "4.17.21",
"luxon": "3.4.0" "luxon": "3.4.3"
}, },
"devDependencies": { "devDependencies": {
"eslint": "8.48.0", "eslint": "8.49.0",
"eslint-config-standard": "17.1.0", "eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.28.1", "eslint-plugin-import": "2.28.1",
"eslint-plugin-node": "11.1.0", "eslint-plugin-node": "11.1.0",

View file

@ -8,7 +8,7 @@ const octokit = new Octokit({
const oldestDate = DateTime.utc().minus({ days: 7 }) const oldestDate = DateTime.utc().minus({ days: 7 })
for (const pkgName of ['datatracker-db', 'datatracker-db-pg']) { for (const pkgName of ['datatracker-db']) {
let hasMore = true let hasMore = true
let currentPage = 1 let currentPage = 1

View file

@ -8,10 +8,10 @@
"dependencies": { "dependencies": {
"dockerode": "^3.3.5", "dockerode": "^3.3.5",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"nanoid": "4.0.2", "nanoid": "5.0.1",
"nanoid-dictionary": "5.0.0-beta.1", "nanoid-dictionary": "5.0.0-beta.1",
"slugify": "1.6.6", "slugify": "1.6.6",
"tar": "^6.1.15", "tar": "^6.2.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {
@ -337,9 +337,9 @@
"optional": true "optional": true
}, },
"node_modules/nanoid": { "node_modules/nanoid": {
"version": "4.0.2", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.1.tgz",
"integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", "integrity": "sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ==",
"funding": [ "funding": [
{ {
"type": "github", "type": "github",
@ -350,7 +350,7 @@
"nanoid": "bin/nanoid.js" "nanoid": "bin/nanoid.js"
}, },
"engines": { "engines": {
"node": "^14 || ^16 || >=18" "node": "^18 || >=20"
} }
}, },
"node_modules/nanoid-dictionary": { "node_modules/nanoid-dictionary": {
@ -483,9 +483,9 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "6.1.15", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"dependencies": { "dependencies": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",
@ -878,9 +878,9 @@
"optional": true "optional": true
}, },
"nanoid": { "nanoid": {
"version": "4.0.2", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.1.tgz",
"integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==" "integrity": "sha512-vWeVtV5Cw68aML/QaZvqN/3QQXc6fBfIieAlu05m7FZW2Dgb+3f0xc0TTxuJW+7u30t7iSDTV/j3kVI0oJqIfQ=="
}, },
"nanoid-dictionary": { "nanoid-dictionary": {
"version": "5.0.0-beta.1", "version": "5.0.0-beta.1",
@ -977,9 +977,9 @@
} }
}, },
"tar": { "tar": {
"version": "6.1.15", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"requires": { "requires": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",

View file

@ -4,10 +4,10 @@
"dependencies": { "dependencies": {
"dockerode": "^3.3.5", "dockerode": "^3.3.5",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"nanoid": "4.0.2", "nanoid": "5.0.1",
"nanoid-dictionary": "5.0.0-beta.1", "nanoid-dictionary": "5.0.0-beta.1",
"slugify": "1.6.6", "slugify": "1.6.6",
"tar": "^6.1.15", "tar": "^6.2.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {

View file

@ -15,9 +15,9 @@
"keypress": "^0.2.1", "keypress": "^0.2.1",
"listr2": "^6.6.1", "listr2": "^6.6.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.4.0", "luxon": "^3.4.3",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"tar": "^6.1.15", "tar": "^6.2.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {
@ -859,9 +859,9 @@
} }
}, },
"node_modules/luxon": { "node_modules/luxon": {
"version": "3.4.0", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-7eDo4Pt7aGhoCheGFIuq4Xa2fJm4ZpmldpGhjTYBNUYNCN6TIEP6v7chwwwt3KRp7YR+rghbfvjyo3V5y9hgBw==", "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg==",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
@ -1193,9 +1193,9 @@
} }
}, },
"node_modules/tar": { "node_modules/tar": {
"version": "6.1.15", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"dependencies": { "dependencies": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",
@ -1950,9 +1950,9 @@
"integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==" "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ=="
}, },
"luxon": { "luxon": {
"version": "3.4.0", "version": "3.4.3",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.3.tgz",
"integrity": "sha512-7eDo4Pt7aGhoCheGFIuq4Xa2fJm4ZpmldpGhjTYBNUYNCN6TIEP6v7chwwwt3KRp7YR+rghbfvjyo3V5y9hgBw==" "integrity": "sha512-tFWBiv3h7z+T/tDaoxA8rqTxy1CHV6gHS//QdaH4pulbq/JuBSGgQspQQqcgnwdAx6pNI7cmvz5Sv/addzHmUg=="
}, },
"mimic-fn": { "mimic-fn": {
"version": "2.1.0", "version": "2.1.0",
@ -2173,9 +2173,9 @@
} }
}, },
"tar": { "tar": {
"version": "6.1.15", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"requires": { "requires": {
"chownr": "^2.0.0", "chownr": "^2.0.0",
"fs-minipass": "^2.0.0", "fs-minipass": "^2.0.0",

View file

@ -11,9 +11,9 @@
"keypress": "^0.2.1", "keypress": "^0.2.1",
"listr2": "^6.6.1", "listr2": "^6.6.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"luxon": "^3.4.0", "luxon": "^3.4.3",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"tar": "^6.1.15", "tar": "^6.2.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
}, },
"engines": { "engines": {

View file

@ -1,6 +1,9 @@
import os import os
import scout_apm.celery
from celery import Celery from celery import Celery
from scout_apm.api import Config
# Set the default Django settings module for the 'celery' program # Set the default Django settings module for the 'celery' program
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ietf.settings') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ietf.settings')
@ -13,6 +16,25 @@ app = Celery('ietf')
# should have a `CELERY_` prefix. # should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY') app.config_from_object('django.conf:settings', namespace='CELERY')
# Turn on Scout APM celery instrumentation if configured in the environment
scout_key = os.environ.get("SCOUT_KEY", "")
scout_name = os.environ.get("SCOUT_NAME", "")
scout_core_agent_socket_path = os.environ.get("SCOUT_CORE_AGENT_SOCKET_PATH", "tcp://scoutapm:6590")
if scout_key and scout_name:
Config.set(
key=scout_key,
name=scout_name,
monitor=True,
core_agent_download=False,
core_agent_launch=False,
core_agent_path=scout_core_agent_socket_path,
)
# Note: Passing the Celery app to install() method as recommended in the
# Scout documentation causes failure at startup, likely because Scout
# ingests the config greedily before Django is ready. Have not found a
# workaround for this other than explicitly configuring Scout.
scout_apm.celery.install()
# Load task modules from all registered Django apps. # Load task modules from all registered Django apps.
app.autodiscover_tasks() app.autodiscover_tasks()

View file

@ -750,7 +750,7 @@ Man Expires September 22, 2015 [Page 3]
stream_id=draft.stream_id, group_id=draft.group_id, abstract=draft.abstract,stream=draft.stream, rev=draft.rev, stream_id=draft.stream_id, group_id=draft.group_id, abstract=draft.abstract,stream=draft.stream, rev=draft.rev,
pages=draft.pages, intended_std_level_id=draft.intended_std_level_id, pages=draft.pages, intended_std_level_id=draft.intended_std_level_id,
shepherd_id=draft.shepherd_id, ad_id=draft.ad_id, expires=draft.expires, shepherd_id=draft.shepherd_id, ad_id=draft.ad_id, expires=draft.expires,
notify=draft.notify, note=draft.note) notify=draft.notify)
rel = RelatedDocument.objects.create(source=replacement, rel = RelatedDocument.objects.create(source=replacement,
target=draft, target=draft,
relationship_id="replaces") relationship_id="replaces")

View file

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright The IETF Trust 2011-2020, All Rights Reserved # Copyright The IETF Trust 2011-2023, All Rights Reserved
import datetime import datetime
@ -837,6 +837,19 @@ class EditCharterTests(TestCase):
self.assertEqual(group.groupmilestone_set.filter(state="active", desc=m1.desc).count(), 1) self.assertEqual(group.groupmilestone_set.filter(state="active", desc=m1.desc).count(), 1)
self.assertEqual(group.groupmilestone_set.filter(state="active", desc=m4.desc).count(), 1) self.assertEqual(group.groupmilestone_set.filter(state="active", desc=m4.desc).count(), 1)
def test_approve_irtf(self):
charter = CharterFactory(group__type_id='rg')
url = urlreverse('ietf.doc.views_charter.approve', kwargs=dict(name=charter.name))
login_testing_unauthorized(self, "secretary", url)
empty_outbox()
r = self.client.post(url, dict())
self.assertEqual(r.status_code, 302)
self.assertEqual(len(outbox), 2)
self.assertTrue("IRTF" in outbox[1]['From'])
self.assertTrue("irtf-announce" in outbox[1]['To'])
self.assertTrue(charter.group.acronym in outbox[1]['Cc'])
self.assertTrue("RG Action" in outbox[1]['Subject'])
def test_charter_with_milestones(self): def test_charter_with_milestones(self):
charter = CharterFactory() charter = CharterFactory()

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2012-2020, All Rights Reserved # Copyright The IETF Trust 2012-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -13,8 +13,8 @@ from django.urls import reverse as urlreverse
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.doc.factories import IndividualDraftFactory, ConflictReviewFactory from ietf.doc.factories import IndividualDraftFactory, ConflictReviewFactory, RgDraftFactory
from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, BallotPositionDocEvent, TelechatDocEvent, State from ietf.doc.models import Document, DocEvent, NewRevisionDocEvent, BallotPositionDocEvent, TelechatDocEvent, State, DocTagName
from ietf.doc.utils import create_ballot_if_not_open from ietf.doc.utils import create_ballot_if_not_open
from ietf.doc.views_conflict_review import default_approval_text from ietf.doc.views_conflict_review import default_approval_text
from ietf.group.models import Person from ietf.group.models import Person
@ -168,6 +168,21 @@ class ConflictReviewTests(TestCase):
self.assertTrue(review_doc.active_ballot()) self.assertTrue(review_doc.active_ballot())
self.assertEqual(review_doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes') self.assertEqual(review_doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes')
# try to change to an AD-forbidden state
appr_noprob_sent_pk = str(State.objects.get(used=True, slug='appr-noprob-sent',type__slug='conflrev').pk)
r = self.client.post(url,dict(review_state=appr_noprob_sent_pk,comment='xyzzy'))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form .invalid-feedback'))
# try again as secretariat
self.client.logout()
login_testing_unauthorized(self, 'secretary', url)
r = self.client.post(url,dict(review_state=appr_noprob_sent_pk,comment='xyzzy'))
self.assertEqual(r.status_code, 302)
review_doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
self.assertEqual(review_doc.get_state('conflrev').slug, 'appr-noprob-sent')
def test_edit_notices(self): def test_edit_notices(self):
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission') doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
@ -450,3 +465,65 @@ class ConflictReviewSubmitTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
ConflictReviewFactory(name='conflict-review-imaginary-irtf-submission',review_of=IndividualDraftFactory(name='draft-imaginary-irtf-submission',stream_id='irtf'),notify='notifyme@example.net') ConflictReviewFactory(name='conflict-review-imaginary-irtf-submission',review_of=IndividualDraftFactory(name='draft-imaginary-irtf-submission',stream_id='irtf'),notify='notifyme@example.net')
class ConflictReviewIrtfStateTests(TestCase):
def start_review(self, role, kwargs=None):
doc = RgDraftFactory()
url = urlreverse('ietf.doc.views_conflict_review.start_review', kwargs=dict(name=doc.name))
login_testing_unauthorized(self, role, url)
r = self.client.post(url, kwargs)
self.assertEqual(r.status_code, 302)
self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'iesg-rev')
def test_start_review_as_secretary(self):
ad_strpk = str(Person.objects.get(name='Areað Irector').pk)
state_strpk = str(State.objects.get(used=True, slug='needshep', type__slug='conflrev').pk)
self.start_review('secretary', kwargs=dict(ad=ad_strpk, create_in_state=state_strpk))
def test_start_review_as_stream_owner(self):
self.start_review('irtf-chair')
def close_review(self, close_type, role):
doc = RgDraftFactory()
review = ConflictReviewFactory(review_of=doc)
url = urlreverse('ietf.doc.views_conflict_review.change_state', kwargs=dict(name=review.name))
login_testing_unauthorized(self, role, url)
strpk = str(State.objects.get(used=True, slug=close_type, type__slug='conflrev').pk)
r = self.client.post(url, dict(review_state=strpk))
self.assertEqual(r.status_code, 302)
self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'chair-w')
self.assertIn(DocTagName.objects.get(pk='iesg-com'), doc.tags.all())
def test_close_review_reqnopub_as_secretary(self):
self.close_review('appr-reqnopub-sent', 'secretary')
def test_close_review_noprob_as_secretary(self):
self.close_review('appr-noprob-sent', 'secretary')
def test_close_review_withdraw_as_secretary(self):
self.close_review('withdraw', 'secretary')
def test_close_review_dead_as_secretary(self):
self.close_review('dead', 'secretary')
def test_close_review_withdraw_as_ad(self):
self.close_review('withdraw', 'ad')
def test_close_review_dead_as_ad(self):
self.close_review('dead', 'ad')
def test_approve_review(self):
doc = RgDraftFactory()
review = ConflictReviewFactory(review_of=doc)
review.set_state(State.objects.get(used=True, slug='appr-noprob-pend', type='conflrev'))
url = urlreverse('ietf.doc.views_conflict_review.approve_conflict_review', kwargs=dict(name=review.name))
login_testing_unauthorized(self, 'secretary', url)
r = self.client.post(url, dict(announcement_text=default_approval_text(review)))
self.assertEqual(r.status_code, 302)
self.assertEqual(doc.get_state('draft-stream-irtf').slug, 'chair-w')
self.assertIn(DocTagName.objects.get(pk='iesg-com'), doc.tags.all())

View file

@ -98,7 +98,7 @@ class ChangeStateTests(TestCase):
draft.action_holders.add(ad) draft.action_holders.add(ad)
url = urlreverse('ietf.doc.views_draft.change_state', kwargs=dict(name=draft.name)) url = urlreverse('ietf.doc.views_draft.change_state', kwargs=dict(name=draft.name))
login_testing_unauthorized(self, "secretary", url) login_testing_unauthorized(self, "ad", url)
first_state = draft.get_state("draft-iesg") first_state = draft.get_state("draft-iesg")
next_states = first_state.next_states.all() next_states = first_state.next_states.all()
@ -154,6 +154,20 @@ class ChangeStateTests(TestCase):
q = PyQuery(r.content) q = PyQuery(r.content)
self.assertEqual(len(q('form [type=submit]:contains("%s")' % first_state.name)), 1) self.assertEqual(len(q('form [type=submit]:contains("%s")' % first_state.name)), 1)
# try to change to an AD-forbidden state
r = self.client.post(url, dict(state=State.objects.get(used=True, type='draft-iesg', slug='ann').pk, comment='Test comment'))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form .invalid-feedback'))
# try again as secretariat
self.client.logout()
login_testing_unauthorized(self, 'secretary', url)
r = self.client.post(url, dict(state=State.objects.get(used=True, type='draft-iesg', slug='ann').pk, comment='Test comment'))
self.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name)
self.assertEqual(draft.get_state_slug('draft-iesg'), 'ann')
def test_pull_from_rfc_queue(self): def test_pull_from_rfc_queue(self):
ad = Person.objects.get(user__username="ad") ad = Person.objects.get(user__username="ad")
draft = WgDraftFactory( draft = WgDraftFactory(
@ -362,16 +376,14 @@ class EditInfoTests(TestCase):
stream=draft.stream_id, stream=draft.stream_id,
ad=str(new_ad.pk), ad=str(new_ad.pk),
notify="test@example.com", notify="test@example.com",
note="New note",
telechat_date="", telechat_date="",
)) ))
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
draft = Document.objects.get(name=draft.name) draft = Document.objects.get(name=draft.name)
self.assertEqual(draft.ad, new_ad) self.assertEqual(draft.ad, new_ad)
self.assertEqual(draft.note, "New note")
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat")) self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
self.assertEqual(draft.docevent_set.count(), events_before + 3) self.assertEqual(draft.docevent_set.count(), events_before + 2)
self.assertEqual(len(outbox), mailbox_before + 1) self.assertEqual(len(outbox), mailbox_before + 1)
self.assertTrue(draft.name in outbox[-1]['Subject']) self.assertTrue(draft.name in outbox[-1]['Subject'])
@ -386,7 +398,6 @@ class EditInfoTests(TestCase):
stream=draft.stream_id, stream=draft.stream_id,
ad=str(draft.ad_id), ad=str(draft.ad_id),
notify=draft.notify, notify=draft.notify,
note="",
) )
# get # get
@ -489,7 +500,6 @@ class EditInfoTests(TestCase):
ad=ad.pk, ad=ad.pk,
create_in_state=State.objects.get(used=True, type="draft-iesg", slug="watching").pk, create_in_state=State.objects.get(used=True, type="draft-iesg", slug="watching").pk,
notify="test@example.com", notify="test@example.com",
note="This is a note",
telechat_date="", telechat_date="",
)) ))
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
@ -497,12 +507,11 @@ class EditInfoTests(TestCase):
draft = Document.objects.get(name=draft.name) draft = Document.objects.get(name=draft.name)
self.assertEqual(draft.get_state_slug("draft-iesg"), "watching") self.assertEqual(draft.get_state_slug("draft-iesg"), "watching")
self.assertEqual(draft.ad, ad) self.assertEqual(draft.ad, ad)
self.assertEqual(draft.note, "This is a note")
self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat")) self.assertTrue(not draft.latest_event(TelechatDocEvent, type="scheduled_for_telechat"))
self.assertEqual(draft.docevent_set.count(), events_before + 5) self.assertEqual(draft.docevent_set.count(), events_before + 4)
self.assertCountEqual(draft.action_holders.all(), [draft.ad]) self.assertCountEqual(draft.action_holders.all(), [draft.ad])
events = list(draft.docevent_set.order_by('time', 'id')) events = list(draft.docevent_set.order_by('time', 'id'))
self.assertEqual(events[-5].type, "started_iesg_process") self.assertEqual(events[-4].type, "started_iesg_process")
self.assertEqual(len(outbox), mailbox_before+1) self.assertEqual(len(outbox), mailbox_before+1)
self.assertTrue('IESG processing' in outbox[-1]['Subject']) self.assertTrue('IESG processing' in outbox[-1]['Subject'])
self.assertTrue('draft-ietf-mars-test2@' in outbox[-1]['To']) self.assertTrue('draft-ietf-mars-test2@' in outbox[-1]['To'])
@ -518,7 +527,6 @@ class EditInfoTests(TestCase):
ad=ad.pk, ad=ad.pk,
create_in_state=State.objects.get(used=True, type="draft-iesg", slug="pub-req").pk, create_in_state=State.objects.get(used=True, type="draft-iesg", slug="pub-req").pk,
notify="test@example.com", notify="test@example.com",
note="This is a note",
telechat_date="", telechat_date="",
)) ))
self.assertEqual(r.status_code, 302) self.assertEqual(r.status_code, 302)
@ -1043,23 +1051,6 @@ class IndividualInfoFormsTests(TestCase):
doc = Document.objects.get(name=self.docname) doc = Document.objects.get(name=self.docname)
self.assertEqual(doc.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date,None) self.assertEqual(doc.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date,None)
def test_doc_change_iesg_note(self):
url = urlreverse('ietf.doc.views_draft.edit_iesg_note', kwargs=dict(name=self.docname))
login_testing_unauthorized(self, "secretary", url)
# get
r = self.client.get(url)
self.assertEqual(r.status_code,200)
q = PyQuery(r.content)
self.assertEqual(len(q('[type=submit]:contains("Save")')),1)
# post
r = self.client.post(url,dict(note='ZpyQFGmA\r\nZpyQFGmA'))
self.assertEqual(r.status_code,302)
doc = Document.objects.get(name=self.docname)
self.assertEqual(doc.note,'ZpyQFGmA\nZpyQFGmA')
self.assertTrue('ZpyQFGmA' in doc.latest_event(DocEvent,type='added_comment').desc)
def test_doc_change_ad(self): def test_doc_change_ad(self):
url = urlreverse('ietf.doc.views_draft.edit_ad', kwargs=dict(name=self.docname)) url = urlreverse('ietf.doc.views_draft.edit_ad', kwargs=dict(name=self.docname))
login_testing_unauthorized(self, "secretary", url) login_testing_unauthorized(self, "secretary", url)

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2016-2020, All Rights Reserved # Copyright The IETF Trust 2016-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -363,6 +363,23 @@ class ReviewTests(TestCase):
request_events = review_req.reviewrequestdocevent_set.all() request_events = review_req.reviewrequestdocevent_set.all()
self.assertEqual(request_events.count(), 0) self.assertEqual(request_events.count(), 0)
def test_assign_reviewer_after_reject(self):
doc = WgDraftFactory()
review_team = ReviewTeamFactory()
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',name_id='reviewer')
reviewer_email = Email.objects.get(person__user__username="reviewer")
RoleFactory(group=review_team,person__user__username='reviewsecretary',name_id='secr')
review_req = ReviewRequestFactory(team=review_team,doc=doc)
ReviewAssignmentFactory(review_request=review_req, state_id='rejected', reviewer=rev_role.person.email_set.first())
url = urlreverse('ietf.doc.views_review.assign_reviewer', kwargs={ "name": doc.name, "request_id": review_req.pk })
login_testing_unauthorized(self, "reviewsecretary", url)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
reviewer_label = q("option[value=\"{}\"]".format(reviewer_email.address)).text().lower()
self.assertIn("rejected review of document before", reviewer_label)
def test_previously_reviewed_replaced_doc(self): def test_previously_reviewed_replaced_doc(self):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut")) review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',person__name='Some Reviewer',name_id='reviewer') rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',person__name='Some Reviewer',name_id='reviewer')
@ -577,6 +594,29 @@ class ReviewTests(TestCase):
self.assertContains(r, '<button type="submit"') self.assertContains(r, '<button type="submit"')
def test_accept_reviewer_assignment_after_reject(self):
doc = WgDraftFactory()
review_team = ReviewTeamFactory()
rev_role = RoleFactory(group=review_team,name_id='reviewer')
review_req = ReviewRequestFactory(doc=doc,team=review_team)
assignment = ReviewAssignmentFactory(review_request=review_req, state_id='rejected', reviewer=rev_role.person.email_set.first())
url = urlreverse('ietf.doc.views_review.review_request', kwargs={ "name": doc.name, "request_id": review_req.pk })
username = assignment.reviewer.person.user.username
self.client.login(username=username, password=username + "+password")
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
d = q('.reviewer-assignment-not-accepted')
self.assertTrue(d("[name=action][value=accept]"))
# accept
r = self.client.post(url, { "action": "accept" })
self.assertEqual(r.status_code, 302)
assignment = reload_db_objects(assignment)
self.assertEqual(assignment.state_id, "accepted")
def make_test_mbox_tarball(self, review_req): def make_test_mbox_tarball(self, review_req):
mbox_path = os.path.join(self.review_dir, "testmbox.tar.gz") mbox_path = os.path.join(self.review_dir, "testmbox.tar.gz")
with tarfile.open(mbox_path, "w:gz") as tar: with tarfile.open(mbox_path, "w:gz") as tar:

View file

@ -252,6 +252,7 @@ This test section has some text.
statement.latest_event(NewRevisionDocEvent).rev, "00" statement.latest_event(NewRevisionDocEvent).rev, "00"
) )
self.assertIsNotNone(statement.latest_event(type="published_statement")) self.assertIsNotNone(statement.latest_event(type="published_statement"))
self.assertIsNotNone(statement.history_set.last().latest_event(type="published_statement"))
if postdict["statement_submission"] == "enter": if postdict["statement_submission"] == "enter":
self.assertEqual(statement.text_or_error(), "some stuff") self.assertEqual(statement.text_or_error(), "some stuff")
else: else:

View file

@ -148,6 +148,21 @@ class StatusChangeTests(TestCase):
self.assertTrue(doc.active_ballot()) self.assertTrue(doc.active_ballot())
self.assertEqual(doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes') self.assertEqual(doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes')
# try to change to an AD-forbidden state
appr_sent_pk = str(State.objects.get(used=True, slug='appr-sent',type__slug='statchg').pk)
r = self.client.post(url, dict(new_state=appr_sent_pk, comment='xyzzy'))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('form .invalid-feedback'))
# try again as secretariat
self.client.logout()
login_testing_unauthorized(self, 'secretary', url)
r = self.client.post(url, dict(new_state=appr_sent_pk, comment='xyzzy'))
self.assertEqual(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEqual(doc.get_state('statchg').slug, 'appr-sent')
def test_edit_notices(self): def test_edit_notices(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review') doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('ietf.doc.views_doc.edit_notify;status-change',kwargs=dict(name=doc.name)) url = urlreverse('ietf.doc.views_doc.edit_notify;status-change',kwargs=dict(name=doc.name))

View file

@ -136,7 +136,6 @@ urlpatterns = [
url(r'^%(name)s/edit/suggested-replaces/$' % settings.URL_REGEXPS, views_draft.review_possibly_replaces), url(r'^%(name)s/edit/suggested-replaces/$' % settings.URL_REGEXPS, views_draft.review_possibly_replaces),
url(r'^%(name)s/edit/status/$' % settings.URL_REGEXPS, views_draft.change_intention), url(r'^%(name)s/edit/status/$' % settings.URL_REGEXPS, views_draft.change_intention),
url(r'^%(name)s/edit/telechat/$' % settings.URL_REGEXPS, views_doc.telechat_date), url(r'^%(name)s/edit/telechat/$' % settings.URL_REGEXPS, views_doc.telechat_date),
url(r'^%(name)s/edit/iesgnote/$' % settings.URL_REGEXPS, views_draft.edit_iesg_note),
url(r'^%(name)s/edit/ad/$' % settings.URL_REGEXPS, views_draft.edit_ad), url(r'^%(name)s/edit/ad/$' % settings.URL_REGEXPS, views_draft.edit_ad),
url(r'^%(name)s/edit/authors/$' % settings.URL_REGEXPS, views_doc.edit_authors), url(r'^%(name)s/edit/authors/$' % settings.URL_REGEXPS, views_doc.edit_authors),
url(r'^%(name)s/edit/consensus/$' % settings.URL_REGEXPS, views_draft.edit_consensus), url(r'^%(name)s/edit/consensus/$' % settings.URL_REGEXPS, views_draft.edit_consensus),

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2012-2020, All Rights Reserved # Copyright The IETF Trust 2012-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -25,6 +25,7 @@ from ietf.doc.forms import AdForm
from ietf.group.models import Role, Group from ietf.group.models import Role, Group
from ietf.iesg.models import TelechatDate from ietf.iesg.models import TelechatDate
from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_stream from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_stream
from ietf.name.models import DocTagName
from ietf.person.models import Person from ietf.person.models import Person
from ietf.utils import log from ietf.utils import log
from ietf.utils.mail import send_mail_preformatted from ietf.utils.mail import send_mail_preformatted
@ -35,6 +36,12 @@ class ChangeStateForm(forms.Form):
review_state = forms.ModelChoiceField(State.objects.filter(used=True, type="conflrev"), label="Conflict review state", empty_label=None, required=True) review_state = forms.ModelChoiceField(State.objects.filter(used=True, type="conflrev"), label="Conflict review state", empty_label=None, required=True)
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history.", required=False, strip=False) comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history.", required=False, strip=False)
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(ChangeStateForm, self).__init__(*args, **kwargs)
if not has_role(user, "Secretariat"):
self.fields["review_state"].queryset = self.fields["review_state"].queryset.exclude(slug__in=("appr-reqnopub-sent","appr-noprob-sent"))
@role_required("Area Director", "Secretariat") @role_required("Area Director", "Secretariat")
def change_state(request, name, option=None): def change_state(request, name, option=None):
"""Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary """Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary
@ -44,7 +51,7 @@ def change_state(request, name, option=None):
login = request.user.person login = request.user.person
if request.method == 'POST': if request.method == 'POST':
form = ChangeStateForm(request.POST) form = ChangeStateForm(request.POST, user=request.user)
if form.is_valid(): if form.is_valid():
clean = form.cleaned_data clean = form.cleaned_data
new_state = clean['review_state'] new_state = clean['review_state']
@ -90,12 +97,16 @@ def change_state(request, name, option=None):
review, review,
ok_to_publish) ok_to_publish)
if new_state.slug in ["appr-reqnopub-sent", "appr-noprob-sent", "withdraw", "dead"]:
doc = review.related_that_doc("conflrev")[0].document
if doc.stream_id == "irtf":
close_review_irtf_state(doc, login)
return redirect('ietf.doc.views_doc.document_main', name=review.name) return redirect('ietf.doc.views_doc.document_main', name=review.name)
else: else:
s = review.get_state() s = review.get_state()
init = dict(review_state=s.pk if s else None) init = dict(review_state=s.pk if s else None)
form = ChangeStateForm(initial=init) form = ChangeStateForm(initial=init, user=request.user)
return render(request, 'doc/change_state.html', return render(request, 'doc/change_state.html',
dict(form=form, dict(form=form,
@ -355,6 +366,10 @@ def approve_conflict_review(request, name):
c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text'] c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text']
c.save() c.save()
doc = review.related_that_doc("conflrev")[0].document
if doc.stream_id == "irtf":
close_review_irtf_state(doc, login)
return HttpResponseRedirect(review.get_absolute_url()) return HttpResponseRedirect(review.get_absolute_url())
else: else:
@ -485,6 +500,9 @@ def start_review_as_secretariat(request, name):
send_conflict_review_started_email(request, conflict_review) send_conflict_review_started_email(request, conflict_review)
if doc_to_review.stream_id == 'irtf':
start_review_irtf_state(doc_to_review, login)
return HttpResponseRedirect(conflict_review.get_absolute_url()) return HttpResponseRedirect(conflict_review.get_absolute_url())
else: else:
notify_addresses = build_notify_addresses(doc_to_review) notify_addresses = build_notify_addresses(doc_to_review)
@ -519,6 +537,9 @@ def start_review_as_stream_owner(request, name):
send_conflict_review_started_email(request, conflict_review) send_conflict_review_started_email(request, conflict_review)
if doc_to_review.stream_id == 'irtf':
start_review_irtf_state(doc_to_review, login)
return HttpResponseRedirect(conflict_review.get_absolute_url()) return HttpResponseRedirect(conflict_review.get_absolute_url())
else: else:
notify_addresses = build_notify_addresses(doc_to_review) notify_addresses = build_notify_addresses(doc_to_review)
@ -533,3 +554,26 @@ def start_review_as_stream_owner(request, name):
'doc_to_review': doc_to_review, 'doc_to_review': doc_to_review,
}, },
) )
def start_review_irtf_state(doc, by):
prev_state = doc.get_state('draft-stream-irtf')
new_state = State.objects.get(type_id='draft-stream-irtf', slug='iesg-rev')
if new_state != prev_state:
doc.set_state(new_state)
events = []
events.append(add_state_change_event(doc, by, prev_state, new_state))
doc.save_with_history(events)
def close_review_irtf_state(doc, by):
prev_state = doc.get_state("draft-stream-irtf")
new_state = State.objects.get(type_id="draft-stream-irtf", slug="chair-w")
prev_tags = set(doc.tags.all())
new_tags = set(DocTagName.objects.filter(pk="iesg-com"))
if new_state != prev_state:
doc.set_state(new_state)
doc.tags.clear()
doc.tags.set(new_tags)
events = [add_state_change_event(doc, by, prev_state, new_state, prev_tags, new_tags)]
doc.save_with_history(events)

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2010-2020, All Rights Reserved # Copyright The IETF Trust 2010-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -61,6 +61,12 @@ class ChangeStateForm(forms.Form):
substate = forms.ModelChoiceField(DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS), required=False) substate = forms.ModelChoiceField(DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS), required=False)
comment = forms.CharField(widget=forms.Textarea, required=False, strip=False) comment = forms.CharField(widget=forms.Textarea, required=False, strip=False)
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(ChangeStateForm, self).__init__(*args, **kwargs)
if not has_role(user, "Secretariat"):
self.fields["state"].queryset = self.fields["state"].queryset.exclude(slug="ann")
def clean(self): def clean(self):
retclean = self.cleaned_data retclean = self.cleaned_data
state = self.cleaned_data.get('state', '(None)') state = self.cleaned_data.get('state', '(None)')
@ -94,7 +100,7 @@ def change_state(request, name):
login = request.user.person login = request.user.person
if request.method == 'POST': if request.method == 'POST':
form = ChangeStateForm(request.POST) form = ChangeStateForm(request.POST, user=request.user)
form.docname=name form.docname=name
if form.is_valid(): if form.is_valid():
@ -175,7 +181,8 @@ def change_state(request, name):
state = doc.get_state("draft-iesg") state = doc.get_state("draft-iesg")
t = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS) t = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
form = ChangeStateForm(initial=dict(state=state.pk if state else None, form = ChangeStateForm(initial=dict(state=state.pk if state else None,
substate=t[0].pk if t else None)) substate=t[0].pk if t else None),
user=request.user)
form.docname=name form.docname=name
state = doc.get_state("draft-iesg") state = doc.get_state("draft-iesg")
@ -491,7 +498,6 @@ class EditInfoForm(forms.Form):
help_text="Separate email addresses with commas.", help_text="Separate email addresses with commas.",
required=False, required=False,
) )
note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False, strip=False)
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'})) telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'}))
returning_item = forms.BooleanField(required=False) returning_item = forms.BooleanField(required=False)
@ -515,9 +521,6 @@ class EditInfoForm(forms.Form):
# returning item is rendered non-standard # returning item is rendered non-standard
self.standard_fields = [x for x in self.visible_fields() if x.name not in ('returning_item',)] self.standard_fields = [x for x in self.visible_fields() if x.name not in ('returning_item',)]
def clean_note(self):
return self.cleaned_data['note'].replace('\r', '').strip()
def to_iesg(request,name): def to_iesg(request,name):
""" Submit an IETF stream document to the IESG for publication """ """ Submit an IETF stream document to the IESG for publication """
doc = get_object_or_404(Document, name=name, stream='ietf') doc = get_object_or_404(Document, name=name, stream='ietf')
@ -715,18 +718,6 @@ def edit_info(request, name):
diff('ad', "Responsible AD") diff('ad', "Responsible AD")
diff('notify', "State Change Notice email list") diff('notify', "State Change Notice email list")
if r['note'] != doc.note:
if not r['note']:
if doc.note:
changes.append("Note field has been cleared")
else:
if doc.note:
changes.append("Note changed to '%s'" % r['note'])
else:
changes.append("Note added '%s'" % r['note'])
doc.note = r['note']
if doc.group.type_id in ("individ", "area"): if doc.group.type_id in ("individ", "area"):
if not r["area"]: if not r["area"]:
r["area"] = Group.objects.get(type="individ") r["area"] = Group.objects.get(type="individ")
@ -769,7 +760,6 @@ def edit_info(request, name):
area=doc.group_id, area=doc.group_id,
ad=doc.ad_id, ad=doc.ad_id,
notify=doc.notify, notify=doc.notify,
note=doc.note,
telechat_date=initial_telechat_date, telechat_date=initial_telechat_date,
returning_item=initial_returning_item, returning_item=initial_returning_item,
) )
@ -862,52 +852,6 @@ def restore_draft_file(request, draft):
log.log(" Exception %s when attempting to move %s" % (ex, file)) log.log(" Exception %s when attempting to move %s" % (ex, file))
class IESGNoteForm(forms.Form):
note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False, strip=False)
def clean_note(self):
# not munging the database content to use html line breaks --
# that has caused a lot of pain in the past.
return self.cleaned_data['note'].replace('\r', '').strip()
@role_required("Area Director", "Secretariat")
def edit_iesg_note(request, name):
doc = get_object_or_404(Document, type="draft", name=name)
login = request.user.person
initial = dict(note=doc.note)
if request.method == "POST":
form = IESGNoteForm(request.POST, initial=initial)
if form.is_valid():
new_note = form.cleaned_data['note']
if new_note != doc.note:
if not new_note:
if doc.note:
log_message = "Note field has been cleared"
else:
if doc.note:
log_message = "Note changed to '%s'" % new_note
else:
log_message = "Note added '%s'" % new_note
c = DocEvent(type="added_comment", doc=doc, rev=doc.rev, by=login)
c.desc = log_message
c.save()
doc.note = new_note
doc.save_with_history([c])
return redirect('ietf.doc.views_doc.document_main', name=doc.name)
else:
form = IESGNoteForm(initial=initial)
return render(request, 'doc/draft/edit_iesg_note.html',
dict(doc=doc,
form=form,
))
class ShepherdWriteupUploadForm(forms.Form): class ShepherdWriteupUploadForm(forms.Form):
content = forms.CharField(widget=forms.Textarea, label="Shepherd writeup", help_text="Edit the shepherd writeup.", required=False, strip=False) content = forms.CharField(widget=forms.Textarea, label="Shepherd writeup", help_text="Edit the shepherd writeup.", required=False, strip=False)
txt = forms.FileField(label=".txt format", help_text="Or upload a .txt file.", required=False) txt = forms.FileField(label=".txt format", help_text="Or upload a .txt file.", required=False)

View file

@ -223,7 +223,7 @@ def review_request(request, name, request_id):
for assignment in assignments: for assignment in assignments:
assignment.is_reviewer = user_is_person(request.user, assignment.reviewer.person) assignment.is_reviewer = user_is_person(request.user, assignment.reviewer.person)
assignment.can_accept_reviewer_assignment = (assignment.state_id == "assigned" assignment.can_accept_reviewer_assignment = (assignment.state_id in ["assigned", "rejected"]
and (assignment.is_reviewer or can_manage_request)) and (assignment.is_reviewer or can_manage_request))
assignment.can_reject_reviewer_assignment = (assignment.state_id in ["assigned", "accepted"] assignment.can_reject_reviewer_assignment = (assignment.state_id in ["assigned", "accepted"]

View file

@ -239,6 +239,7 @@ def new_statement(request):
rev=statement.rev, rev=statement.rev,
by=request.user.person, by=request.user.person,
desc="Statement published", desc="Statement published",
time=statement.time,
) )
statement.save_with_history([e1, e2]) statement.save_with_history([e1, e2])
markdown_content = "" markdown_content = ""

View file

@ -42,6 +42,12 @@ class ChangeStateForm(forms.Form):
new_state = forms.ModelChoiceField(State.objects.filter(type="statchg", used=True), label="Status Change Evaluation State", empty_label=None, required=True) new_state = forms.ModelChoiceField(State.objects.filter(type="statchg", used=True), label="Status Change Evaluation State", empty_label=None, required=True)
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history.", required=False, strip=False) comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history.", required=False, strip=False)
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(ChangeStateForm, self).__init__(*args, **kwargs)
if not has_role(user, "Secretariat"):
self.fields["new_state"].queryset = self.fields["new_state"].queryset.exclude(slug="appr-sent")
@role_required("Area Director", "Secretariat") @role_required("Area Director", "Secretariat")
def change_state(request, name, option=None): def change_state(request, name, option=None):
@ -52,7 +58,7 @@ def change_state(request, name, option=None):
login = request.user.person login = request.user.person
if request.method == 'POST': if request.method == 'POST':
form = ChangeStateForm(request.POST) form = ChangeStateForm(request.POST, user=request.user)
if form.is_valid(): if form.is_valid():
clean = form.cleaned_data clean = form.cleaned_data
new_state = clean['new_state'] new_state = clean['new_state']
@ -116,7 +122,7 @@ def change_state(request, name, option=None):
type='statchg', type='statchg',
label='Status Change Evaluation State', label='Status Change Evaluation State',
) )
form = ChangeStateForm(initial=init) form = ChangeStateForm(initial=init, user=request.user)
return render(request, 'doc/change_state.html', return render(request, 'doc/change_state.html',
dict(form=form, dict(form=form,

View file

@ -27,7 +27,7 @@ class GroupFactory(factory.django.DjangoModelFactory):
django_get_or_create = ('acronym',) django_get_or_create = ('acronym',)
skip_postgeneration_save = True skip_postgeneration_save = True
name = factory.Faker('sentence',nb_words=6) name = factory.Faker('text', max_nb_chars=80)
acronym = factory.Sequence(lambda n: 'acronym%d' %n) acronym = factory.Sequence(lambda n: 'acronym%d' %n)
state_id = 'active' state_id = 'active'
type_id = 'wg' type_id = 'wg'

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2016-2020, All Rights Reserved # Copyright The IETF Trust 2016-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -711,6 +711,22 @@ class ReviewTests(TestCase):
self.assertEqual(settings.max_items_to_show_in_reviewer_list, 10) self.assertEqual(settings.max_items_to_show_in_reviewer_list, 10)
self.assertEqual(settings.days_to_show_in_reviewer_list, 365) self.assertEqual(settings.days_to_show_in_reviewer_list, 365)
def test_assign_reviewer_after_reject(self):
team = ReviewTeamFactory()
reviewer = RoleFactory(name_id='reviewer', group=team).person
ReviewerSettingsFactory(person=reviewer, team=team)
review_req = ReviewRequestFactory(team=team)
ReviewAssignmentFactory(review_request=review_req, state_id='rejected', reviewer=reviewer.email())
unassigned_url = urlreverse(ietf.group.views.manage_review_requests, kwargs={ 'acronym': team.acronym, 'group_type': team.type_id, "assignment_status": "unassigned" })
login_testing_unauthorized(self, "secretary", unassigned_url)
r = self.client.get(unassigned_url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
reviewer_label = q("option[value=\"{}\"]".format(reviewer.email())).text().lower()
self.assertIn("rejected review of document before", reviewer_label)
class BulkAssignmentTests(TestCase): class BulkAssignmentTests(TestCase):

View file

@ -142,8 +142,6 @@ def agenda_json(request, date=None):
'ad':doc.ad.name if doc.ad else None, 'ad':doc.ad.name if doc.ad else None,
} }
if doc.note:
docinfo['note'] = doc.note
defer = doc.active_defer_event() defer = doc.active_defer_event()
if defer: if defer:
docinfo['defer-by'] = defer.by.name docinfo['defer-by'] = defer.by.name

View file

@ -109,7 +109,9 @@ class DraftForm(forms.ModelForm):
cleaned_data = super().clean() cleaned_data = super().clean()
revisions = cleaned_data.get("revisions") revisions = cleaned_data.get("revisions")
document = cleaned_data.get("document") document = cleaned_data.get("document")
if not document.name.startswith("rfc"): if not document:
self.add_error("document", "Identifying the Internet-Draft or RFC for this disclosure is required.")
elif not document.name.startswith("rfc"):
if revisions.strip() == "": if revisions.strip() == "":
self.add_error("revisions", "Revisions of this Internet-Draft for which this disclosure is relevant must be specified.") self.add_error("revisions", "Revisions of this Internet-Draft for which this disclosure is relevant must be specified.")
return cleaned_data return cleaned_data

View file

@ -1,7 +1,7 @@
import factory import factory
from ietf.group.factories import GroupFactory from ietf.group.factories import GroupFactory
from ietf.liaisons.models import LiaisonStatement, LiaisonStatementEvent, LiaisonStatementAttachment from ietf.liaisons.models import LiaisonStatement, LiaisonStatementEvent, LiaisonStatementAttachment, RelatedLiaisonStatement
class LiaisonStatementFactory(factory.django.DjangoModelFactory): class LiaisonStatementFactory(factory.django.DjangoModelFactory):
class Meta: class Meta:
@ -50,3 +50,12 @@ class LiaisonStatementAttachmentFactory(factory.django.DjangoModelFactory):
type_id='liai-att', type_id='liai-att',
# TODO: Make name more convenient (the default now is to try to generate a draftname) # TODO: Make name more convenient (the default now is to try to generate a draftname)
) )
class RelatedLiaisonStatementFactory(factory.django.DjangoModelFactory):
class Meta:
model = RelatedLiaisonStatement
source = factory.SubFactory(LiaisonStatementFactory)
target = factory.SubFactory(LiaisonStatementFactory)
relationship_id = "refunk"

View file

@ -518,8 +518,7 @@ class EditLiaisonForm(LiaisonModelForm):
super(EditLiaisonForm, self).__init__(*args, **kwargs) super(EditLiaisonForm, self).__init__(*args, **kwargs)
self.edit = True self.edit = True
self.fields['attachments'].initial = self.instance.liaisonstatementattachment_set.exclude(removed=True) self.fields['attachments'].initial = self.instance.liaisonstatementattachment_set.exclude(removed=True)
related = [ str(x.pk) for x in self.instance.source_of_set.all() ] self.fields['related_to'].initial = [ x.target for x in self.instance.source_of_set.all() ]
self.fields['related_to'].initial = ','.join(related)
self.fields['submitted_date'].initial = self.instance.submitted self.fields['submitted_date'].initial = self.instance.submitted
def save(self, *args, **kwargs): def save(self, *args, **kwargs):

View file

@ -24,7 +24,7 @@ from ietf.utils.mail import outbox
from ietf.group.factories import GroupFactory, RoleFactory from ietf.group.factories import GroupFactory, RoleFactory
from ietf.liaisons.factories import ( LiaisonStatementFactory, from ietf.liaisons.factories import ( LiaisonStatementFactory,
LiaisonStatementEventFactory, LiaisonStatementAttachmentFactory, ) LiaisonStatementEventFactory, LiaisonStatementAttachmentFactory, RelatedLiaisonStatementFactory)
from ietf.liaisons.models import (LiaisonStatement, LiaisonStatementPurposeName, from ietf.liaisons.models import (LiaisonStatement, LiaisonStatementPurposeName,
LiaisonStatementAttachment) LiaisonStatementAttachment)
from ietf.person.models import Person from ietf.person.models import Person
@ -393,6 +393,8 @@ class LiaisonManagementTests(TestCase):
LiaisonStatementEventFactory(statement=liaison,type_id='posted') LiaisonStatementEventFactory(statement=liaison,type_id='posted')
from_group = liaison.from_groups.first() from_group = liaison.from_groups.first()
to_group = liaison.to_groups.first() to_group = liaison.to_groups.first()
rel1 = RelatedLiaisonStatementFactory(source=liaison)
rel2 = RelatedLiaisonStatementFactory(source=liaison)
url = urlreverse('ietf.liaisons.views.liaison_edit', kwargs=dict(object_id=liaison.pk)) url = urlreverse('ietf.liaisons.views.liaison_edit', kwargs=dict(object_id=liaison.pk))
login_testing_unauthorized(self, "secretary", url) login_testing_unauthorized(self, "secretary", url)
@ -402,6 +404,13 @@ class LiaisonManagementTests(TestCase):
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
q = PyQuery(r.content) q = PyQuery(r.content)
self.assertEqual(len(q('form input[name=from_contact]')), 1) self.assertEqual(len(q('form input[name=from_contact]')), 1)
json_data = q('form select[name=related_to]').attr('data-pre')
try:
decoded = json.loads(json_data)
except json.JSONDecodeError as e:
self.fail('data-pre contained invalid JSON data: %s' % str(e))
decoded_ids = [item['id'] for item in decoded]
self.assertEqual(decoded_ids, [rel1.target.id, rel2.target.id])
# edit # edit
attachments_before = liaison.attachments.count() attachments_before = liaison.attachments.count()
@ -1165,4 +1174,4 @@ class LiaisonManagementTests(TestCase):
mailbox_before = len(outbox) mailbox_before = len(outbox)
possibly_send_deadline_reminder(liaison) possibly_send_deadline_reminder(liaison)
self.assertEqual(len(outbox), mailbox_before) self.assertEqual(len(outbox), mailbox_before)

View file

@ -0,0 +1,26 @@
# Copyright The IETF Trust 2023, All Rights Reserved
from django.db import migrations
def forward(apps, schema_editor):
MailTrigger = apps.get_model("mailtrigger", "MailTrigger")
Recipient = apps.get_model("mailtrigger", "Recipient")
mt = MailTrigger.objects.get(pk="ballot_approved_charter")
mt.to.remove(mt.to.first())
mt.to.add(Recipient.objects.get(slug="group_stream_announce"))
def reverse(apps, schema_editor):
MailTrigger = apps.get_model("mailtrigger", "MailTrigger")
Recipient = apps.get_model("mailtrigger", "Recipient")
mt = MailTrigger.objects.get(pk="ballot_approved_charter")
mt.to.remove(mt.to.first())
mt.to.add(Recipient.objects.get(slug="ietf_announce"))
class Migration(migrations.Migration):
dependencies = [
("mailtrigger", "0002_slidesubmitter"),
]
operations = [
migrations.RunPython(forward, reverse)
]

View file

@ -3811,7 +3811,7 @@
], ],
"desc": "Recipients when a charter is approved", "desc": "Recipients when a charter is approved",
"to": [ "to": [
"ietf_announce" "group_stream_announce"
] ]
}, },
"model": "mailtrigger.mailtrigger", "model": "mailtrigger.mailtrigger",

View file

@ -1327,6 +1327,36 @@ class InactiveNomcomTests(TestCase):
q = PyQuery(response.content) q = PyQuery(response.content)
self.assertIn('not active', q('.alert-warning').text() ) self.assertIn('not active', q('.alert-warning').text() )
def test_filter_nominees(self):
url = reverse(
"ietf.nomcom.views.private_index", kwargs={"year": self.nc.year()}
)
login_testing_unauthorized(self, self.chair.user.username, url)
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
states = list(NomineePositionStateName.objects.values_list("slug", flat=True))
states += ["not-declined", "questionnaire"]
for state in states:
response = self.client.get(url, {"state": state})
self.assertEqual(response.status_code, 200)
q = PyQuery(response.content)
nps = []
if state == "not-declined":
nps = NomineePosition.objects.exclude(state__slug="declined")
elif state == "questionnaire":
nps = [
np
for np in NomineePosition.objects.not_duplicated()
if np.questionnaires
]
else:
nps = NomineePosition.objects.filter(state__slug=state)
# nomination state is in third table column
self.assertEqual(
len(nps), len(q("#nominee-position-table td:nth-child(3)"))
)
def test_email_pasting_closed(self): def test_email_pasting_closed(self):
url = reverse('ietf.nomcom.views.private_feedback_email', kwargs={'year':self.nc.year()}) url = reverse('ietf.nomcom.views.private_feedback_email', kwargs={'year':self.nc.year()})
login_testing_unauthorized(self, self.chair.user.username, url) login_testing_unauthorized(self, self.chair.user.username, url)
@ -2389,6 +2419,7 @@ class rfc8713EligibilityTests(TestCase):
self.eligible_people = list() self.eligible_people = list()
self.ineligible_people = list() self.ineligible_people = list()
# Section 4.14 qualification criteria
for combo_len in range(0,6): for combo_len in range(0,6):
for combo in combinations(meetings,combo_len): for combo in combinations(meetings,combo_len):
p = PersonFactory() p = PersonFactory()
@ -2399,6 +2430,18 @@ class rfc8713EligibilityTests(TestCase):
else: else:
self.eligible_people.append(p) self.eligible_people.append(p)
# Section 4.15 disqualification criteria
def ineligible_person_with_role(**kwargs):
p = RoleFactory(**kwargs).person
for m in meetings:
MeetingRegistrationFactory(person=p, meeting=m, attended=True)
self.ineligible_people.append(p)
for group in ['isocbot', 'ietf-trust', 'llc-board', 'iab']:
for role in ['member', 'chair']:
ineligible_person_with_role(group__acronym=group, name_id=role)
ineligible_person_with_role(group__type_id='area', group__state_id='active',name_id='ad')
ineligible_person_with_role(group=self.nomcom.group, name_id='chair')
# No-one is eligible for the other_nomcom # No-one is eligible for the other_nomcom
self.other_nomcom = NomComFactory(group__acronym='nomcom2018',first_call_for_volunteers=datetime.date(2018,5,1)) self.other_nomcom = NomComFactory(group__acronym='nomcom2018',first_call_for_volunteers=datetime.date(2018,5,1))

View file

@ -22,8 +22,8 @@ urlpatterns = [
url(r'^(?P<year>\d{4})/private/view-feedback/nominee/(?P<nominee_id>\d+)$', views.view_feedback_nominee), url(r'^(?P<year>\d{4})/private/view-feedback/nominee/(?P<nominee_id>\d+)$', views.view_feedback_nominee),
url(r'^(?P<year>\d{4})/private/view-feedback/topic/(?P<topic_id>\d+)$', views.view_feedback_topic), url(r'^(?P<year>\d{4})/private/view-feedback/topic/(?P<topic_id>\d+)$', views.view_feedback_topic),
url(r'^(?P<year>\d{4})/private/edit/nominee/(?P<nominee_id>\d+)$', views.edit_nominee), url(r'^(?P<year>\d{4})/private/edit/nominee/(?P<nominee_id>\d+)$', views.edit_nominee),
url(r'^(?P<year>\d{4})/private/merge-nominee/?$', views.private_merge_nominee), url(r'^(?P<year>\d{4})/private/merge-nominee/$', views.private_merge_nominee),
url(r'^(?P<year>\d{4})/private/merge-person/?$', views.private_merge_person), url(r'^(?P<year>\d{4})/private/merge-person/$', views.private_merge_person),
url(r'^(?P<year>\d{4})/private/send-reminder-mail/(?P<type>\w+)/$', views.send_reminder_mail), url(r'^(?P<year>\d{4})/private/send-reminder-mail/(?P<type>\w+)/$', views.send_reminder_mail),
url(r'^(?P<year>\d{4})/private/extract-email-lists/$', views.extract_email_lists), url(r'^(?P<year>\d{4})/private/extract-email-lists/$', views.extract_email_lists),
url(r'^(?P<year>\d{4})/private/edit-members/$', views.edit_members), url(r'^(?P<year>\d{4})/private/edit-members/$', views.edit_members),

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2012-2022, All Rights Reserved # Copyright The IETF Trust 2012-2023, All Rights Reserved
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
@ -66,8 +66,11 @@ DEFAULT_NOMCOM_TEMPLATES = [HOME_TEMPLATE,
] ]
# See RFC8713 section 4.15 # See RFC8713 section 4.15
# This potentially over-disqualifies past nomcom chairs if some
# nomcom 2+ nomcoms ago is still in the active state
DISQUALIFYING_ROLE_QUERY_EXPRESSION = ( Q(group__acronym__in=['isocbot', 'ietf-trust', 'llc-board', 'iab'], name_id__in=['member', 'chair']) DISQUALIFYING_ROLE_QUERY_EXPRESSION = ( Q(group__acronym__in=['isocbot', 'ietf-trust', 'llc-board', 'iab'], name_id__in=['member', 'chair'])
| Q(group__type_id='area', group__state='active',name_id='ad') | Q(group__type_id='area', group__state='active',name_id='ad')
| Q(group__type_id='nomcom', group__state='active', name_id='chair')
) )

View file

@ -77,7 +77,6 @@ def year_index(request, year):
return render(request, 'nomcom/year_index.html', return render(request, 'nomcom/year_index.html',
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'index',
'template': template}) 'template': template})
def announcements(request): def announcements(request):
@ -182,8 +181,7 @@ def private_key(request, year):
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'back_url': back_url, 'back_url': back_url,
'form': form, 'form': form})
'selected': 'private_key'})
@role_required("Nomcom") @role_required("Nomcom")
@ -216,10 +214,11 @@ def private_index(request, year):
filters = {} filters = {}
questionnaire_state = "questionnaire" questionnaire_state = "questionnaire"
not_declined_state = "not-declined"
selected_state = request.GET.get('state') selected_state = request.GET.get('state')
selected_position = request.GET.get('position') selected_position = request.GET.get('position')
if selected_state and not selected_state == questionnaire_state: if selected_state and selected_state not in [questionnaire_state, not_declined_state]:
filters['state__slug'] = selected_state filters['state__slug'] = selected_state
if selected_position: if selected_position:
@ -231,13 +230,15 @@ def private_index(request, year):
if selected_state == questionnaire_state: if selected_state == questionnaire_state:
nominee_positions = [np for np in nominee_positions if np.questionnaires] nominee_positions = [np for np in nominee_positions if np.questionnaires]
elif selected_state == not_declined_state:
nominee_positions = nominee_positions.exclude(state__slug='declined')
positions = Position.objects.get_by_nomcom(nomcom=nomcom) positions = Position.objects.get_by_nomcom(nomcom=nomcom)
stats = [ { 'position__name':p.name, stats = [ { 'position__name':p.name,
'position__id':p.pk, 'position__id':p.pk,
'position': p, 'position': p,
} for p in positions] } for p in positions]
states = [{'slug': questionnaire_state, 'name': 'Accepted and sent Questionnaire'}] + list(NomineePositionStateName.objects.values('slug', 'name')) states = [{'slug': questionnaire_state, 'name': 'Accepted and sent Questionnaire'}, {'slug': not_declined_state, 'name': 'Not declined'}] + list(NomineePositionStateName.objects.values('slug', 'name'))
positions = set([ n.position for n in all_nominee_positions.order_by('position__name') ]) positions = set([ n.position for n in all_nominee_positions.order_by('position__name') ])
for s in stats: for s in stats:
for state in states: for state in states:
@ -280,7 +281,6 @@ def private_index(request, year):
'positions': positions, 'positions': positions,
'selected_state': selected_state, 'selected_state': selected_state,
'selected_position': selected_position and int(selected_position) or None, 'selected_position': selected_position and int(selected_position) or None,
'selected': 'index',
'is_chair': is_chair, 'is_chair': is_chair,
'mailto': mailto, 'mailto': mailto,
}) })
@ -305,13 +305,11 @@ def send_reminder_mail(request, year, type):
interesting_state = 'pending' interesting_state = 'pending'
mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE mail_path = nomcom_template_path + NOMINEE_ACCEPT_REMINDER_TEMPLATE
reminder_description = 'accept (or decline) a nomination' reminder_description = 'accept (or decline) a nomination'
selected_tab = 'send_accept_reminder'
state_description = NomineePositionStateName.objects.get(slug=interesting_state).name state_description = NomineePositionStateName.objects.get(slug=interesting_state).name
elif type=='questionnaire': elif type=='questionnaire':
interesting_state = 'accepted' interesting_state = 'accepted'
mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE mail_path = nomcom_template_path + NOMINEE_QUESTIONNAIRE_REMINDER_TEMPLATE
reminder_description = 'complete the questionnaire for a nominated position' reminder_description = 'complete the questionnaire for a nominated position'
selected_tab = 'send_questionnaire_reminder'
state_description = NomineePositionStateName.objects.get(slug=interesting_state).name+' but no questionnaire has been received' state_description = NomineePositionStateName.objects.get(slug=interesting_state).name+' but no questionnaire has been received'
else: else:
raise Http404 raise Http404
@ -346,7 +344,6 @@ def send_reminder_mail(request, year, type):
'year': year, 'year': year,
'nominees': annotated_nominees, 'nominees': annotated_nominees,
'mail_template': mail_template, 'mail_template': mail_template,
'selected': selected_tab,
'reminder_description': reminder_description, 'reminder_description': reminder_description,
'state_description': state_description, 'state_description': state_description,
'is_chair_task' : True, 'is_chair_task' : True,
@ -373,7 +370,6 @@ def private_merge_person(request, year):
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'form': form, 'form': form,
'selected': 'merge_person',
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -398,7 +394,6 @@ def private_merge_nominee(request, year):
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'form': form, 'form': form,
'selected': 'merge_nominee',
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -408,8 +403,7 @@ def requirements(request, year):
return render(request, 'nomcom/requirements.html', return render(request, 'nomcom/requirements.html',
{'nomcom': nomcom, {'nomcom': nomcom,
'positions': positions, 'positions': positions,
'year': year, 'year': year})
'selected': 'requirements'})
def questionnaires(request, year): def questionnaires(request, year):
@ -418,8 +412,7 @@ def questionnaires(request, year):
return render(request, 'nomcom/questionnaires.html', return render(request, 'nomcom/questionnaires.html',
{'nomcom': nomcom, {'nomcom': nomcom,
'positions': positions, 'positions': positions,
'year': year, 'year': year})
'selected': 'questionnaires'})
@login_required @login_required
@ -453,15 +446,13 @@ def nominate(request, year, public, newperson):
messages.warning(request, "This Nomcom is not yet accepting nominations") messages.warning(request, "This Nomcom is not yet accepting nominations")
return render(request, template, return render(request, template,
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year})
'selected': 'nominate'})
if nomcom.group.state_id == 'conclude': if nomcom.group.state_id == 'conclude':
messages.warning(request, "Nominations to this Nomcom are closed.") messages.warning(request, "Nominations to this Nomcom are closed.")
return render(request, template, return render(request, template,
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year})
'selected': 'nominate'})
if request.method == 'POST': if request.method == 'POST':
if newperson: if newperson:
@ -485,8 +476,7 @@ def nominate(request, year, public, newperson):
{'form': form, {'form': form,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year,
'positions': nomcom.position_set.filter(is_open=True), 'positions': nomcom.position_set.filter(is_open=True)})
'selected': 'nominate'})
@login_required @login_required
def public_feedback(request, year): def public_feedback(request, year):
@ -550,7 +540,6 @@ def feedback(request, year, public):
return render(request, 'nomcom/feedback.html', { return render(request, 'nomcom/feedback.html', {
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'feedback',
'counts' : counts, 'counts' : counts,
'base_template': base_template 'base_template': base_template
}) })
@ -561,7 +550,6 @@ def feedback(request, year, public):
'form': None, 'form': None,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'feedback',
'positions': positions, 'positions': positions,
'topics': topics, 'topics': topics,
'counts' : counts, 'counts' : counts,
@ -575,7 +563,6 @@ def feedback(request, year, public):
'form': None, 'form': None,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'feedback',
'positions': positions, 'positions': positions,
'topics': topics, 'topics': topics,
'counts' : counts, 'counts' : counts,
@ -622,7 +609,6 @@ def feedback(request, year, public):
'year': year, 'year': year,
'positions': positions, 'positions': positions,
'topics': topics, 'topics': topics,
'selected': 'feedback',
'counts': counts, 'counts': counts,
'topic_counts': topic_counts, 'topic_counts': topic_counts,
'base_template': base_template 'base_template': base_template
@ -648,7 +634,6 @@ def private_feedback_email(request, year):
return render(request, template, return render(request, template,
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'feedback_email',
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -668,8 +653,7 @@ def private_feedback_email(request, year):
return render(request, template, return render(request, template,
{'form': form, {'form': form,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year})
'selected': 'feedback_email'})
@role_required("Nomcom Chair", "Nomcom Advisor") @role_required("Nomcom Chair", "Nomcom Advisor")
def private_questionnaire(request, year): def private_questionnaire(request, year):
@ -691,7 +675,6 @@ def private_questionnaire(request, year):
return render(request, template, return render(request, template,
{'nomcom': nomcom, {'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'questionnaire',
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -710,8 +693,7 @@ def private_questionnaire(request, year):
{'form': form, {'form': form,
'questionnaire_response': questionnaire_response, 'questionnaire_response': questionnaire_response,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year})
'selected': 'questionnaire'})
def process_nomination_status(request, year, nominee_position_id, state, date, hash): def process_nomination_status(request, year, nominee_position_id, state, date, hash):
@ -765,7 +747,6 @@ def process_nomination_status(request, year, nominee_position_id, state, date, h
'nominee_position': nominee_position, 'nominee_position': nominee_position,
'state': state, 'state': state,
'need_confirmation': need_confirmation, 'need_confirmation': need_confirmation,
'selected': 'feedback',
'form': form }) 'form': form })
@role_required("Nomcom") @role_required("Nomcom")
@ -830,7 +811,6 @@ def view_feedback(request, year):
return render(request, 'nomcom/view_feedback.html', return render(request, 'nomcom/view_feedback.html',
{'year': year, {'year': year,
'selected': 'view_feedback',
'nominees': nominees, 'nominees': nominees,
'nominee_feedback_types': nominee_feedback_types, 'nominee_feedback_types': nominee_feedback_types,
'independent_feedback_types': independent_feedback_types, 'independent_feedback_types': independent_feedback_types,
@ -927,7 +907,6 @@ def view_feedback_pending(request, year):
form.set_nomcom(nomcom, request.user) form.set_nomcom(nomcom, request.user)
return render(request, 'nomcom/view_feedback_pending.html', return render(request, 'nomcom/view_feedback_pending.html',
{'year': year, {'year': year,
'selected': 'feedback_pending',
'formset': formset, 'formset': formset,
'extra_step': extra_step, 'extra_step': extra_step,
'extra_ids': extra_ids, 'extra_ids': extra_ids,
@ -1090,7 +1069,6 @@ def edit_nominee(request, year, nominee_id):
return render(request, 'nomcom/edit_nominee.html', return render(request, 'nomcom/edit_nominee.html',
{'year': year, {'year': year,
'selected': 'index',
'nominee': nominee, 'nominee': nominee,
'form': form, 'form': form,
'nomcom': nomcom, 'nomcom': nomcom,
@ -1128,7 +1106,6 @@ def edit_nomcom(request, year):
'formset': formset, 'formset': formset,
'nomcom': nomcom, 'nomcom': nomcom,
'year': year, 'year': year,
'selected': 'edit_nomcom',
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -1142,7 +1119,6 @@ def list_templates(request, year):
return render(request, 'nomcom/list_templates.html', return render(request, 'nomcom/list_templates.html',
{'template_list': template_list, {'template_list': template_list,
'year': year, 'year': year,
'selected': 'edit_templates',
'nomcom': nomcom, 'nomcom': nomcom,
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -1215,7 +1191,6 @@ def list_positions(request, year):
return render(request, 'nomcom/list_positions.html', return render(request, 'nomcom/list_positions.html',
{'positions': positions, {'positions': positions,
'year': year, 'year': year,
'selected': 'edit_positions',
'nomcom': nomcom, 'nomcom': nomcom,
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -1282,7 +1257,6 @@ def list_topics(request, year):
return render(request, 'nomcom/list_topics.html', return render(request, 'nomcom/list_topics.html',
{'topics': topics, {'topics': topics,
'year': year, 'year': year,
'selected': 'edit_topics',
'nomcom': nomcom, 'nomcom': nomcom,
'is_chair_task' : True, 'is_chair_task' : True,
}) })
@ -1364,8 +1338,7 @@ def edit_members(request, year):
return render(request, 'nomcom/new_edit_members.html', return render(request, 'nomcom/new_edit_members.html',
{'nomcom' : nomcom, {'nomcom' : nomcom,
'year' : year, 'year' : year,
'form': form, 'form': form})
})
@role_required("Nomcom Chair", "Nomcom Advisor") @role_required("Nomcom Chair", "Nomcom Advisor")
def extract_email_lists(request, year): def extract_email_lists(request, year):
@ -1385,8 +1358,7 @@ def extract_email_lists(request, year):
'pending': pending, 'pending': pending,
'accepted': accepted, 'accepted': accepted,
'noresp': noresp, 'noresp': noresp,
'bypos': bypos, 'bypos': bypos})
})
@login_required @login_required
def volunteer(request): def volunteer(request):

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2019-2021, All Rights Reserved # Copyright The IETF Trust 2019-2023, All Rights Reserved
import re import re
@ -10,6 +10,7 @@ from simple_history.utils import bulk_update_with_history
from ietf.doc.models import DocumentAuthor from ietf.doc.models import DocumentAuthor
from ietf.doc.utils import extract_complete_replaces_ancestor_mapping_for_docs from ietf.doc.utils import extract_complete_replaces_ancestor_mapping_for_docs
from ietf.group.models import Role from ietf.group.models import Role
from ietf.name.models import ReviewAssignmentStateName
from ietf.person.models import Person from ietf.person.models import Person
import debug # pyflakes:ignore import debug # pyflakes:ignore
from ietf.review.models import NextReviewerInTeam, ReviewerSettings, ReviewWish, ReviewRequest, \ from ietf.review.models import NextReviewerInTeam, ReviewerSettings, ReviewWish, ReviewRequest, \
@ -55,8 +56,6 @@ def persons_with_previous_review(team, review_req, possible_person_ids, state_id
reviewassignment__state=state_id, reviewassignment__state=state_id,
team=team, team=team,
).distinct() ).distinct()
if review_req.pk is not None:
has_reviewed_previous = has_reviewed_previous.exclude(pk=review_req.pk)
has_reviewed_previous = set( has_reviewed_previous = set(
has_reviewed_previous.values_list("reviewassignment__reviewer__person", flat=True)) has_reviewed_previous.values_list("reviewassignment__reviewer__person", flat=True))
return has_reviewed_previous return has_reviewed_previous
@ -70,7 +69,14 @@ class AbstractReviewerQueuePolicy:
"""Assign a reviewer to a request and update policy state accordingly""" """Assign a reviewer to a request and update policy state accordingly"""
# Update policy state first - needed by LRU policy to correctly compute whether assignment was in-order # Update policy state first - needed by LRU policy to correctly compute whether assignment was in-order
self.update_policy_state_for_assignment(review_req, reviewer.person, add_skip) self.update_policy_state_for_assignment(review_req, reviewer.person, add_skip)
return review_req.reviewassignment_set.create(state_id='assigned', reviewer=reviewer, assigned_on=timezone.now()) assignment = review_req.reviewassignment_set.filter(reviewer=reviewer).first()
if assignment:
assignment.state = ReviewAssignmentStateName.objects.get(slug='assigned', used=True)
assignment.assigned_on = timezone.now()
assignment.save()
return assignment
else:
return review_req.reviewassignment_set.create(state_id='assigned', reviewer=reviewer, assigned_on=timezone.now())
def default_reviewer_rotation_list(self, include_unavailable=False): def default_reviewer_rotation_list(self, include_unavailable=False):
""" Return a list of reviewers (Person objects) in the default reviewer rotation for a policy. """ Return a list of reviewers (Person objects) in the default reviewer rotation for a policy.
@ -168,15 +174,15 @@ class AbstractReviewerQueuePolicy:
PersonEmailChoiceField(label="Assign Reviewer", empty_label="(None)") PersonEmailChoiceField(label="Assign Reviewer", empty_label="(None)")
""" """
# Collect a set of person IDs for people who have either not responded # Collect a set of person IDs for people who have not responded
# to or outright rejected reviewing this document in the past # to this document in the past
rejecting_reviewer_ids = review_req.doc.reviewrequest_set.filter( rejecting_reviewer_ids = review_req.doc.reviewrequest_set.filter(
reviewassignment__state__slug__in=('rejected', 'no-response') reviewassignment__state__slug='no-response'
).values_list( ).values_list(
'reviewassignment__reviewer__person_id', flat=True 'reviewassignment__reviewer__person_id', flat=True
) )
# Query the Email objects for reviewers who haven't rejected or # Query the Email objects for reviewers who haven't
# not responded to this document in the past # not responded to this document in the past
field.queryset = field.queryset.filter( field.queryset = field.queryset.filter(
role__name="reviewer", role__name="reviewer",

View file

@ -1,4 +1,4 @@
# Copyright The IETF Trust 2016-2021, All Rights Reserved # Copyright The IETF Trust 2016-2023, All Rights Reserved
import debug # pyflakes:ignore import debug # pyflakes:ignore
import datetime import datetime
@ -471,9 +471,6 @@ class _Wrapper(TestCase):
addresses = list( map( lambda choice: choice[0], field.choices ) ) addresses = list( map( lambda choice: choice[0], field.choices ) )
self.assertNotIn(
str(rejected_reviewer.email()), addresses,
"Reviews should not suggest people who have rejected this request in the past")
self.assertNotIn( self.assertNotIn(
str(no_response_reviewer.email()), addresses, str(no_response_reviewer.email()), addresses,
"Reviews should not suggest people who have not responded to this request in the past.") "Reviews should not suggest people who have not responded to this request in the past.")

View file

@ -390,8 +390,10 @@ def assign_review_request_to_reviewer(request, review_req, reviewer, add_skip=Fa
log.assertion('reviewer is not None') log.assertion('reviewer is not None')
# cannot reference reviewassignment_set relation until pk exists # cannot reference reviewassignment_set relation until pk exists
if review_req.pk is not None and review_req.reviewassignment_set.filter(reviewer=reviewer).exists(): if review_req.pk is not None:
return reviewassignment_set = review_req.reviewassignment_set.filter(reviewer=reviewer)
if reviewassignment_set.exists() and not reviewassignment_set.filter(state_id='rejected').exists():
return
# Note that assigning a review no longer unassigns other reviews # Note that assigning a review no longer unassigns other reviews

View file

@ -165,7 +165,8 @@ class SessionRequestTestCase(TestCase):
self.assertContains(r, 'Schedule the sessions on subsequent days') self.assertContains(r, 'Schedule the sessions on subsequent days')
self.assertContains(r, 'Thursday early afternoon, Thursday late afternoon') self.assertContains(r, 'Thursday early afternoon, Thursday late afternoon')
self.assertContains(r, group2.acronym) self.assertContains(r, group2.acronym)
self.assertContains(r, 'Second session with: {} {}'.format(group3.acronym, group4.acronym)) # The sessions can be in any order in the HTML, deal with that
self.assertRegex(r.content.decode(), r'Second session with: ({} {}|{} {})'.format(group3.acronym, group4.acronym, group4.acronym, group3.acronym))
# check that a notification was sent # check that a notification was sent
self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox), 1)

View file

@ -57,7 +57,7 @@ $(document)
var text = $(this) var text = $(this)
.text(); .text();
// insert some <wbr> at strategic places // insert some <wbr> at strategic places
var newtext = text.replace(/([@._])/g, "$1<wbr>"); var newtext = text.replace(/([@._+])/g, "$1<wbr>");
if (newtext === text) { if (newtext === text) {
return; return;
} }

View file

@ -1,16 +1,21 @@
import * as List from "list.js"; import {
default as List
var dummy = new List(); } from "list.js";
function text_sort(a, b, options) { function text_sort(a, b, options) {
function prep(e, options) {
return $($.parseHTML(e.values()[options.valueName]))
.text()
.trim()
.replaceAll(/\s+/g, ' ');
}
// sort by text content // sort by text content
return dummy.utils.naturalSort.caseInsensitive($($.parseHTML(a.values()[options.valueName])) return prep(a, options).localeCompare(prep(b, options), "en", {
.text() sensitivity: "base",
.trim() ignorePunctuation: true
.replaceAll(/\s+/g, ' '), $($.parseHTML(b.values()[options.valueName])) });
.text()
.trim()
.replaceAll(/\s+/g, ' '));
} }
function replace_with_internal(table, internal_table, i) { function replace_with_internal(table, internal_table, i) {
@ -204,12 +209,12 @@ $(document)
} }
let newlist = new List(hook, pagination ? { let newlist = new List(hook, pagination ? {
valueNames: fields, valueNames: fields,
pagination: pagination, pagination: pagination,
page: items_per_page page: items_per_page
} : { } : {
valueNames: fields valueNames: fields
}); });
// override search module with a patched version // override search module with a patched version
// see https://github.com/javve/list.js/issues/699 // see https://github.com/javve/list.js/issues/699
// TODO: check if this is still needed if list.js ever sees an update // TODO: check if this is still needed if list.js ever sees an update
@ -220,7 +225,7 @@ $(document)
if (enable_search) { if (enable_search) {
reset_search.on("click", function () { reset_search.on("click", function () {
search_field.val(""); search_field.val("");
$.each(list_instance, (i, e) => { $.each(list_instance, (_, e) => {
e.search(); e.search();
}); });
}); });
@ -229,7 +234,7 @@ $(document)
if (event.key == "Escape") { if (event.key == "Escape") {
reset_search.trigger("click"); reset_search.trigger("click");
} else { } else {
$.each(list_instance, (i, e) => { $.each(list_instance, (_, e) => {
e.search($(this) e.search($(this)
.val()); .val());
}); });
@ -242,16 +247,19 @@ $(document)
.on("click", function () { .on("click", function () {
var order = $(this) var order = $(this)
.hasClass("asc") ? "desc" : "asc"; .hasClass("asc") ? "desc" : "asc";
$.each(list_instance, (i, e) => { $.each(list_instance, (_, e) => {
e.sort($(this) e.sort($(this)
.attr("data-sort"), { order: order, sortFunction: text_sort }); .attr("data-sort"), {
order: order,
sortFunction: text_sort
});
}); });
}); });
$.each(list_instance, (i, e) => { $.each(list_instance, (i, e) => {
e.on("sortComplete", function () { e.on("sortComplete", function () {
replace_with_internal(table, internal_table, i); replace_with_internal(table, internal_table, i);
$(table).find("[data-bs-original-title]").tooltip(); $(table).find("[data-bs-original-title]").tooltip();
if (i == list_instance.length - 1) { if (i == list_instance.length - 1) {
$(table) $(table)
.find("thead:first tr") .find("thead:first tr")
@ -267,6 +275,9 @@ $(document)
}); });
} }
}); });
e.on("searchComplete", function () {
replace_with_internal(table, internal_table, i);
});
}); });
$(table.addClass("tablesorter-done")); $(table.addClass("tablesorter-done"));
@ -284,8 +295,11 @@ $(document)
if (presort_col) { if (presort_col) {
const order = presort_col.attr("data-default-sort"); const order = presort_col.attr("data-default-sort");
if (order === "asc" || order === "desc") { if (order === "asc" || order === "desc") {
$.each(list_instance, (i, e) => { $.each(list_instance, (_, e) => {
e.sort(presort_col.attr("data-sort"), { order: order, sortFunction: text_sort }); e.sort(presort_col.attr("data-sort"), {
order: order,
sortFunction: text_sort
});
}); });
} }
} }

View file

@ -207,11 +207,12 @@ const interimRequest = (function() {
toggleLocation: function () { toggleLocation: function () {
if (this.checked) { if (this.checked) {
$(".location") $(".location input, .location select")
.prop('disabled', false); .prop('disabled', false);
} else { } else {
$(".location") $(".location input, .location select")
.prop('disabled', true); .prop('disabled', true)
.val('');
} }
}, },

View file

@ -34,7 +34,7 @@ function filter_calendar_events(filter_params, event_list) {
} }
// format a moment in a tz // format a moment in a tz
var moment_formats = { time: 'HH:mm', date: 'YYYY-MM-DD', datetime: 'YYYY-MM-DD HH:mm' }; var moment_formats = { time: 'HH:mm', date: 'YYYY-MM-DD', datetime: 'YYYY-MM-DD HH:mm' , timezone: 'z'};
function format_moment(t_moment, tz, fmt_type) { function format_moment(t_moment, tz, fmt_type) {
return t_moment.tz(tz) return t_moment.tz(tz)
@ -43,6 +43,9 @@ function format_moment(t_moment, tz, fmt_type) {
function make_display_events(event_data, tz) { function make_display_events(event_data, tz) {
var calendarEl = document.getElementById('calendar'); var calendarEl = document.getElementById('calendar');
if (!calendarEl) {
return;
}
var glue = calendarEl.clientWidth > 720 ? ' ' : '\n'; var glue = calendarEl.clientWidth > 720 ? ' ' : '\n';
return $.map(event_data, function (src_event) { return $.map(event_data, function (src_event) {
var title; var title;
@ -83,6 +86,9 @@ function update_calendar(tz, filter_params) {
* filtered events. * filtered events.
*/ */
var calendarEl = document.getElementById('calendar'); var calendarEl = document.getElementById('calendar');
if (!calendarEl) {
return;
}
event_calendar = new FullCalendar(calendarEl, { event_calendar = new FullCalendar(calendarEl, {
plugins: [dayGridPlugin, bootstrap5Plugin], plugins: [dayGridPlugin, bootstrap5Plugin],
initialView: 'dayGridMonth', initialView: 'dayGridMonth',
@ -136,7 +142,7 @@ function format_session_time(session_elt, tz) {
.attr('data-start-utc')); .attr('data-start-utc'));
var end = moment.utc($(session_elt) var end = moment.utc($(session_elt)
.attr('data-end-utc')); .attr('data-end-utc'));
return format_moment(start, tz, 'datetime') + '-' + format_moment(end, tz, 'time'); return format_moment(start, tz, 'datetime') + '-' + format_moment(end, tz, 'time') + ' ' + format_moment(start, tz, 'timezone');
} }
function format_meeting_time(meeting_elt, tz) { function format_meeting_time(meeting_elt, tz) {

View file

@ -355,7 +355,6 @@ class SubmitTests(BaseSubmitTestCase):
ad=draft.ad, ad=draft.ad,
expires=timezone.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE), expires=timezone.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE),
notify="aliens@example.mars", notify="aliens@example.mars",
note="",
) )
sug_replaced_draft.set_state(State.objects.get(used=True, type="draft", slug="active")) sug_replaced_draft.set_state(State.objects.get(used=True, type="draft", slug="active"))
@ -1401,7 +1400,6 @@ class SubmitTests(BaseSubmitTestCase):
"submitter-name": "Some Random Test Person", "submitter-name": "Some Random Test Person",
"submitter-email": "random@example.com", "submitter-email": "random@example.com",
"replaces": [str(draft.pk)], "replaces": [str(draft.pk)],
"edit-note": "no comments",
"authors-0-name": "Person 1", "authors-0-name": "Person 1",
"authors-0-email": "person1@example.com", "authors-0-email": "person1@example.com",
"authors-1-name": "Person 2", "authors-1-name": "Person 2",
@ -1417,7 +1415,6 @@ class SubmitTests(BaseSubmitTestCase):
self.assertEqual(submission.document_date, document_date) self.assertEqual(submission.document_date, document_date)
self.assertEqual(submission.abstract, "some abstract") self.assertEqual(submission.abstract, "some abstract")
self.assertEqual(submission.pages, 123) self.assertEqual(submission.pages, 123)
self.assertEqual(submission.note, "no comments")
self.assertEqual(submission.submitter, "Some Random Test Person <random@example.com>") self.assertEqual(submission.submitter, "Some Random Test Person <random@example.com>")
self.assertEqual(submission.replaces, draft.name) self.assertEqual(submission.replaces, draft.name)
self.assertEqual(submission.state_id, "manual") self.assertEqual(submission.state_id, "manual")

View file

@ -14,7 +14,7 @@
{% csrf_token %} {% csrf_token %}
{% bootstrap_form ballot_writeup_form %} {% bootstrap_form ballot_writeup_form %}
<div class="form-text my-3"> <div class="form-text my-3">
Technical summary, Working Group summary, document quality, personnel, IRTF note, IESG note, IANA note. This text will be appended to all announcements and messages to the IRTF or RFC Editor. Technical summary, Working Group summary, document quality, personnel, IANA note. This text will be appended to all announcements and messages to the IRTF or RFC Editor.
{% if ballot_issue_danger %} {% if ballot_issue_danger %}
<p class="text-danger"> <p class="text-danger">
This document has not completed IETF Last Call. Please do not issue the ballot early without good reason. This document has not completed IETF Last Call. Please do not issue the ballot early without good reason.
@ -36,4 +36,4 @@
Back Back
</a> </a>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -1,4 +1,4 @@
{% load ietf_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org> {% load ietf_filters %}{% autoescape off %}From: {% if group.type_id == "rg" %}The IRTF <irtf-chair@irtf.org>{% else %}The IESG <iesg-secretary@ietf.org>{% endif %}
To: {{ to }}{% if cc %} To: {{ to }}{% if cc %}
Cc: {{ cc }} {% endif %} Cc: {{ cc }} {% endif %}
Subject: {{ group.type.name }} Action: {{ action_type }} {{ group.name }} ({{ group.acronym }}) Subject: {{ group.type.name }} Action: {{ action_type }} {{ group.name }} ({{ group.acronym }})

View file

@ -36,14 +36,6 @@ RFC Editor Note
(Insert RFC Editor Note here or remove section) (Insert RFC Editor Note here or remove section)
IRTF Note
(Insert IRTF Note here or remove section)
IESG Note
(Insert IESG Note here or remove section)
IANA Note IANA Note
(Insert IANA Note here or remove section) (Insert IANA Note here or remove section)

View file

@ -13,7 +13,7 @@
<form class="mt-3" method="post"> <form class="mt-3" method="post">
{% csrf_token %} {% csrf_token %}
{% bootstrap_form ballot_writeup_form %} {% bootstrap_form ballot_writeup_form %}
<div class="form-text mb-3">Working group summary, personnel, IAB note, IESG note, IANA note.</div> <div class="form-text mb-3">Working group summary, personnel, IANA note.</div>
<button type="submit" <button type="submit"
class="btn btn-primary" class="btn btn-primary"
name="save_ballot_writeup" name="save_ballot_writeup"

View file

@ -408,32 +408,19 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% if iesg_state.slug != 'idexists' %} {% if iesg_state.slug != 'idexists' and doc.note %}
{% if doc.note or can_edit %} <tr>
<tr> <td></td>
<td></td> <th scope="row">
<th scope="row"> IESG note
IESG note </th>
</th> <td class="edit">
<td class="edit"> {# IESG Notes are historic and read-only now #}
{% if can_edit and not snapshot %} </td>
<a class="btn btn-primary btn-sm" <td>
href="{% url 'ietf.doc.views_draft.edit_iesg_note' name=doc.name %}"> {{ doc.notedoc.note|urlize_ietf_docs|linkify|linebreaksbr }}
Edit </td>
</a> </tr>
{% endif %}
</td>
<td>
{% if doc.note %}
{{ doc.note|linebreaksbr }}
{% else %}
<span class="text-body-secondary">
(None)
</span>
{% endif %}
</td>
</tr>
{% endif %}
{% endif %} {% endif %}
<tr> <tr>
<td></td> <td></td>

View file

@ -2,7 +2,7 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #} {# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %} {% load origin %}
{% load static %} {% load static %}
{% load ietf_filters textfilters %} {% load ietf_filters textfilters tz %}
{% block title %}{{ doc.title|default:"Untitled" }}{% endblock %} {% block title %}{{ doc.title|default:"Untitled" }}{% endblock %}
{% block content %} {% block content %}
{% origin %} {% origin %}
@ -29,6 +29,24 @@
{% if snapshot %}<span class="badge rounded-pill text-bg-warning">Snapshot</span>{% endif %} {% if snapshot %}<span class="badge rounded-pill text-bg-warning">Snapshot</span>{% endif %}
</td> </td>
</tr> </tr>
{% if doc.meeting_related %}
<tr>
<th scope="row">
Date and time
</th>
<td></td>
<td>
{% with session=doc.get_related_session %}
{% with timeslot=session.official_timeslotassignment.timeslot %}
{% if session.meeting %}
<span class="session-time date me-3" data-start-utc="{{ timeslot.time|utc|date:'Y-m-d H:i' }}" data-end-utc="{{ timeslot.end_time|utc|date:'Y-m-d H:i' }}"></span>
{% include "meeting/tz-display.html" with meeting_timezone=session.meeting.time_zone id_suffix="" minimal=True only %}
{% endif %}
{% endwith %}
{% endwith %}
</td>
</tr>
{% endif %}
<tr> <tr>
<th scope="row">Title</th> <th scope="row">Title</th>
<td class="edit"> <td class="edit">
@ -97,7 +115,21 @@
{% if presentations %} {% if presentations %}
{% for pres in presentations %} {% for pres in presentations %}
{{ pres.session.short_name }} at {{ pres.session.meeting }} {{ pres.session.short_name }} at {{ pres.session.meeting }}
{% if pres.rev != doc.rev %}(version -{{ pres.rev }}){% endif %}{% if not forloop.last %},{% endif %} {% if pres.rev != doc.rev %}(version -{{ pres.rev }}){% endif %}
<br>
<b>Remote instructions:</b>
{% if pres.session.agenda_note|first_url|conference_url %}
<a href="{{ pres.session.agenda_note|first_url }}" title="Online conference">
<i class="bi bi-beople"></i>
</a>
{% elif pres.session.remote_instructions|first_url|conference_url %}
<a href="{{ pres.session.remote_instructions|first_url }}"
title="Online conference">
<i class="bi bi-people"></i>
</a>
{% endif %}
{{ pres.session.remote_instructions|linkify }}
{% if not forloop.last %}<br>{% endif %}
{% endfor %} {% endfor %}
{% else %} {% else %}
<span class="text-body-secondary">(None)</span> <span class="text-body-secondary">(None)</span>
@ -142,4 +174,16 @@
{% block js %} {% block js %}
<script src="{% static 'ietf/js/d3.js' %}"></script> <script src="{% static 'ietf/js/d3.js' %}"></script>
<script src="{% static 'ietf/js/document_timeline.js' %}"></script> <script src="{% static 'ietf/js/document_timeline.js' %}"></script>
{% if doc.meeting_related %}
<script src="{% static 'ietf/js/moment.js' %}"></script>
<script src="{% static 'ietf/js/upcoming.js' %}"></script>
<script src="{% static 'ietf/js/timezone.js' %}"></script>
<script>
$(function () {
// Init with best guess at local timezone.
ietf_timezone.set_tz_change_callback(timezone_changed);
ietf_timezone.initialize('local');
});
</script>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -1,19 +0,0 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load django_bootstrap5 %}
{% block title %}Edit IESG note for {{ doc.name }}{% endblock %}
{% block content %}
{% origin %}
<h1>
Edit IESG note
<br>
<small class="text-body-secondary">{{ doc.name }}</small>
</h1>
<form class="mt-3" method="post">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">Save</button>
<a class="btn btn-secondary float-end" href="{{ doc.get_absolute_url }}">Back</a>
</form>
{% endblock %}

View file

@ -33,13 +33,6 @@ Personnel
Who is the Document Shepherd for this document? Who is the Who is the Document Shepherd for this document? Who is the
Responsible Area Director? Responsible Area Director?
{% endif %} {% endif %}
{% if doc.stream.slug == "irtf" %}IRTF Note
(Insert IRTF Note here or remove section)
{% elif doc.stream.slug == "ietf" %}IESG Note
(Insert IESG Note here or remove section)
{% endif %}
IANA Note IANA Note
{% if iana %} {% if iana %}
{% filter wordwrap:"76"|indent:2 %}{{ iana }}{% endfilter %} {% filter wordwrap:"76"|indent:2 %}{{ iana }}{% endfilter %}

View file

@ -177,6 +177,8 @@
<div class="reviewer-assignment-not-accepted"> <div class="reviewer-assignment-not-accepted">
{% if assignment.state_id == "assigned" %} {% if assignment.state_id == "assigned" %}
Assignment not accepted yet Assignment not accepted yet
{% elif assignment.state_id == "rejected" %}
<span class="text-danger">Assignment rejected</span>
{% else %} {% else %}
<span class="text-success">Assignment accepted</span> <span class="text-success">Assignment accepted</span>
{% endif %} {% endif %}

View file

@ -26,7 +26,7 @@
{% for state in states %} {% for state in states %}
<tr id="{{ state.slug|default:"idexists" }}"> <tr id="{{ state.slug|default:"idexists" }}">
<th scope="row">{{ state.name }}</th> <th scope="row">{{ state.name }}</th>
<td>{{ state.desc|urlize_ietf_docs|linkify }}</td> <td>{{ state.desc|safe|urlize_ietf_docs|linkify }}</td>
{% if has_next_states %} {% if has_next_states %}
<td> <td>
{% for s in state.next_states.all %} {% for s in state.next_states.all %}

View file

@ -8,7 +8,8 @@
<h1>{{ group_type | upper }} {{ role }} photos</h1> <h1>{{ group_type | upper }} {{ role }} photos</h1>
{% regroup roles|dictsort:"last_initial" by last_initial as alphabet_blocks %} {% regroup roles|dictsort:"last_initial" by last_initial as alphabet_blocks %}
{% for letter in alphabet_blocks %} {% for letter in alphabet_blocks %}
<h2 class="mt-4" {% if letter.grouper|slugify %}id="{{ letter.grouper|slugify }}"{% endif %}>{{ letter.grouper }}</h2> <!-- [html-validate-disable-next valid-id -- Unicode IDs are OK in HTML5] -->
<h2 class="mt-4" {% if letter.grouper|slugify %}id="{{ letter.grouper }}"{% endif %}>{{ letter.grouper }}</h2>
{% regroup letter.list by person as person_groups %} {% regroup letter.list by person as person_groups %}
{# keep in sync with group_photos.html #} {# keep in sync with group_photos.html #}
<div class="mt-0 row row-cols-2 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-4 row-cols-xxl-5 g-2"> <div class="mt-0 row row-cols-2 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-4 row-cols-xxl-5 g-2">
@ -17,4 +18,4 @@
{% endfor %} {% endfor %}
</div> </div>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}

View file

@ -1,7 +1,6 @@
{% load origin tz %} {% load origin tz %}
{% origin %} {% origin %}
{% for s in sessions %} {% for s in sessions %}
{% timezone s.meeting.time_zone %}
<tr> <tr>
<td> <td>
{% if s.meeting.type.slug == 'ietf' %} {% if s.meeting.type.slug == 'ietf' %}
@ -12,9 +11,11 @@
</td> </td>
<td> <td>
{% if s.current_status == "sched" %} {% if s.current_status == "sched" %}
{{ s.time|date:"Y-m-d" }} {% with timeslot=s.official_timeslotassignment.timeslot %}
<span class="session-time date me-3" data-start-utc="{{ timeslot.time|utc|date:'Y-m-d H:i' }}" data-end-utc="{{ timeslot.end_time|utc|date:'Y-m-d H:i' }}"></span>
{% endwith %}
{% else %} {% else %}
<i>{{ s.current_status_name }}</i> <div class="badge rounded-pill text-bg-secondary">{{ s.current_status_name }}</div>
{% endif %} {% endif %}
{% if show_request and s.meeting.type_id == 'ietf' %} {% if show_request and s.meeting.type_id == 'ietf' %}
{% if can_edit %} {% if can_edit %}
@ -28,9 +29,6 @@
<td> <td>
{% if s.name %}{{ s.name }}{% endif %} {% if s.name %}{{ s.name }}{% endif %}
</td> </td>
<td>
{% if s.current_status == "sched" %}{{ s.time|date:"D" }}{% endif %}
</td>
<td> <td>
{% if show_ical and s.current_status == "sched" %} {% if show_ical and s.current_status == "sched" %}
{% if s.meeting.type_id == 'ietf' %} {% if s.meeting.type_id == 'ietf' %}
@ -78,5 +76,4 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endtimezone %}
{% endfor %} {% endfor %}

View file

@ -1,6 +1,5 @@
{% extends "group/group_base.html" %} {% extends "group/group_base.html" %}
{# Copyright The IETF Trust 2015-2022, All Rights Reserved #} {% load origin static %}
{% load origin %}
{% block title %} {% block title %}
Meetings Meetings
{% if group %}for {{ group.acronym }}{% endif %} {% if group %}for {{ group.acronym }}{% endif %}
@ -19,15 +18,15 @@
{% endblock %} {% endblock %}
{% block group_content %} {% block group_content %}
{% origin %} {% origin %}
{% include "meeting/tz-display.html" with meeting_timezone=None id_suffix="" minimal=False only %}
{% if in_progress %} {% if in_progress %}
<h2 class="mt-3" id="inprogressmeets">Meetings in progress</h2> <h2 class="mt-5" id="inprogressmeets">Meetings in progress</h2>
{% with sessions=in_progress show_request=True show_ical=True can_edit_materials=can_edit %} {% with sessions=in_progress show_request=True show_ical=True can_edit_materials=can_edit %}
<table class="table table-sm table-striped tablesorter"> <table class="table table-sm table-striped tablesorter">
<thead> <thead>
<tr> <tr>
<th scope="col" data-sort="meeting">Meeting</th> <th class="col-3" scope="col" data-sort="meeting">Meeting</th>
<th scope="col" data-sort="date">Date</th> <th class="col-3" scope="col" data-sort="date">Date</th>
<th scope="col"></th>
<th scope="col"></th> <th scope="col"></th>
<th scope="col">Materials</th> <th scope="col">Materials</th>
</tr> </tr>
@ -39,7 +38,7 @@
{% endwith %} {% endwith %}
{% endif %} {% endif %}
{% if future %} {% if future %}
<h2 class="mt-3" id="futuremeets"> <h2 class="mt-5" id="futuremeets">
Future Meetings Future Meetings
<a class="float-end" <a class="float-end"
aria-label="icalendar entry for all scheduled future {{ group.acronym }} meetings" aria-label="icalendar entry for all scheduled future {{ group.acronym }} meetings"
@ -51,9 +50,8 @@
<table class="table table-sm table-striped tablesorter"> <table class="table table-sm table-striped tablesorter">
<thead> <thead>
<tr> <tr>
<th scope="col" data-sort="meeting">Meeting</th> <th class="col-3" scope="col" data-sort="meeting">Meeting</th>
<th scope="col" data-sort="date">Date</th> <th class="col-3" scope="col" data-sort="date">Date</th>
<th scope="col"></th>
<th scope="col"></th> <th scope="col"></th>
<th scope="col">Materials</th> <th scope="col">Materials</th>
</tr> </tr>
@ -66,13 +64,12 @@
</table> </table>
{% endif %} {% endif %}
{% if past or recent %} {% if past or recent %}
<h2 class="mt-3" id="pastmeets">Past Meetings (within the last four years)</h2> <h2 class="mt-5" id="pastmeets">Past Meetings (within the last four years)</h2>
<table class="table table-sm table-striped tablesorter"> <table class="table table-sm table-striped tablesorter">
<thead> <thead>
<tr> <tr>
<th scope="col" data-sort="meeting">Meeting</th> <th class="col-3" scope="col" data-sort="meeting">Meeting</th>
<th scope="col" data-sort="date">Date</th> <th class="col-3" scope="col" data-sort="date">Date</th>
<th scope="col"></th>
<th scope="col"></th> <th scope="col"></th>
<th scope="col">Materials</th> <th scope="col">Materials</th>
</tr> </tr>
@ -100,13 +97,12 @@
older_sessions value, this block will need to be adjusted. older_sessions value, this block will need to be adjusted.
{% endcomment %} {% endcomment %}
{% if far_past %} {% if far_past %}
<h2 class="mt-3" id="farpastmeets">Meetings more than four years ago</h2> <h2 class="mt-5" id="farpastmeets">Meetings more than four years ago</h2>
<table class="table table-sm table-striped tablesorter"> <table class="table table-sm table-striped tablesorter">
<thead> <thead>
<tr> <tr>
<th scope="col" data-sort="meeting">Meeting</th> <th class="col-3" scope="col" data-sort="meeting">Meeting</th>
<th scope="col" data-sort="date">Date</th> <th class="col-3" scope="col" data-sort="date">Date</th>
<th scope="col"></th>
<th scope="col"></th> <th scope="col"></th>
<th scope="col">Materials</th> <th scope="col">Materials</th>
</tr> </tr>
@ -160,3 +156,16 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block js %}
<script src="{% static 'ietf/js/list.js' %}"></script>
<script src="{% static 'ietf/js/moment.js' %}"></script>
<script src="{% static 'ietf/js/upcoming.js' %}"></script>
<script src="{% static 'ietf/js/timezone.js' %}"></script>
<script>
$(function () {
// Init with best guess at local timezone.
ietf_timezone.set_tz_change_callback(timezone_changed);
ietf_timezone.initialize('local');
});
</script>
{% endblock %}

View file

@ -1,7 +1,7 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #} {# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %} {% load origin %}
{% origin %} {% origin %}
{% load ietf_filters ballot_icon person_filters %} {% load ietf_filters ballot_icon person_filters textfilters %}
<div class="card mb-3"> <div class="card mb-3">
<div class="position-absolute top-0 end-0 m-3">{% ballot_icon doc %}</div> <div class="position-absolute top-0 end-0 m-3">{% ballot_icon doc %}</div>
<div class="card-body"> <div class="card-body">
@ -27,7 +27,7 @@
{% if conflictdoc.note %} {% if conflictdoc.note %}
<div class="row"> <div class="row">
<div class="col-3 text-end fw-bold">Note</div> <div class="col-3 text-end fw-bold">Note</div>
<div class="col">{{ conflictdoc.note|linebreaksbr }}</div> <div class="col">{{ conflictdoc.note|urlize_ietf_docs|linkify|linebreaksbr }}</div>
</div> </div>
{% endif %} {% endif %}
<div class="row"> <div class="row">

View file

@ -3,6 +3,5 @@
{% filter wordwrap:"68"|indent|indent %}{{ doc.title }}{% endfilter %} {% filter wordwrap:"68"|indent|indent %}{{ doc.title }}{% endfilter %}
{{ conflictdoc.name }}-{{ conflictdoc.rev }} {{ conflictdoc.name }}-{{ conflictdoc.rev }}
{% filter wordwrap:"66"|indent:"4" %}{{ conflictdoc.title }} ({{ conflictdoc.stream }}: {{ conflictdoc.intended_std_level }}){% endfilter %} {% filter wordwrap:"66"|indent:"4" %}{{ conflictdoc.title }} ({{ conflictdoc.stream }}: {{ conflictdoc.intended_std_level }}){% endfilter %}
{% if conflictdoc.note %}{# note: note is not escaped #} {% filter wordwrap:"64"|indent:"6" %}Note: {{ conflictdoc.note|striptags }}{% endfilter %} Token: {{ doc.ad }}
{% endif %} Token: {{ doc.ad }}
{% with doc.active_defer_event as defer %}{% if defer %} Was deferred by {{defer.by}} on {{defer.time|date:"Y-m-d"}}{% endif %}{% endwith %}{% endwith %} {% with doc.active_defer_event as defer %}{% if defer %} Was deferred by {{defer.by}} on {{defer.time|date:"Y-m-d"}}{% endif %}{% endwith %}{% endwith %}

View file

@ -1,8 +1,7 @@
{% load ietf_filters %}{% with doc.rfc_number as rfc_number %} {% load ietf_filters %}{% with doc.rfc_number as rfc_number %}
o {{doc.name}}{% if not rfc_number %}-{{doc.rev}}{% endif %}{% endwith %}{%if doc.has_rfc_editor_note %} (Has RFC Editor Note){% endif %}{% if doc.stream %} - {{ doc.stream }} stream{% endif %} o {{doc.name}}{% if not rfc_number %}-{{doc.rev}}{% endif %}{% endwith %}{%if doc.has_rfc_editor_note %} (Has RFC Editor Note){% endif %}{% if doc.stream %} - {{ doc.stream }} stream{% endif %}
{% filter wordwrap:"68"|indent|indent %}{{ doc.title }} ({{ doc.intended_std_level }}){% endfilter %} {% filter wordwrap:"68"|indent|indent %}{{ doc.title }} ({{ doc.intended_std_level }}){% endfilter %}
{% if doc.note %}{# note: note is not escaped #} {% filter wordwrap:"68"|indent|indent %}Note: {{ doc.note|striptags }}{% endfilter %} Token: {{ doc.ad }}{% if doc.iana_review_state %}
{% endif %} Token: {{ doc.ad }}{% if doc.iana_review_state %}
IANA Review: {{ doc.iana_review_state }}{% endif %}{% if doc.consensus %} IANA Review: {{ doc.iana_review_state }}{% endif %}{% if doc.consensus %}
Consensus: {{ doc.consensus }}{% endif %}{% if doc.lastcall_expires %} Consensus: {{ doc.consensus }}{% endif %}{% if doc.lastcall_expires %}
Last call expires: {{ doc.lastcall_expires|date:"Y-m-d" }}{% endif %}{% if doc.review_assignments %} Last call expires: {{ doc.lastcall_expires|date:"Y-m-d" }}{% endif %}{% if doc.review_assignments %}

View file

@ -93,7 +93,7 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send a working <p>If APPROVED with caveats - The Secretariat will send a working
group submission, Protocol Action Announcement that includes the group submission, Protocol Action Announcement that includes the
[RFC Editor Note, IESG Note, etc.] to be drafted by [Name that [RFC Editor Note, etc.] to be drafted by [Name that
AD].</p> AD].</p>
{% endif %} {% endif %}
@ -103,7 +103,7 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send an <p>If APPROVED with caveats - The Secretariat will send an
individual submission, Protocol Action Announcement that includes individual submission, Protocol Action Announcement that includes
the [RFC Editor Note, IESG Note, etc.] to be drafted by [Name that the [RFC Editor Note, etc.] to be drafted by [Name that
AD].</p> AD].</p>
{% endif %} {% endif %}
@ -113,7 +113,7 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send the <p>If APPROVED with caveats - The Secretariat will send the
associated status change Protocol Action Announcements that includes the associated status change Protocol Action Announcements that includes the
[RFC Editor Note, IESG Note, etc.] to be drafted by [Name that [RFC Editor Note, etc.] to be drafted by [Name that
AD].</p> AD].</p>
{% endif %} {% endif %}
@ -123,7 +123,7 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send a working <p>If APPROVED with caveats - The Secretariat will send a working
group submission Document Action announcement that includes the [RFC group submission Document Action announcement that includes the [RFC
Ed. Note, IESG, note, etc.] from [Name that AD].</p> Ed. Note, etc.] from [Name that AD].</p>
{% endif %} {% endif %}
{% if num|startswith:"3.2.1" or num|startswith:"3.2.2" %} {% if num|startswith:"3.2.1" or num|startswith:"3.2.2" %}
@ -132,7 +132,7 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send an <p>If APPROVED with caveats - The Secretariat will send an
individual submission Document Action announcement that includes the individual submission Document Action announcement that includes the
[RFC Ed. Note, IESG, note, etc.] from [Name that AD].</p> [RFC Ed. Note, etc.] from [Name that AD].</p>
{% endif %} {% endif %}
{% if num|startswith:"3.3.1" or num|startswith:"3.3.2" %} {% if num|startswith:"3.3.1" or num|startswith:"3.3.2" %}
@ -141,13 +141,12 @@ Parts Copyright (c) 2009 The IETF Trust, all rights reserved.
<p>If APPROVED with caveats - The Secretariat will send the associated <p>If APPROVED with caveats - The Secretariat will send the associated
status change Document Action announcements that includes the [RFC status change Document Action announcements that includes the [RFC
Ed. Note, IESG, note, etc.] from [Name that AD].</p> Ed. Note, etc.] from [Name that AD].</p>
{% endif %} {% endif %}
{% if num|startswith:"3.4.1" or num|startswith:"3.4.2" %} {% if num|startswith:"3.4.1" or num|startswith:"3.4.2" %}
<p>If APPROVED - The Secretariat will send a standard no problem <p>If APPROVED - The Secretariat will send a standard no problem
message to the RFC Editor. [Name of AD] will you supply the text for message to the RFC Editor.</p>
the IESG Note?</p>
<p>If APPROVED with caveats - The Secretariat will send a standard <p>If APPROVED with caveats - The Secretariat will send a standard
no problem message to the RFC Editor that includes the note drafted no problem message to the RFC Editor that includes the note drafted

View file

@ -24,8 +24,8 @@
</div> </div>
{% endif %} {% endif %}
{% bootstrap_field form.meeting_type layout='horizontal' %} {% bootstrap_field form.meeting_type layout='horizontal' %}
{% bootstrap_field form.city layout='horizontal' %} {% bootstrap_field form.city layout='horizontal' wrapper_class='location mb-3' %}
{% bootstrap_field form.country layout='horizontal' %} {% bootstrap_field form.country layout='horizontal' wrapper_class='location mb-3' %}
{% bootstrap_field form.time_zone layout='horizontal' %} {% bootstrap_field form.time_zone layout='horizontal' %}
{{ formset.management_form }} {{ formset.management_form }}
{% if formset.non_form_errors %}<div class="my-3 alert alert-danger">{{ formset.non_form_errors }}</div>{% endif %} {% if formset.non_form_errors %}<div class="my-3 alert alert-danger">{{ formset.non_form_errors }}</div>{% endif %}

View file

@ -25,7 +25,7 @@
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="{{ form.subject.id_for_label }}" class="col-md-2 fw-bold col-form-label">Subject</label> <label for="{{ form.subject.id_for_label }}" class="col-md-2 fw-bold col-form-label">Subject</label>
<div class="col-md-10">{% render_field form.subject class="form-control" readonly="readonly" %}</div> <div class="col-md-10">{% render_field form.subject class="form-control" %}</div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<label for="{{ form.body.id_for_label }}" class="col-md-2 fw-bold col-form-label">Body</label> <label for="{{ form.body.id_for_label }}" class="col-md-2 fw-bold col-form-label">Body</label>

View file

@ -57,6 +57,17 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script src="{% static 'ietf/js/list.js' %}"></script>
<script src="{% static 'ietf/js/moment.js' %}"></script>
<script src="{% static 'ietf/js/upcoming.js' %}"></script>
<script src="{% static 'ietf/js/timezone.js' %}"></script>
<script>
$(function () {
// Init with best guess at local timezone.
ietf_timezone.set_tz_change_callback(timezone_changed);
ietf_timezone.initialize('local');
});
</script>
{% if can_manage_materials %} {% if can_manage_materials %}
<script src="{% static 'ietf/js/sortable.js' %}"></script> <script src="{% static 'ietf/js/sortable.js' %}"></script>
<script> <script>

View file

@ -17,8 +17,8 @@
{% if sessions|length > 1 %}Session {{ forloop.counter }} :{% endif %} {% if sessions|length > 1 %}Session {{ forloop.counter }} :{% endif %}
{% for time in session.times %} {% for time in session.times %}
{% if not forloop.first %},{% endif %} {% if not forloop.first %},{% endif %}
{{ time|timezone:session.meeting.time_zone|dateformat:"l Y-m-d H:i T" }} <span class="session-time date me-3" data-start-utc="{{ timeslot.time|utc|date:'Y-m-d H:i' }}" data-end-utc="{{ timeslot.end_time|utc|date:'Y-m-d H:i' }}"></span>
{% if time.tzinfo.zone != "UTC" %}<span class="small">({{ time|utc|dateformat:"H:i T" }})</span>{% endif %} {% include "meeting/tz-display.html" with meeting_timezone=session.meeting.time_zone id_suffix=session.pk minimal=True only %}
{% endfor %} {% endfor %}
{% if session.cancelled %} {% if session.cancelled %}
<small class="badge rounded-pill text-bg-warning">Cancelled</small> <small class="badge rounded-pill text-bg-warning">Cancelled</small>

View file

@ -12,8 +12,8 @@ As long as id_suffix is different, should allow for as many copies of the widget
{% load origin %} {% load origin %}
{% origin %} {% origin %}
{% firstof id_suffix "" as suffix %} {% firstof id_suffix "" as suffix %}
<div class="tz-display flex-fill {% if minimal %}btn-group btn-group-sm my-2{% else %}input-group my-3{% endif %} flex-wrap"> <span class="tz-display flex-fill {% if minimal %}btn-group btn-group-sm my-2{% else %}input-group my-3{% endif %} flex-wrap">
{% if not minimal %}<label class="input-group-text border-primary bg-white fw-bold">Time zone:</label>{% endif %} {% if not minimal %}<label class="input-group-text border-primary bg-transparent fw-bold">Time zone:</label>{% endif %}
{% if meeting_timezone is not None %} {% if meeting_timezone is not None %}
<input type="radio" <input type="radio"
name="tzradio{{ suffix }}" name="tzradio{{ suffix }}"
@ -46,4 +46,4 @@ As long as id_suffix is different, should allow for as many copies of the widget
</option> </option>
</select> </select>
{% endif %} {% endif %}
</div> </span>

View file

@ -4,9 +4,6 @@
{% load django_bootstrap5 textfilters person_filters %} {% load django_bootstrap5 textfilters person_filters %}
{% load static %} {% load static %}
{% block subtitle %}- Eligible People{% endblock %} {% block subtitle %}- Eligible People{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block nomcom_content %} {% block nomcom_content %}
{% origin %} {% origin %}
<h2>Eligible People for {{ nomcom.group }}</h2> <h2>Eligible People for {{ nomcom.group }}</h2>
@ -41,7 +38,4 @@
{% endif %} {% endif %}
</table> </table>
} }
{% endblock %}
{% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
{% endblock %} {% endblock %}

View file

@ -24,23 +24,24 @@
<thead> <thead>
<tr> <tr>
{% if nomcom.group.state_id == 'active' %} {% if nomcom.group.state_id == 'active' %}
<th scope="colgroup" colspan="3"> <th scope="col">
<i class="bi bi-check"></i>
</th> </th>
<th scope="col"></th>
{% endif %} {% endif %}
<th scope="col" data-sort="position"> <th scope="col" data-sort="position">
Position Position
</th> </th>
<th scope="col" data-sort="iesg"> <th class="text-center" scope="col" data-sort="iesg">
IESG IESG
</th> </th>
<th scope="col" data-sort="open"> <th class="text-center" scope="col" data-sort="open">
Open Open
</th> </th>
<th scope="col" data-sort="accept_nom"> <th class="text-center" scope="col" data-sort="accept_nom">
Accepting Nominations Accepting Nominations
</th> </th>
<th scope="col" data-sort="accept_fb"> <th class="text-center" scope="col" data-sort="accept_fb">
Accepting Feedback Accepting Feedback
</th> </th>
</tr> </tr>
@ -58,13 +59,11 @@
aria-label="position.name" aria-label="position.name"
name="selected"> name="selected">
</td> </td>
<td class="edit"> <td class="text-nowrap">
<a class="btn btn-primary btn-sm" <a class="btn btn-primary btn-sm"
href="{% url 'ietf.nomcom.views.edit_position' year position.id %}"> href="{% url 'ietf.nomcom.views.edit_position' year position.id %}">
Edit Edit
</a> </a>
</td>
<td class="remove">
<a class="btn btn-danger btn-sm" <a class="btn btn-danger btn-sm"
href="{% url 'ietf.nomcom.views.remove_position' year position.id %}"> href="{% url 'ietf.nomcom.views.remove_position' year position.id %}">
Remove Remove
@ -74,16 +73,16 @@
<td> <td>
{{ position.name }} {{ position.name }}
</td> </td>
<td> <td class="text-center">
{{ position.is_iesg_position|yesno:"✓," }} {{ position.is_iesg_position|yesno:"✓," }}
</td> </td>
<td> <td class="text-center">
{{ position.is_open|yesno:"✓," }} {{ position.is_open|yesno:"✓," }}
</td> </td>
<td> <td class="text-center">
{{ position.accepting_nominations|yesno:"✓," }} {{ position.accepting_nominations|yesno:"✓," }}
</td> </td>
<td> <td class="text-center">
{{ position.accepting_feedback|yesno:"✓," }} {{ position.accepting_feedback|yesno:"✓," }}
</td> </td>
</tr> </tr>
@ -117,7 +116,7 @@
<option value="unset_accept_nom"> <option value="unset_accept_nom">
Is Accepting Nominations: No Is Accepting Nominations: No
</option> </option>
<option value="set_accept_bf"> <option value="set_accept_fb">
Is Accepting Feedback: Yes Is Accepting Feedback: Yes
</option> </option>
<option value="unset_accept_fb"> <option value="unset_accept_fb">
@ -135,7 +134,4 @@
There are no positions defined. There are no positions defined.
</p> </p>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
{% endblock %}

View file

@ -1,14 +1,18 @@
{% extends "base.html" %} {% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #} {# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %} {% load origin static %}
{% load nomcom_tags %} {% load nomcom_tags %}
{% load ietf_filters %} {% load ietf_filters %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block title %} {% block title %}
NomCom {{ year }} Private NomCom {{ year }} Private
{% block subtitle %}{% endblock %} {% block subtitle %}{% endblock %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% origin %} {% origin %}
{% with selected=request.path|split:'/'|slice:'4:-1'|join:'-' %}
<h1> <h1>
NomCom {{ year }} NomCom {{ year }}
{% if nomcom.group.state_id == 'conclude' %}<span class="badge rounded-pill text-bg-info">Concluded</span>{% endif %} {% if nomcom.group.state_id == 'conclude' %}<span class="badge rounded-pill text-bg-info">Concluded</span>{% endif %}
@ -19,129 +23,140 @@
</h1> </h1>
<ul class="nav nav-tabs my-3"> <ul class="nav nav-tabs my-3">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "index" %}active{% endif %}" <a class="nav-link {% if selected == '' %}active{% endif %}"
href="{% url "ietf.nomcom.views.private_index" year %}"> href="{% url "ietf.nomcom.views.private_index" year %}">
Nominees Nominees
</a> </a>
</li> </li>
{% if nomcom|has_publickey %} {% if nomcom|has_publickey %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "nominate" %}active{% endif %}" <a class="nav-link {% if selected == 'nominate' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.private_nominate' year %}"> href="{% url 'ietf.nomcom.views.private_nominate' year %}">
Nominate Nominate
</a> </a>
</li> </li>
<li class="nav-item"> {% endif %}
<a class="nav-link {% if selected == "feedback" %}active{% endif %}" <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle {% if selected in 'feedback,view-feedback'|split:',' %}active{% endif %}" data-bs-toggle="dropdown" href="#">Feedback</a>
<ul class="dropdown-menu mt-n1" role="menu">
{% if nomcom|has_publickey %}
<li>
<a class="dropdown-item {% if selected == 'feedback' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.private_feedback' year %}"> href="{% url 'ietf.nomcom.views.private_feedback' year %}">
Enter feedback Enter feedback
</a> </a>
</li> </li>
{% endif %} {% endif %}
<li class="nav-item"> <li>
<a class="nav-link {% if selected == "view_feedback" %}active{% endif %}" <a class="dropdown-item {% if selected == 'view-feedback' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.view_feedback' year %}"> href="{% url 'ietf.nomcom.views.view_feedback' year %}">
View feedback View feedback
</a> </a>
</li>
</ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "private_key" %}active{% endif %}" <a class="nav-link {% if selected == 'key' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.private_key' year %}"> href="{% url 'ietf.nomcom.views.private_key' year %}">
Private key Private key
</a> </a>
</li> </li>
{% if user|is_chair_or_advisor:year %} {% if user|is_chair_or_advisor:year %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "feedback_pending" %}active{% endif %}" <a class="nav-link {% if selected == 'view-feedback-pending' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.view_feedback_pending' year %}"> href="{% url 'ietf.nomcom.views.view_feedback_pending' year %}">
Pending emails Pending emails
{% if nomcom.pending_email_count %}<span class="badge rounded-pill text-bg-primary">{{ nomcom.pending_email_count }}</span>{% endif %} {% if nomcom.pending_email_count %}<span class="badge rounded-pill text-bg-primary">{{ nomcom.pending_email_count }}</span>{% endif %}
</a> </a>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">Chair/Advisor Tasks</a> <a class="nav-link dropdown-toggle {% if selected in 'feedback-email,questionnaire-response,extract-email-lists,send-reminder-mail-accept,send-reminder-mail-questionnaire,merge-person,merge-nominee,edit-nomcom,chair-templates,chair-position,chair-topic,edit-members,help'|split:',' %}active{% endif %}" data-bs-toggle="dropdown" href="#">Chair/advisor tasks</a>
<ul class="dropdown-menu mt-n1" role="menu"> <ul class="dropdown-menu mt-n1" role="menu">
{% if nomcom.group.state_id == 'active' %} {% if nomcom.group.state_id == 'active' %}
<li role="presentation" class="dropdown-header">Feedback Management</li> <li role="presentation" class="dropdown-header">Feedback Management</li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.private_feedback_email' year %}">Enter email feedback</a> <a class="dropdown-item {% if selected == 'feedback-email' %}active{% endif %}" href="{% url 'ietf.nomcom.views.private_feedback_email' year %}">Enter email feedback</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.private_questionnaire' year %}">Enter questionnaire response</a> <a class="dropdown-item {% if selected == 'questionnaire-response' %}active{% endif %}" href="{% url 'ietf.nomcom.views.private_questionnaire' year %}">Enter questionnaire response</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.extract_email_lists' year %}">Extract email lists</a> <a class="dropdown-item {% if selected == 'extract-email-lists' %}active{% endif %}" href="{% url 'ietf.nomcom.views.extract_email_lists' year %}">Extract email lists</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.send_reminder_mail' year "accept" %}">Send accept reminder</a> <a class="dropdown-item {% if selected == 'send-reminder-mail-accept' %}active{% endif %}" href="{% url 'ietf.nomcom.views.send_reminder_mail' year "accept" %}">Send accept reminder</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.send_reminder_mail' year "questionnaire" %}">Send questionnaire reminder</a> <a class="dropdown-item {% if selected == 'send-reminder-mail-questionnaire' %}active{% endif %}" href="{% url 'ietf.nomcom.views.send_reminder_mail' year "questionnaire" %}">Send questionnaire reminder</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url "ietf.nomcom.views.private_merge_person" year %}">Request person record merge</a> <a class="dropdown-item {% if selected == 'merge-person' %}active{% endif %}" href="{% url "ietf.nomcom.views.private_merge_person" year %}">Request person record merge</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url "ietf.nomcom.views.private_merge_nominee" year %}">Merge nominee records</a> <a class="dropdown-item {% if selected == 'merge-nominee' %}active{% endif %}" href="{% url "ietf.nomcom.views.private_merge_nominee" year %}">Merge nominee records</a>
</li> </li>
<li><hr class="dropdown-divider"></li>
{% endif %} {% endif %}
<li role="presentation" class="dropdown-header">NomCom configuration</li> <li role="presentation" class="dropdown-header">NomCom configuration</li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.edit_nomcom' year %}">Edit settings</a> <a class="dropdown-item {% if selected == 'edit-nomcom' %}active{% endif %}" href="{% url 'ietf.nomcom.views.edit_nomcom' year %}">Edit settings</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.list_templates' year %}">Edit pages</a> <a class="dropdown-item {% if selected == 'chair-templates' %}active{% endif %}" href="{% url 'ietf.nomcom.views.list_templates' year %}">Edit pages</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.list_positions' year %}">Edit positions</a> <a class="dropdown-item {% if selected == 'chair-position' %}active{% endif %}" href="{% url 'ietf.nomcom.views.list_positions' year %}">Edit positions</a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.list_topics' year %}">Edit topics</a> <a class="dropdown-item {% if selected == 'chair-topic' %}active{% endif %}" href="{% url 'ietf.nomcom.views.list_topics' year %}">Edit topics</a>
</li> </li>
{% if nomcom.group.state_id == 'active' %} {% if nomcom.group.state_id == 'active' %}
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.edit_members' year %}">Edit members</a> <a class="dropdown-item {% if selected == 'edit-members' %}active{% endif %}" href="{% url 'ietf.nomcom.views.edit_members' year %}">Edit members</a>
</li> </li>
{% endif %} {% endif %}
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.configuration_help' year %}">Configuration help</a> <a class="dropdown-item {% if selected == 'help' %}active{% endif %}" href="{% url 'ietf.nomcom.views.configuration_help' year %}">Configuration help</a>
</li> </li>
<li><hr class="dropdown-divider"></li>
<li role="presentation" class="dropdown-header">Other tools</li> <li role="presentation" class="dropdown-header">Other tools</li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.secr.announcement.views.main' %}">Announcement tool</a> <a class="dropdown-item" href="{% url 'ietf.secr.announcement.views.main' %}">Announcement tool</a>
</li>
<li class="dropdown-item">
<a href="https://www.ietf.org/registration/nomcom_chair/nomcomstaff.py">Secretariat private eligibility checker</a>
</li>
<li class="dropdown-item">
<a href="https://www.ietf.org/registration/nomcom.py">Secretariat public eligibility checker</a>
</li> </li>
</ul> </ul>
</li> </li>
{% endif %} {% endif %}
{% if user|is_chair_or_advisor:year or user|has_role:"Secretariat" %} {% if user|is_chair_or_advisor:year or user|has_role:"Secretariat" %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#"> <a class="nav-link dropdown-toggle {% if selected in 'chair-eligible,chair-volunteers'|split:',' %}active{% endif %}" data-bs-toggle="dropdown" href="#">
Volunteers Volunteers
</a> </a>
<ul class="dropdown-menu mt-n1" role="menu"> <ul class="dropdown-menu mt-n1" role="menu">
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.private_eligible' year %}"> <a class="dropdown-item {% if selected == 'chair-eligible' %}active{% endif %}" href="{% url 'ietf.nomcom.views.private_eligible' year %}">
View eligible View eligible
</a> </a>
</li> </li>
<li class="dropdown-item"> <li>
<a href="{% url 'ietf.nomcom.views.private_volunteers' year %}"> <a class="dropdown-item {% if selected == 'chair-volunteers' %}active{% endif %}" href="{% url 'ietf.nomcom.views.private_volunteers' year %}">
View volunteers View volunteers
</a> </a>
</li> </li>
</ul> </ul>
</li> </li>
{% endif %} {% endif %}
<li class="nav-item">
<a class="nav-link"
href="/nomcom/{{ nomcom.year }}">
Public pages &raquo;
</a>
</li>
</ul> </ul>
{% block nomcom_content %}{% endblock %} {% block nomcom_content %}{% endblock %}
{% endwith %}
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
<script> <script>
// Javascript to enable link to tab // Javascript to enable link to tab
var url=document.location.toString(); var url=document.location.toString();

View file

@ -1,21 +1,25 @@
{% extends "base.html" %} {% extends "base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #} {# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %} {% load origin static %}
{% load nomcom_tags %} {% load nomcom_tags %}
{% load ietf_filters %} {% load ietf_filters %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block title %} {% block title %}
NomCom {{ year }} NomCom {{ year }}
{% block subtitle %}{% endblock %} {% block subtitle %}{% endblock %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% origin %} {% origin %}
{% with selected=request.path|split:'/'|slice:'3:-1'|join:'-' %}
<h1> <h1>
NomCom {{ year }} NomCom {{ year }}
{% if nomcom.group.state_id == 'conclude' %}<span class="badge rounded-pill text-bg-info">Concluded</span>{% endif %} {% if nomcom.group.state_id == 'conclude' %}<span class="badge rounded-pill text-bg-info">Concluded</span>{% endif %}
</h1> </h1>
<ul class="nav nav-tabs my-3"> <ul class="nav nav-tabs my-3">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "index" %}active{% endif %}" <a class="nav-link {% if selected == '' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.year_index' year %}"> href="{% url 'ietf.nomcom.views.year_index' year %}">
Home Home
</a> </a>
@ -35,7 +39,7 @@
</li> </li>
{% endif %} {% endif %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if selected == "requirements" %}active{% endif %}" <a class="nav-link {% if selected == "expertise" %}active{% endif %}"
href="{% url 'ietf.nomcom.views.requirements' year %}"> href="{% url 'ietf.nomcom.views.requirements' year %}">
Desired expertise Desired expertise
</a> </a>
@ -48,14 +52,14 @@
</li> </li>
{% if user|is_chair_or_advisor:year or user|has_role:"Secretariat" %} {% if user|is_chair_or_advisor:year or user|has_role:"Secretariat" %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">Volunteers</a> <a class="nav-link dropdown-toggle {% if selected in 'eligible,volunteers'|split:',' %}active{% endif %}" data-bs-toggle="dropdown" href="#">Volunteers</a>
<ul class="dropdown-menu mt-n1" role="menu"> <ul class="dropdown-menu mt-n1" role="menu">
<li class="nav-item"> <li class="nav-item">
<a class="dropdown-item" <a class="dropdown-item {% if selected == 'eligible' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.public_eligible' year %}">View eligible</a> href="{% url 'ietf.nomcom.views.public_eligible' year %}">View eligible</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="dropdown-item" <a class="dropdown-item {% if selected == 'volunteers' %}active{% endif %}"
href="{% url 'ietf.nomcom.views.public_volunteers' year %}">View volunteers</a> href="{% url 'ietf.nomcom.views.public_volunteers' year %}">View volunteers</a>
</li> </li>
</ul> </ul>
@ -63,8 +67,10 @@
{% endif %} {% endif %}
</ul> </ul>
{% block nomcom_content %}{% endblock %} {% block nomcom_content %}{% endblock %}
{% endwith %}
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
<script> <script>
$(document) $(document)
.ready(function () { .ready(function () {

View file

@ -2,9 +2,6 @@
{# Copyright The IETF Trust 2015-2020, All Rights Reserved #} {# Copyright The IETF Trust 2015-2020, All Rights Reserved #}
{% load origin static %} {% load origin static %}
{% block subtitle %}- Administration{% endblock %} {% block subtitle %}- Administration{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block nomcom_content %} {% block nomcom_content %}
{% origin %} {% origin %}
<h2 class="mt-3">Nomination status</h2> <h2 class="mt-3">Nomination status</h2>
@ -251,7 +248,4 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endblock %}
{% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
{% endblock %} {% endblock %}

View file

@ -3,9 +3,6 @@
{% load origin static %} {% load origin static %}
{% load nomcom_tags %} {% load nomcom_tags %}
{% block subtitle %}- View feedback{% endblock %} {% block subtitle %}- View feedback{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block nomcom_content %} {% block nomcom_content %}
{% origin %} {% origin %}
<h2 class="mt-3">Feedback related to nominees</h2> <h2 class="mt-3">Feedback related to nominees</h2>
@ -113,7 +110,4 @@
</tbody> </tbody>
</table> </table>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
{% endblock %}

View file

@ -1,12 +1,9 @@
{% extends public|yesno:"nomcom/nomcom_public_base.html,nomcom/nomcom_private_base.html" %} {% extends public|yesno:"nomcom/nomcom_public_base.html,nomcom/nomcom_private_base.html" %}
{# Copyright The IETF Trust 2021, All Rights Reserved #} {# Copyright The IETF Trust 2021, All Rights Reserved #}
{% load origin %} {% load origin %}
{% load django_bootstrap5 textfilters person_filters %} {% load django_bootstrap5 textfilters person_filters ietf_filters%}
{% load static %} {% load static %}
{% block subtitle %}- Volunteers{% endblock %} {% block subtitle %}- Volunteers{% endblock %}
{% block pagehead %}
<link rel="stylesheet" href="{% static "ietf/css/list.css" %}">
{% endblock %}
{% block nomcom_content %} {% block nomcom_content %}
{% origin %} {% origin %}
<h2>Volunteers for {{ nomcom.group }}</h2> <h2>Volunteers for {{ nomcom.group }}</h2>
@ -34,7 +31,7 @@
{% for v in eligibility_group.list %} {% for v in eligibility_group.list %}
<tr> <tr>
<td>{{ forloop.counter }}</td> <td>{{ forloop.counter }}</td>
<td>{{ v.person.last_name }}</td> <td>{{ v.person.last_name|split:'+'|join:'+<wbr>' }}</td>
<td>{{ v.person.first_name }}</td> <td>{{ v.person.first_name }}</td>
<td>{{ v.person.ascii_name }}</td> <td>{{ v.person.ascii_name }}</td>
<td>{% person_link v.person %}</td> <td>{% person_link v.person %}</td>
@ -46,7 +43,4 @@
</tbody> </tbody>
</table> </table>
{% endfor %} {% endfor %}
{% endblock %}
{% block js %}
<script src="{% static "ietf/js/list.js" %}"></script>
{% endblock %} {% endblock %}

View file

@ -21,7 +21,6 @@
</p> </p>
<ul> <ul>
<li>Only XML-only uploads are supported, not text or combined.</li> <li>Only XML-only uploads are supported, not text or combined.</li>
<li>Document replacement information cannot be supplied.</li>
<li> <li>
The server expects <code>multipart/form-data</code>, supported by <code>curl</code> but <b>not</b> by <code>wget</code>. The server expects <code>multipart/form-data</code>, supported by <code>curl</code> but <b>not</b> by <code>wget</code>.
</li> </li>

Some files were not shown because too many files have changed in this diff Show more