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"