Skip to content

Feature/uxp e02 students empty - #521

Closed
David-Tenni wants to merge 1884 commits into
thoth-tech:developmentfrom
ontrack-features-t2-2026:feature/UXP-E02-students-empty
Closed

Feature/uxp e02 students empty#521
David-Tenni wants to merge 1884 commits into
thoth-tech:developmentfrom
ontrack-features-t2-2026:feature/UXP-E02-students-empty

Conversation

@David-Tenni

Copy link
Copy Markdown

Jira ticket

UXP-E02

Summary

Replaces the bare "No students were found using the filters specified." text in the students list table with the shared f-empty-state component (search_off icon), matching the pattern from UXP-E01.

Target branch

feature/ui-polish

Testing

tsc --noEmit, prettier --check, and eslint all pass on the changed files. Added a discriminating spec that asserts f-empty-state renders when the filtered list is empty and disappears once a row is present. Build and full test suite run in CI.

Built and tested against:

  • doubtfire-web: feature/UXP-E02-students-empty @ 90dcd11
  • doubtfire-api: @
  • doubtfire-deploy: @

Security and privacy

No known security or privacy impact. Presentational component only; no data model or API change, no student data.

Evidence

After screenshot of the students-list empty state attached below.

Checklist

  • I selected the correct base branch.
  • My changes match the assigned Jira ticket.
  • I kept the change within the agreed scope.
  • I tested my changes.
  • I did not include passwords, tokens, API keys, secrets, or real student data.
  • I updated relevant documentation, or no documentation change was needed.
  • I reviewed my own changes before requesting review.

jayfshrimpton and others added 30 commits August 20, 2026 20:15
Co-authored-by: Cursor <cursoragent@cursor.com>
…s page

Completes IN-05. Web PR #28 added bulk actions to the header dropdown
only, and the dropdown is hidden at the xs breakpoint, so on a phone
there was no way to clear or delete a notification at all.

Adds a Mark all read control, a per-row delete behind a confirmation
dialog, and screen reader labels naming the notification being deleted.
The delete button is a sibling of the row rather than nested inside it,
because a button inside a button is not valid html and the browser
unnests them.

Also handles the cases that only show up in use: marking all read is not
offered when nothing is unread, a failed delete keeps the row, deleting
the last row on the last page pulls the reader back a page, and a list
read still in flight is dropped when either action fires so a stale
response cannot overwrite the list or strand a spinner.

Tests: 15 new cases, taking the notifications page spec
Full web suite 64 files, 227 tests, 0 failures.

Built against doubtfire-web feature/notifications f5c4b5b,
doubtfire-api feature/notifications d3be7c79f, and doubt
11.0.x 5d2c8b409.
11.0.x split doubtfire-constants.ts into loadPublicSettings(), which runs
pre-auth through HttpBackend, and applyAuthenticatedSettings(), which
authentication.service.ts calls once a token exists.

IsPushEnabled and VapidPublicKey move into applyAuthenticatedSettings. They
used to be read at bootstrap from the unauthenticated /settings, and GET
/settings is authenticated on 11.0.x, so leaving them at bootstrap would
have left push permanently off with nothing on screen to explain why.

The two fields are optional on AuthenticatedSettingsResponseFormat so the
web can run against an API that has not taken the api-side change yet, and
so doubtfire-constants.spec.ts still type checks.

Built against doubtfire-web feature/notifications f5c4b5b merged with
11.0.x 6b82a61, doubtfire-api feature/notifications d3be7c79f, and
doubtfire-deploy 11.0.x 5d2c8b409.
…rd (CPD-Q06)

* docs: add privacy-safe screenshot checklist for Cross-Project Dashboard (CPD-Q06)

(cherry picked from commit df15f62)

* docs: strengthen screenshot redaction guidance (CPD-Q06)

---------

Co-authored-by: jmirchh75 <jmirch@live.com>
* Add GitHub Actions workflow to notify Teams on PRs

* fix(ci): gate the Teams notifier and harden its payload

Adds a job guard so the webhook is unreachable from anonymous fork pull
requests on these public repositories, and so the file is inert if it ever
travels to thoth-tech or doubtfire-lms.

Adds reopened and ready_for_review, which is the transition a reviewer alert
exists to catch, and varies the headline per action so it stays accurate.

Strips Markdown link and code syntax from the title, author and head label
before they reach the channel. Joins on a double newline, which is what Teams
renders as a break. Reports the real HTTP status instead of asserting a
delivery the workflow never checked.

---------

Co-authored-by: Clupai8o0 <clupaio4@gmail.com>
Refactor Teams notification to use Adaptive Card
Bumps  and [brace-expansion](https://github.com/juliangruber/brace-expansion). These dependencies needed to be updated together.

Updates `brace-expansion` from 5.0.6 to 5.0.9
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](juliangruber/brace-expansion@v5.0.6...v5.0.9)

Updates `brace-expansion` from 5.0.7 to 5.0.9
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](juliangruber/brace-expansion@v5.0.6...v5.0.9)

