Skip to content

fix(staff): admin > Users table never refreshes after a CSV import - #520

Closed
dylancleal wants to merge 1877 commits into
thoth-tech:developmentfrom
ontrack-features-t2-2026:fix/staff-12
Closed

fix(staff): admin > Users table never refreshes after a CSV import#520
dylancleal wants to merge 1877 commits into
thoth-tech:developmentfrom
ontrack-features-t2-2026:fix/staff-12

Conversation

@dylancleal

Copy link
Copy Markdown

Summary

STAFF-12. The admin Users table never refreshed after importing a
users.csv — the server created the accounts, but the table kept
showing the pre-import list until a full page reload.

Root cause

onUserUploadSuccess (users.component.ts:111) called
this.userService.query(); with nothing subscribing it, so no
request was ever made. Subscribing it alone wouldn't have fixed
this either: ngOnInit already runs this.userService.query().subscribe()
on load, and CachedEntityService.query() returns the cached
observer once a query key has been used, with a 24h cache expiry.
So the same query key would just replay the pre-import cache.

Fix

Replaced it with the cache-bypassing fetch:

this.userService.fetchAll().subscribe({error: (e) => this.alerts.error(e)});

fetchAll() is what ngx-entity-service documents as the call that
forces bypassing the cache, and it writes into userService.cache,
which is what the table's dataSource is bound to.

Built against

  • doubtfire-web fix/staff-12 off origin/11.0.x @ 1671005
  • doubtfire-api 11.0.x @ 04b2c8fd99cb98f8ab5a0722b0a8e3228c598fac
  • doubtfire-deploy 11.0.x @ c2bdf9d0be6fcf446238f4a58b1c71e9e0ee76da

Tests

Added users.component.spec.ts with 2 cases:

  • refetches the user list from the server after a CSV upload succeeds
  • surfaces an alert if the post-upload refetch fails, instead of failing silently

Both verified to fail against the pre-fix line and pass after it.

npx ng test --include='src/app/admin/states/users/users.component.spec.ts' --watch=false
-> Test Files  1 passed (1)
-> Tests  2 passed (2)

Files touched

  • src/app/admin/states/users/users.component.ts
  • src/app/admin/states/users/users.component.spec.ts (new)

Not covered by the test

The tests exercise onUserUploadSuccess directly with a mocked
UserService/AlertService, not a real CSV upload through the
file-uploader component and HTTP layer end-to-end.

Clupai8o0 and others added 30 commits August 20, 2026 16:20
…roduction

numberOfTasks.completed counted completions at every grade while remaining was
scoped to the target grade, so availableTasks reduced to activeTasks().length
and the only thing the round trip could do was let completed exceed available.
A student who had done work above their target saw an inflated percentage, and
past a certain point both panels blanked out entirely. Count completions with
tasksByStatus, which filters activeTasks by status.

Gate both PPI surfaces on environment.production. The card and the already
merged task-sheet widget each render a hardcoded 42 percent, and a student
cannot tell a fixture from a real cohort figure. The optimiser removes the mock
call from a production build entirely.

Only a missing cohort percentage now drives the cohort panel to unavailable. A
missing student percentage said nothing about cohort data we were given, and
the card already renders the two panels independently.

Handover doc: name student_percentage as a field the unit endpoint has to add,
require the target grade to be derived server-side, match the quantisation
bucket to the API, and record the nullability the frontend types do not allow.
…vigation-review

test(dashboard): address CPD route review feedback
CPD-F04 - Add due-date range filtering to the Cross-Project Dashboard
…ngs-bootstrap-compat

fix(settings): preserve bootstrap with protected feature flags
…-summary

feat(ppi): complete mock-backed unit peer progress summary
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.
maplefoxgit and others added 29 commits August 28, 2026 09:54
…k-mobile-view-20260828

fix(dashboard): make task feedback usable on phones
…ract

docs(theme): define the light, dark and system theme contract
…tor-sort

fix: handle tutorials without tutors when sorting
…validation

docs(theme): add the theme MVP validation plan, unrun
…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
@dylancleal dylancleal closed this Aug 30, 2026
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.