Theme/staff admin workflows - #531
Closed
gauravmyana2002 wants to merge 2052 commits into
Closed
gauravmyana2002 wants to merge 2052 commits into
gauravmyana2002 wants to merge 2052 commits into
Conversation
@angular/build, @angular/cli and ngx-monaco-editor-v2-alternative were pinned to exact versions. In a change whose purpose is remediating audit findings that is the wrong direction: it stops the next patch release arriving and stops a later npm audit fix from taking it, and @angular/build is one of the packages carrying an advisory on the base branch. Restored as ^22.0.9, ^22.0.9 and ^22.0.0. The resolved versions in the lockfile are unchanged and still satisfy the ranges, so nothing is upgraded here. The root declaration in package-lock.json is updated to match, which is what npm ci compares against. The exact dompurify pin inside overrides is deliberate and is left alone. npm audit on origin/11.0.x: 12 total, 4 high, 5 moderate, 3 low. npm audit with this branch: 0.
…y-integration-prs-20260826 ci: add weekly integration PR automation
…on-submission-only-20260826 fix: only reset dashboard after completed submission
project-dashboard.component.spec.ts came out as add/add. 11.0.x gained one via #96 covering task selection, this branch has one covering route reuse. Kept both, the describe names were already distinct. The merge also broke the build in a way neither side could see on its own. #96 added taskService as the third constructor parameter of ProjectDashboardComponent, and this branch's spec constructs the component directly rather than through TestBed, so all three call sites were passing six arguments to a seven argument constructor: TS2554: Expected 7 arguments, but got 6. An argument for 'breakpointObserver' was not provided. Added a TaskService stub in third position at each of them. It only needs taskSubmissionCompleted$, since that is the one member ngOnInit subscribes to, so a bare Subject is enough and the tests stay about routing. ng test --include **/project-dashboard.component.spec.ts: 6 passed.
…260824 fix(deps): resolve inherited npm audit findings
….x-all-features-20260824 release(web): OnTrack 11.0.x all-features handover
…-mvp-20260827 # Conflicts: # src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.spec.ts
The target grade selector lost its static disabled attribute, so it was live for anyone viewing the dashboard, staff included, and the API permits the change because tutors hold :change on a project. The component already computes viewingOtherStudentProject, so the guard uses that. The Task Planner carried the same unguarded selector and now matches. Deselecting had moved into applyFilters, which is bound to the search box, so every keystroke closed the open task and rewrote the URL, losing an unsent comment with it. It now only deselects when the open task has gone or a view filter hides it. Hiding tasks above the target grade is counted by the filter badge, and a task with unread comments stays visible the way the hide-completed filter already allows, so tutor feedback cannot disappear behind the new default.
Swapping first() for takeUntil made the subscription permanent, which is what unit switching needs. It also meant every emission re-ran activateProject, which resets projectReady and clears the selected task. The portfolios progress tab re-emits on every change detection pass, because its taskSelectionUrlBase getter returned a new array each call and ngOnChanges pushed into the project subject unconditionally. The tab reset itself continuously. activateProject now returns early when the project is already the active one, the url base is memoised, and ngOnChanges only pushes when the project input actually changed.
contrastingTextColor left the always-rendered Awaiting Feedback card at 4.44:1, under the 4.5:1 AA wants for normal text. The dark foreground moves to #000000 and the dark-contrast divisor now matches it. The hidden-series legend pill fell to 2.97:1 while still being an interactive control, which misses the 3:1 in 1.4.11. It uses an explicit dimmed state rather than an opacity. Hiding a series zeroed its values instead of removing it, so the pill read as off while the chart still drew the entry. Hidden series are filtered out of the data. The clipping guard asserted a removed class string, so it could not fail for the right reason. It reads computed maxHeight and overflow instead.
…layout refactor(layout): standardise the grid & container layout (doubtfire-lms#1208)
One conflict, in project-plan.component.html. 11.0.x rewrapped the page in f-page-container while this branch added aria-label and the disabled binding to the target grade selector. Both are kept: the resolution takes the 11.0.x layout and grafts the two mat-select attributes onto it. project-plan.component.spec.ts finds the selector by its aria-label under NO_ERRORS_SCHEMA, so it does not depend on the wrapper either way. It still passes, as does project-card.component.spec.ts, prettier and ng lint.
…rack-mvp-20260827 Validate and hand over the OnTrack Web MVP streams
Adds docs/theme/THEME-CONTRACT.md, the contract THM-F01 through THM-M05 build against. It fixes the three stored preference states and the two resolved ones, the data-ot-theme marker on <html>, the ontrack.theme.preference key and its allowlist, the semantic --ot-* token set with a light and a dark value for every role, the split between fixed brand colour and theme-aware colour, the WCAG AA floor, and the rules for no-flash startup, live operating-system changes, reduced motion and print. The feature is specified in two phases so that every card on the board has something to build. Phase one stores the preference in localStorage. Phase two, section 6.2, adds the user account as a second store and settles how the two reconcile: local is always the boot store, the account carries the stored preference and never the resolved theme, conflicts go to whichever side was written last, a device with no local value adopts the account value, and the sync never blocks startup. Section 10 configures the Tailwind dark variant against the same root marker rather than banning the prefix, because an unconfigured darkMode is not an absent dark variant, it is one that silently follows the operating system and ignores the stored preference. Section 2 audits the current stylesheet, because THM-D01 has not started and there was no register to work from. Every count has the command printed beside it and Appendix B collects them for re-running. Every contrast ratio is computed with the formula in Appendix A rather than estimated, and all seventy-five were recomputed in one pass before this was handed over. The audit found that eight of thirteen distinct status chip colour pairs already fail AA in light mode, and that task status colour has two sources of truth that agree by hand. Section 8.1 lifts every failing pair to 4.5:1 while leaving thirteen of fifteen fills alone. No code, no styles and no configuration change. The document stays a draft until the four approvals in section 17 are recorded.
THM-MVP01 validates the finished Theme Support MVP objective. The objective has not started, so this file is the instrument the validation will be run from and not a record of one. The title, the first line and the head of every results section say so, because a document made of empty tables is easy to mistake for a document somebody forgot to fill. Every result cell reads NOT RUN and every empty list carries a placeholder row, so the blank state is visibly deliberate. The dependency register is dated. On 27 August 2026 all seventeen THM tickets and the two migration tickets are Not started, and the file carries the commands that show it: no branch matching theme, thm or dark on any of the four org repositories, 0 of 160 heads, and no pull request with a theme head or title in any state, 0 of 210. Nothing in the register is overdue, the earliest due date is 9 September. All eighteen register rows were machine compared against the board a second time after the rebase and none of them moved. Everything that would cite the DOM marker, the storage key or the theme enum is marked as depending on THM-D02, which is Not started. Its contract document is absent from every one of the 81 branches on origin. A draft is committed on a local branch that was never pushed, so nobody else can read it and this plan does not quote it. Those three things are named by role and never by value, so nobody substitutes a guess. The check that proves the contract is missing now walks every head rather than 11.0.x alone, because the one branch version did not support the sentence it was cited for. The scheduling clash stays. THM-MVP01 is due 20 September and THM-JL01, THM-D01, THM-F02 and THM-Q01 are due the same day. Dates and statuses only, no fault attached to anyone. No application code changes. Built against doubtfire-web 11.0.x at 4034e7d. The four npm scripts the plan names, lint, typecheck, test:ci and build, all exist in package.json on that commit.
Rebases onto the closure merge of PR #105 and fixes four things review found, plus three more the re-audit turned up. The audit was taken on efda579 at 09:24. The closure branch landed at 22:00 the same day and moved nine of the counts, so every Appendix B command was re-run and every number re-derived on the new base. The loose hex literals under src/app went 105 to 226, which matters because section 10 quotes that figure as the migration baseline for another card. Two files new to this base carry 94 of the 226 between them. What did not move is recorded too: the three palette files, all 15 status colours and every contrast ratio in sections 7, 8 and appendix A were re-checked and are unchanged, so the token tables stand as written. Section 15 claimed the theme is not sent to Google Analytics and cited src/index.html:6-14. There is no Google Analytics in this app. No GA, no tag manager, no analytics package in package.json, and those lines are the Google Fonts stylesheet links. Replaced with the greps that show the absence and with Sentry, which is real and is the reporter the bullet should have been about. Section 12 cited src/index.html:34 for the theme-color meta. It is at line 24; line 34 is a respond.js shim behind an IE conditional comment. Section 6.2 rule 3 left the case that decides the whole feature undefined: a valid local preference, no updatedAt key, and an account field that has never been written. That is not an edge case, it is day one of THM-B01 for every existing user, because phase one never writes the timestamp key. Read naively the rule discarded the local value and reset everyone to system. Now settled as a four-row table where presence beats recency and timestamps are only consulted when both sides hold a value, with the two intended consequences spelled out and a test for each row added to section 14. The Angular Material line citation for rejecting option B could not be checked because node_modules is not installed here, so the line numbers are dropped rather than left unverifiable. The argument does not depend on them. Section 2.3's palette reference is marked the same way, with the four flattened values shown to be reproducible without it. Three more from the re-audit. The burndown chart palette moved and its fifth slot changed from transparent to a real colour. The localStorage key convention moved and now has a second call site. And the focus counts read level at 11 against 11 where they were 11 against 7, which looks like an improvement and is not: only one of the ten files that suppress an outline declares a focus-visible rule, so nine still have no replacement ring. Appendix B now carries the commands for the section 2.4 palette split and remainder, the focus-set overlap, the custom-property count, the template file count and the analytics check, so every number in the document has a command beside it. Each one was run and matches.
(cherry picked from commit e1abb68)
Improved clarity in the user guide. (cherry picked from commit 67e732c)
Seven templates gated an action or an explanation on (mouseover) and (mouseout) alone, so a keyboard user could never reach what the pointer revealed. mouse-events-have-key-events moves from off to error, which catches the bare case where a hover handler has no keyboard counterpart at all. That rule is a floor and not a guarantee, so it is worth being precise about what it does and does not stop. Its selector is Element:has(BoundEvent[mouseover]):not(:has(BoundEvent[focus])), and :has matches descendants, so an element can keep (mouseover) and (mouseout) with no keyboard equivalent of its own and still lint clean off a nested control's (focus). It also never checks that whatever takes focus is reachable, so a div carrying (focus) and no tabindex passes. The rule stops the pattern being reintroduced bare. The tests added here are what hold these particular fixes in place. Where the reveal hid a control, it is done with opacity now rather than display or [hidden]. Both of those take the control out of the tab order, so :focus-within can never become true and the focus path is shut before it starts. staff-notes, tutor-notes and task-comments-viewer show their actions on :hover or :focus-within of the surrounding card, and those actions are real buttons instead of mat-icon elements carrying a click handler, so there is something in the tab order for :focus-within to answer to. The staff task inbox keeps its options button in the tab order, stacked over the pin indicator and revealed on row hover or on its own focus. Pointer and keyboard hold the row open independently, so tabbing off the button no longer fades it out from under a pointer still on the row. The row div is one of the cases described above: it keeps (mouseover) and (mouseout) and depends on that nested options button for its keyboard path, which is a real path rather than a lint technicality. The pin beside that button is no longer a button itself. It reports whether a task is pinned and has no action, so it was an unlabelled tab stop on every row and empty on the rows that were not pinned. Worse, it was hidden whenever the adjacent options button took focus, so a forward tab landed on it while a shift-tab skipped it and the row's tab order read differently in each direction. It is a div with role="img" and a label now, and it is out of the tab order in both directions. The planner's gantt bar carries role="button" and tabindex="0", so the (focus) binding on it can actually fire, and Enter and Space open the prerequisites modal the way a click does. Its focus outline is drawn in currentColor, which is already picked per bar to contrast with that bar's own background. The planner spec blanks the component template, so those attributes were previously unguarded by any test. It now holds the #bar TemplateRef and stamps that template directly, because ngx-gantt sizes the chart from real layout and draws no bars under jsdom. Deleting role, tabindex or either keydown binding fails those tests. tutor-discussion wrote task.hover from its mouse handlers and fed it to an [ngClass] with no matching .hover rule in that component's stylesheet, so the path was a no-op before and after. It is removed rather than left looking like it does something, and allowHover goes with it since nothing there ever set it false. hoveredCommentId in the engagement dialog was likewise only ever written and never read. Three rule ignores are left in the config, covering keyboard activation and focus for click handlers elsewhere in the app. Clearing them is A11Y-F03 and A11Y-F04.
…le-form refactor: replace flex-layout with tailwindcss in edit profile form
refactor: replace flex-layout with tailwindcss in audio player
refactor: replace flex-layout with tailwindcss in admin users
refactor: replace flex-layout with tailwindcss in header
refactor: replace flex-layout with tailwindcss in edit profile
…endar-2026-09 feat(calendar): land CAL-F07, F08, F09 and PR-CAL-14 on 11.0.x
FEPERF-20: Optimise comment cache reconciliation
…ixed-20260914 fix(a11y): label the task badges used by students
Both unit dropdowns bound [value] on the select, but their options are created later by @for, so the browser kept the first option selected. A staff member managing two units could see SIT111 in Manage updates while saves went to SIT222, and the filter showed All my units for ?unit=222. Mark the matching option as selected and add a regression spec that holds the reload open until the options re-render. Also open a Teams draft for a session saved without a description. The API returns null for it, which the plain text check rejected as too long.
…nnouncements-sessions feat: centralize unit updates, Teams meetings and study essentials
Bumps [hono](https://github.com/honojs/hono) from 4.13.3 to 4.13.7. - [Release notes](https://github.com/honojs/hono/releases) - [Commits](honojs/hono@v4.13.3...v4.13.7) --- updated-dependencies: - dependency-name: hono dependency-version: 4.13.7 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
The old base feature/peer-progress-indicator is already on 11.0.x in a newer form, so every conflicted peer progress file takes the 11.0.x version. The only change left is outputHashing in angular.json.
…and_yarn/hono-4.13.7 chore(deps): bump hono from 4.13.3 to 4.13.7
…ogress-indicator-JE-live chore(web): enable outputHashing=all for production caching
fix(a11y): two empty states are a single aria-hidden icon with no text
…ailwind refactor: replace ng-flex-layout with Tailwind in task-viewer-state
First slice of THM-M03 (tutor/unit-chair/admin workflow theming), covering checklist item 2: the task inbox / marking queue tutors use to review and assess submissions (inbox.component, staff-task-list.component, moderation.component, inbox-dashboard.component). Migrates every hardcoded colour in these four components onto the THM-M01 token layer (--ot-color-*), following the exact pattern THM-M01 established in header.component.scss: var(--ot-color-X, <original-light-value>), so light mode is pixel-identical and only dark mode changes. One exception needed a real override rather than a token swap: staff-task-list's --background-gray (a hover/selected row tint) is an rgba(black) value that reads correctly in light but would be nearly invisible or wrong-direction on a dark surface, so it gets a :host-context([data-ot-theme='dark']) override to an rgba(white) tint instead. Also migrates the four Tailwind arbitrary-hex classes and one inline style in inbox-dashboard's empty states (the icons/text shown when no task is selected, or a task has no PDF/task sheet) onto the same tokens via Tailwind's var() arbitrary-value syntax. Adds a focused spec for InboxDashboardComponent (previously untested) that asserts the empty-state icon and message carry the token class rather than a bare hex, verified to fail against the pre-migration classes and pass after. Checklist items 1, 3-10 (route confirmation beyond this surface, student lists, unit/task editors, staff reports, dense-table/nav/narrow-layout checks, and the remaining marking-queue sub-surfaces - task-claim, confirm-moderation-modal, batch-feedback-workflow-dialog) are follow-up work, not covered by this PR. No business, permission, or marking-transition logic changed - colour/class values only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Draft PR — this is a first, verified slice of THM-M03, not the complete ticket. Opening now given the due date, with the remaining scope filed as follow-up tickets rather than holding this back.
Migrates every hardcoded colour in the task inbox / marking queue —
inbox.component,staff-task-list.component,moderation.component,inbox-dashboard.component— onto the--ot-color-*token layer established by THM-M01. This is THM-M03 checklist item 2 ("marking queues, task assessment panels") and the surface the ticket's own purpose statement calls out as highest-stakes: "poor contrast could cause incorrect decisions."Every substitution follows THM-M01's own pattern exactly (
var(--ot-color-X, <original-light-hex>)), so light mode is pixel-identical — only dark mode changes. One exception needed a real override rather than a token swap:staff-task-list's--background-gray(a hover/selected-row tint) isrgba(0,0,0,0.04), which reads fine in light but would be nearly invisible or wrong-direction on a dark surface, so it gets a:host-context([data-ot-theme='dark'])override to anrgba(255,255,255,0.06)tint instead. Also migrates four Tailwind arbitrary-hex classes and one inline style ininbox-dashboard's empty states onto the same tokens, via Tailwind'svar()arbitrary-value syntax.No dependencies required for this change.
Branch and commit combination:
theme/staff-admin-workflows@29fc4b683, branched fromorigin/11.0.x@518abe8f1feature/peer-progress-indicator@5af61f965fix/local-dev-run@89a999abfNot covered by this PR (filed as follow-up scope, not silently dropped): route confirmation beyond this surface (THM-D01 doesn't exist yet, self-audited from
app.routes.tsinstead), student lists, task lists, group views, extension/date controls, unit-chair decision surfaces, unit/task/rubric/learning-outcome/feedback-template editors, staff reports/analytics/filters/bulk actions, dense-table/nav/narrow-layout checks, and the rest of the marking queue itself (task-claim,confirm-moderation-modal,batch-feedback-workflow-dialog).Fixes # (ticket THM-M03, tracked on the team Planner board — no linked GitHub issue)
Type of change
How Has This Been Tested?
npx ngc -p src/tsconfig.app.json --noEmit— clean.npx eslint <touched files> --max-warnings 0— clean.npx ng test --no-watch --include=<4 touched spec files>— 25/25 pass.npx ng build— succeeds.Added a new spec for
InboxDashboardComponent(previously untested) asserting the empty-state icon/message carry the token class rather than a bare hex. Verified it fails against the pre-migration markup (expected '...text-[#c5c5c5]' to contain 'var(--ot-color-text-muted,#c5c5c5)') and passes after the fix.Not covered by automated tests: actual rendered appearance in Light/Dark. jsdom doesn't evaluate CSS custom-property resolution across global stylesheets, so the tests confirm the correct token is wired in, not what it looks like. Docker's local database was reset today by an unrelated crash, so Light/Dark screenshots haven't been captured yet — flagging this honestly rather than skipping it silently.
Testing Checklist:
Checklist: