Add task category feature with predefined priority levels#17
Conversation
Agent-Logs-Url: https://github.com/CleveritDemo/copilot-agentic-workshop/sessions/45903273-402d-4046-b20a-435173c49255 Co-authored-by: rtraidcleverit <169684453+rtraidcleverit@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a predefined “category/priority” field for tasks (Low/Medium/High) across the backend API and the vanilla JS frontend, including UI controls and styling for category badges.
Changes:
- Backend: adds
categorysupport on task creation (defaulting toMedium) and task updates. - Frontend: adds a category
<select>in the task form and sends the selected category when creating tasks. - UI: adds CSS variables and badge styles to visually distinguish categories in both light/dark themes.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| backend/controllers/tasksController.js | Persists category on create and update endpoints. |
| frontend/index.html | Adds a category dropdown to the create-task form. |
| frontend/script.js | Sends category on create and renders a category badge per task. |
| frontend/style.css | Adds theme variables and styles for the category select + category badges. |
| const { title, completed = false, category = 'Medium' } = req.body; | ||
| const newTask = { id: uuidv4(), title, completed, category }; |
There was a problem hiding this comment.
category is accepted directly from req.body without validation/normalization. Since the UI and frontend rendering assume one of Low|Medium|High, storing arbitrary values can lead to inconsistent data and (because the frontend interpolates task.category into HTML/class attributes) potential XSS. Consider enforcing an allowlist (case-insensitive), defaulting to Medium, and returning 400 for invalid values.
There was a problem hiding this comment.
Applied in commit d7112dc. The changes address all four review points:
- Backend
createTask: Added aVALID_CATEGORIESallowlist (['Low', 'Medium', 'High']); category is now normalized (case-insensitive) and returns 400 for any value not in the list. - Backend
updateTask: Same allowlist validation applied whencategoryis present in the request body. - Frontend XSS fix:
addTaskToDOMnow usescreateElement,textContent,classList, andaddEventListenerinstead ofinnerHTML, eliminating injection risk. - Accessibility: Added
aria-label="Task priority category"to the<select>element so screen readers announce it properly.
| task.title = req.body.title ?? task.title; | ||
| task.completed = req.body.completed ?? task.completed; | ||
| task.category = req.body.category ?? task.category; |
There was a problem hiding this comment.
updateTask allows updating task.category to any arbitrary value from req.body.category with no validation. If categories are meant to be predefined (Low|Medium|High), reject invalid inputs (400) and/or normalize case to avoid persisting unexpected values.
| const categoryClass = `category-${task.category ? task.category.toLowerCase() : 'medium'}`; | ||
| li.innerHTML = ` | ||
| <span class="${task.completed ? 'completed' : ''}">${task.title}</span> | ||
| <div> | ||
| <div class="task-actions"> | ||
| <span class="category-badge ${categoryClass}">${task.category || 'Medium'}</span> | ||
| <button onclick="toggleComplete('${task.id}', ${!task.completed})">✓</button> | ||
| <button onclick="deleteTask('${task.id}')">✕</button> |
There was a problem hiding this comment.
addTaskToDOM interpolates task.category into both an element’s class attribute and its inner HTML via innerHTML. If a task is created/updated with a malicious category value (backend currently allows arbitrary strings), this can break markup and enable XSS. Prefer building the DOM with textContent/classList and mapping category values to a known set of CSS classes rather than concatenating raw values into HTML.
| <select id="categorySelect" title="Select task priority category"> | ||
| <option value="Low">Low</option> | ||
| <option value="Medium" selected>Medium</option> | ||
| <option value="High">High</option> | ||
| </select> |
There was a problem hiding this comment.
The new <select> relies on title for its accessible name, but title is not a reliable label for screen readers. Add an explicit <label for="categorySelect">…</label> or at least an aria-label/aria-labelledby so the control is properly announced.
Agent-Logs-Url: https://github.com/CleveritDemo/copilot-agentic-workshop/sessions/eb1004a7-8803-4b08-b25d-12e6670f275a Co-authored-by: rtraidcleverit <169684453+rtraidcleverit@users.noreply.github.com>
createTask(return 400 for invalid values, normalize case)updateTask(return 400 for invalid values, normalize case)addTaskToDOMby using DOM methods instead ofinnerHTMLaria-labelto the category<select>in index.html for accessibility