diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1117e60..afaab59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,9 +16,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.x + with: + persist-credentials: false - - uses: actions/setup-python@v7 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.x with: python-version: "3.12" diff --git a/src/server/templates/admin.js b/src/server/templates/admin.js index fee9ff4..53fcfe3 100644 --- a/src/server/templates/admin.js +++ b/src/server/templates/admin.js @@ -81,8 +81,9 @@ function buildAddItemSelect(availableMeals) { availableMeals.forEach(m => { const opt = document.createElement('option'); + const price = m.price || 0; opt.value = m.name; - opt.textContent = m.name + ' ($' + m.price.toFixed(2) + ')'; + opt.textContent = m.name + ' ($' + price.toFixed(2) + ')'; select.appendChild(opt); }); diff --git a/src/server/templates/form.js b/src/server/templates/form.js index a8eff56..39f10ef 100644 --- a/src/server/templates/form.js +++ b/src/server/templates/form.js @@ -31,16 +31,6 @@ let mealsListDelegationBound = false; window.googleCredential = null; -function escapeHtml(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); -} - function employeePrice(retail) { if (!retail) return 0; const bulkPrice = Math.round(retail * (1 - BULK_DISCOUNT / 100) * 100 + 1e-8) / 100; @@ -48,7 +38,7 @@ function employeePrice(retail) { return empPrice; } -window.FormUtils = { escapeHtml, employeePrice }; +window.FormUtils = { employeePrice }; function syncGoogleCredential() { window.googleCredential = googleCredential; @@ -374,33 +364,26 @@ async function submitOrder() { } async function loadRoster() { + let employees = ROSTER; try { const res = await fetch(ROSTER_URL); const data = await res.json(); - const select = document.getElementById('emp-name'); - select.innerHTML = ''; - (data.employees || ROSTER).forEach(emp => { - const opt = document.createElement('option'); - opt.value = emp.name; - opt.dataset.email = emp.email; - opt.textContent = emp.name; - select.appendChild(opt); - }); - select.addEventListener('change', () => { - const selected = select.options[select.selectedIndex]; - document.getElementById('emp-email').value = selected?.dataset?.email || ''; - }); - } catch (e) { - const select = document.getElementById('emp-name'); - select.innerHTML = ''; - ROSTER.forEach(emp => { - const opt = document.createElement('option'); - opt.value = emp.name; - opt.dataset.email = emp.email; - opt.textContent = emp.name; - select.appendChild(opt); - }); - } + employees = data.employees || ROSTER; + } catch (e) {} + + const select = document.getElementById('emp-name'); + select.innerHTML = ''; + employees.forEach(emp => { + const opt = document.createElement('option'); + opt.value = emp.name; + opt.dataset.email = emp.email; + opt.textContent = emp.name; + select.appendChild(opt); + }); + select.addEventListener('change', () => { + const selected = select.options[select.selectedIndex]; + document.getElementById('emp-email').value = selected?.dataset?.email || ''; + }); } function showClosedOverlay() { diff --git a/tests/test_generate_form.py b/tests/test_generate_form.py index 05d4b93..d9a1b0b 100644 --- a/tests/test_generate_form.py +++ b/tests/test_generate_form.py @@ -206,33 +206,38 @@ class TestGenerateFormPlaywright: "Chromium is required for form Playwright tests. " "Run: playwright install --with-deps chromium" ) from exc - page = browser.new_page() - page.route( - "**/api/form-status/**", - lambda route: route.fulfill( - status=200, - content_type="application/json", - body='{"status":"open"}', - ), - ) - page.route( - "**/api/roster**", - lambda route: route.fulfill( - status=200, - content_type="application/json", - body=json.dumps( - { - "employees": [ - {"name": "Ada Lovelace", "email": "ada@example.com"} - ] - } + try: + page = browser.new_page() + page.route( + "**/api/form-status/**", + lambda route: route.fulfill( + status=200, + content_type="application/json", + body='{"status":"open"}', ), - ), - ) - page.goto(out.as_uri()) - page.wait_for_selector('[data-meal-index="0"]') - yield page - browser.close() + ) + page.route( + "**/api/roster**", + lambda route: route.fulfill( + status=200, + content_type="application/json", + body=json.dumps( + { + "employees": [ + { + "name": "Ada Lovelace", + "email": "ada@example.com", + } + ] + } + ), + ), + ) + page.goto(out.as_uri()) + page.wait_for_selector('[data-meal-index="0"]') + yield page + finally: + browser.close() def test_admin_bundle_loads(self, browser_page): assert browser_page.evaluate("typeof window.loadWeekOrders") == "function"