serval-admin: serval-builds: add SF project ID filter#3846
serval-admin: serval-builds: add SF project ID filter#3846
Conversation
This allows showing only Serval builds that correspond to a particular project. It can be tested by adding `&sfProjectId=FOO` to the URL.
There was a problem hiding this comment.
Pull request overview
Adds an sfProjectId query-parameter-driven filter to the Serval Builds admin view so admins can restrict the build list (and summary stats) to a single Scripture Forge project, with a UI notice and “clear filter” action.
Changes:
- Listen to
sfProjectIdin query params and apply a project filter to the builds table + summary. - Resolve and display a human-friendly project name for the active filter (fallback to raw ID).
- Add UI notice + styling for the active filter and add unit tests for filter behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.ts | Adds query-param listening, filter state, filter-clearing navigation, and row filtering logic. |
| src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html | Shows an on-page notice when a project filter is active and provides a “Show all projects” action. |
| src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.scss | Styles the new filter notice layout and adjusts notice margins. |
| src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.spec.ts | Adds tests covering filtering behavior when sfProjectId is set/cleared and updates DI setup for routing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| combineLatest([ | ||
| this.route.queryParams.pipe(map(params => params['sfProjectId'])), | ||
| this.onlineStatusService.onlineStatus$, | ||
| this.dateRange$.pipe(filter(notNull)) | ||
| ]) |
There was a problem hiding this comment.
This does look like it was not the intention of this change to reload when switching tabs. Probably the distinctUntilChange pipe is the right choice here
There was a problem hiding this comment.
I think with the current implementation, it's not significant to use distinctUntilChanged, because if the user switches tabs, ServalBuildComponent I think is going to be destroyed, and another component is going to be shown. I suppose other URL parameters could get changed that the current page could start to use for something, like pagination. I have added distinctUntilChanged.
| const projectDoc = await this.servalAdministrationService.get(projectFilterId); | ||
| displayName = projectDoc?.data != null ? projectLabel(projectDoc.data) : projectFilterId; | ||
| } catch { | ||
| // Filter can reference a deleted project; fall back to the raw ID | ||
| } |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3846 +/- ##
==========================================
- Coverage 81.03% 81.01% -0.02%
==========================================
Files 630 630
Lines 40577 40596 +19
Branches 6574 6583 +9
==========================================
+ Hits 32880 32889 +9
- Misses 6666 6685 +19
+ Partials 1031 1022 -9 ☔ View full report in Codecov by Sentry. |
RaymondLuong3
left a comment
There was a problem hiding this comment.
@RaymondLuong3 reviewed 4 files and all commit messages, and made 4 comments.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on marksvc).
src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html line 41 at r2 (raw file):
</div> @if (currentProjectFilter) {
Nit: This should be explicit currentProjectFilter != null
Code quote:
@if (currentProjectFilter) {src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html line 49 at r2 (raw file):
<button mat-button class="clear-filter-btn" (click)="clearProjectFilter()"> <mat-icon>filter_alt_off</mat-icon> <span>Show all projects</span>
Thanks for the helpful label!
Code quote:
<span>Show all projects</span>src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.spec.ts line 97 at r2 (raw file):
const rowA = env.createRowWithDetails({ projectId: 'project-a', startDate: new Date('2024-01-03T00:00:00Z') }); const rowB = env.createRowWithDetails({ projectId: 'project-b', startDate: new Date('2024-01-02T00:00:00Z') }); const rowC = env.createRowWithDetails({ projectId: 'project-a', startDate: new Date('2024-01-01T00:00:00Z') });
It looks like these projects can be added in a beforeEach for this describe.
Code quote:
const rowA = env.createRowWithDetails({ projectId: 'project-a', startDate: new Date('2024-01-03T00:00:00Z') });
const rowB = env.createRowWithDetails({ projectId: 'project-b', startDate: new Date('2024-01-02T00:00:00Z') });
const rowC = env.createRowWithDetails({ projectId: 'project-a', startDate: new Date('2024-01-01T00:00:00Z') });| combineLatest([ | ||
| this.route.queryParams.pipe(map(params => params['sfProjectId'])), | ||
| this.onlineStatusService.onlineStatus$, | ||
| this.dateRange$.pipe(filter(notNull)) | ||
| ]) |
There was a problem hiding this comment.
This does look like it was not the intention of this change to reload when switching tabs. Probably the distinctUntilChange pipe is the right choice here
marksvc
left a comment
There was a problem hiding this comment.
@marksvc made 4 comments.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on RaymondLuong3).
src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html line 41 at r2 (raw file):
Previously, RaymondLuong3 (Raymond Luong) wrote…
Nit: This should be explicit
currentProjectFilter != null
Thank you! Done.
src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.html line 49 at r2 (raw file):
Previously, RaymondLuong3 (Raymond Luong) wrote…
Thanks for the helpful label!
😄
src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.spec.ts line 97 at r2 (raw file):
Previously, RaymondLuong3 (Raymond Luong) wrote…
It looks like these projects can be added in a beforeEach for this describe.
Done.
| combineLatest([ | ||
| this.route.queryParams.pipe(map(params => params['sfProjectId'])), | ||
| this.onlineStatusService.onlineStatus$, | ||
| this.dateRange$.pipe(filter(notNull)) | ||
| ]) |
There was a problem hiding this comment.
I think with the current implementation, it's not significant to use distinctUntilChanged, because if the user switches tabs, ServalBuildComponent I think is going to be destroyed, and another component is going to be shown. I suppose other URL parameters could get changed that the current page could start to use for something, like pagination. I have added distinctUntilChanged.
RaymondLuong3
left a comment
There was a problem hiding this comment.
@RaymondLuong3 reviewed 2 files and all commit messages, made 1 comment, and resolved 3 discussions.
Reviewable status: 3 of 4 files reviewed, 2 unresolved discussions (waiting on marksvc).
src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/serval-builds.component.spec.ts line 97 at r2 (raw file):
Previously, marksvc wrote…
Done.
I was actually thinking of using a beforeEach for the tests in this describe so that all tests in this describe initialize with the same projects. That is what i was asking for here.
This allows showing only Serval builds that correspond to a particular
project. It can be tested by adding
&sfProjectId=FOOto the URL.Screenshot:

This change is