Updates `brace-expansion` from 2.1.1 to 2.1.4
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](juliangruber/brace-expansion@v5.0.6...v5.0.9)

---
updated-dependencies:
- dependency-name: brace-expansion
  dependency-version: 5.0.9
  dependency-type: indirect
- dependency-name: brace-expansion
  dependency-version: 5.0.9
  dependency-type: indirect
- dependency-name: brace-expansion
  dependency-version: 2.1.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [ip-address](https://github.com/beaugunderson/ip-address) from 10.2.0 to 10.5.0.
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](beaugunderson/ip-address@v10.2.0...v10.5.0)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Simplified the conditional check for PR notifications.
…n-click

feat(notifications): navigate on push notification click
…anage focus

Mark all read had no success handler, so the only feedback was rows losing
their bold and a dot going grey. It now announces through AlertService.

The button also moved from @if to disabled, but a native disabled attribute
does not solve the focus problem it was meant to: a natively disabled button
cannot hold focus either, so the browser drops it to the body just the same.
disabledInteractive is Material's input for exactly this, buttons that become
disabled when activated. It announces via aria-disabled and stays focusable,
so markAllRead re-checks hasUnread rather than trusting the binding. The block
stays inside an @if on the list length so a greyed control never sits over the
loading, failed or empty states.

The confirmation dialog closes as soon as it is agreed to and the row is not
dropped until the response lands, so the same delete could be confirmed twice
and the second request 404s. Ids with a request in the air are held and the
button marked disabled, with disabledInteractive again so MatDialog can still
restore focus to it.

Focus after a removal now lands on the row that took the deleted one's place,
clamped to what is on screen so a page collapse does not jump to the top, and
only when focus actually went to the body, so a slow delete cannot take it back
from wherever the reader moved to.

The dialog also now names the notification, which the button's aria-label
already did and the modal covering the list dropped.
…x/pr44-fix-20260823

# Conflicts:
#	src/app/common/notifications-page/notifications-page.component.ts
maplefoxgit and others added 29 commits August 28, 2026 19:50
…coverage

fix(routes): apply the role guard to every staff route
…key-events

fix(a11y): give hover reveals a focus path and enable the lint rule
…-unsaved-guard

fix(unit-tasks): stop an unsaved task definition being discarded without asking
…-route-param

fix(task-viewer): follow taskAbbreviation changes in the route
…empty-body

fix(http): handle an error response with an empty body
…ft-user-scope

fix(comments): scope comment drafts to the signed in user and clear them on sign out
# Conflicts:
#	src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.spec.ts
…follows-navigation

fix(units): follow the route when the unit changes
…board-followup-20260828

fix(dashboard): complete mobile navigation and feedback routing
…-url-20260828

fix(auth): restore notification destination after sign in
…-skeleton

Jira ticket: UXP-L01
Summary: Adds a small reusable f-skeleton-loader standalone component (shape and repeat-count inputs) that wraps the already-installed ngx-skeleton-loader, and applies it to the loading state of the portfolio included-tasks list, replacing the bare spinner with row-shaped placeholders.
Target branch: feature/ui-polish
Testing: npx tsc --noEmit passes against src/tsconfig.app.json and src/tsconfig.spec.json. Added skeleton-loader.component.spec.ts (defaults to 3 row placeholders, renders the configured count, renders none for a count of zero, a discriminating test that row and card shapes render different placeholder heights, and that the placeholder group is aria-hidden). Added portfolio-included-tasks.component.spec.ts, which did not exist before (skeleton renders with shape row and count 4 while the load is pending, is replaced by the real list once the load resolves, and gives way to the existing "No tasks found" state when the load resolves empty). Build and test:ci run in CI, since the dev container mounts a different checkout than this branch.
Security and privacy: No data model or API change. Presentational component only. No student data involved.
Evidence: An after screenshot of the skeleton loading state will be attached.


fixed these One thing blocks merge: lint (22) is red on prettier import ordering, and the job runs --max-warnings 0. I reproduced both against .prettierrc (the @trivago sort-imports plugin). Two one-line moves fix it:

skeleton-loader.component.ts: unmatched third-party imports sort before the @angular group, so put the ngx-skeleton-loader line above the @angular/core line.

portfolio-included-tasks.component.spec.ts: within the src/app group the entries must be alphabetical, so move the AlertService import (common/services/alert.service) above the SkeletonLoaderComponent import (common/skeleton-loader/...), since "se" sorts before "sk".

Easiest is to run npx prettier --write on those two files, which produces exactly those two changes and nothing else. Once lint is green this is good to merge.

Not blocking: ChangeDetectionStrategy.Eager is valid in Angular 22 (it is the renamed Default and matches the sibling component), so no change needed there.
…UXP-E01-empty-state

# Conflicts:
#	src/app/doubtfire-angular.module.ts
…-empty-state

feat(ui): add reusable empty-state component and apply to notificatio…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.