This log tracks the progress of the Angular modernization project from version 13 towards version 21.
Angular 13 → 14
The initial upgrade from Angular 13 to 14 was performed using ng update. This phase focused on establishing a stable v14 base, resolving immediate template warnings, and adopting the new Typed Forms feature.
1. Chore: Upgrade Angular 13 to 14 (c68f708b)
-
Executed
npx ng update @angular/core@14 @angular/cli@14 @angular-eslint/schematics@14. -
This was followed by a
npx ng update @angular/cdk@14 @angular/material@14.
2. Fix: Remove Unnecessary Optional Chaining (387be213)
-
Action: Cleaned up template code to resolve
NG8107warnings. -
Reason: Angular 14's improved template type checking flagged optional chaining (
?.) on properties that are guaranteed to be defined (or where the parent is not null/undefined). This "chore" was necessary to clear the console of noise and ensure clean build outputs.
3. Refactor: Migrate to Typed Reactive Forms (3d36885e)
-
Action: Converted
UntypedFormControl,UntypedFormGroup, etc., to their typed counterparts. -
Reason: One of the major benefits of Angular 14. This improves type safety across the application and catches potential form-related errors at compile time.
4. Fix: Update SettingsComponent Spec to Resolve Test Failures (31aef4ab)
-
Action: Fixed 3 failing tests in
settings.component.spec.tsby providing missing mock data. -
Reason: Removing
?.in commit031ef6a1exposed that the test environment never provided ametaobject to the component. SinceMockLoaderServicereturns nometa,this.metastayedundefinedat render time, causing Angular's template engine to crash withCannot read properties of undefined (reading 'activityMeta'). Added ametastub on the component instance beforedetectChanges(), and provided aGithubServicespy which was also missing from the test providers.
Angular 14 → 15
The upgrade from Angular 14 to 15 involved multiple phases: a TypeScript prerequisite upgrade, the Angular core/CLI ng update, the Angular Material/CDK ng update (which auto-aliases all components to mat-legacy-*), a typography configuration fix, the full MDC migration using Angular's CLI schematics, manual resolution of all TODO(mdc-migration) comments, several rounds of CSS/template/component fixes for chips, sliders, form-fields, buttons, and dark-mode styling, test suite updates, and finally a full migration to standalone components (removing AppModule and MaterialModule entirely).
1. Chore: Upgrade TypeScript to 4.8 (24645b16)
- Action: Bumped
typescriptfrom^4.6.4to^4.8.0inpackage.json.
2. Chore: Upgrade Angular Core & CLI to v15 (6a433bbb)
-
Action: Executed
npx ng update @angular/core@15 @angular/cli@15 @angular-eslint/schematics@15. -
Key Changes:
-
All
@angular/*core packages bumped from^14.3.0to^15.2.10. -
@angular-devkit/build-angularbumped from^14.2.13to^15.2.11. -
@angular-eslint/*packages bumped from^14.4.0to^15.2.1. -
@typescript-eslint/*bumped from^5.36.2to^5.43.0. -
tsconfig.json:targetchanged fromes2020toES2022, added"useDefineForClassFields": false(required by Angular 15's class field semantics). -
src/test.ts: Removed deprecatedrequire.context()bootstrapping; Angular 15's test builder auto-discovers spec files. -
angular.json: Addedschematicsconfiguration for@angular-eslint. -
Files:
angular.json,package.json,package-lock.json,src/test.ts,tsconfig.json
3. Chore: Upgrade Angular Material & CDK to v15 (a9999c51)
-
Action: Executed
npx ng update @angular/cdk@15 @angular/material@15. -
Key Changes:
-
@angular/cdkbumped from^14.2.7to^15.2.9. -
@angular/materialbumped from^14.2.7to^15.2.9. -
Auto-aliasing to
mat-legacy-*: Theng updateschematic automatically rewrote all Material imports across the entire codebase to use legacy aliases (e.g.,MatButtonModule→MatLegacyButtonModule as MatButtonModule). This is Angular Material 15's strategy for maintaining backward compatibility while introducing new MDC-based components. -
material.module.ts: All 14 Material module imports were aliased (Button, List, Table, Chips, ProgressSpinner, Autocomplete, Input, Select, FormField, Card, Checkbox, Slider, etc.). -
Component files: Dialog, Tooltip, Menu imports were aliased across
app.module.ts, all modal components, all page components, all spec files, and the notification service. -
custom-theme.scss: -
mat.core()→mat.legacy-core() -
mat.all-component-themes()→mat.all-legacy-component-themes() -
Added auto-generated
TODO(v15)comment about typography migration -
Added
mat.all-legacy-component-typographies($custom-typography) -
Files: 24 files changed across
package.json,app.module.ts, all component.ts/.spec.tsfiles,material.module.ts,notification.service.ts,custom-theme.scss
4. Fix: Correct Typography Configuration & Theme Structure (d354b9f5)
-
Action:
-
Replaced
mat.define-typography-level()withmat.define-legacy-typography-config($font-family: 'Roboto, Helvetica Neue, sans-serif'). -
Reordered SCSS
@includestatements:mat.legacy-core()beforemat.all-legacy-component-typographies(). -
Changed
mat.all-legacy-component-themes()→mat.all-legacy-component-colors()(avoids re-emitting typography/density styles). -
Reason: The original code used
mat.define-typography-level()which produces a single level, not a full config map. Material silently ignored it and fell back to defaults.Montserratwas never rendered in production. Usingmat.define-legacy-typography-config()fixes the signature, and Roboto preserves visual parity with the live site. Theall-legacy-component-colors()mixin avoids duplicate typography emission when theme colors differ between light/dark modes. -
Files:
custom-theme.scss,docs/migration-doc.md,teams.component.html,teams.component.ts
5. Refactor: Run MDC Migration Schematics (66c409cd)
-
Action: Executed
ng generate @angular/material:mdc-migrationto migrate all legacy components to MDC. -
Key Changes (38 files):
-
CSS: Auto-generated
TODO(mdc-migration)comments on rules targeting legacy internal classes (.mat-slider-horizontal,.mat-chip-list,.mat-form-field-wrapper,.mat-card-header, etc.) -
custom-theme.scss: -
mat.legacy-core()→mat.core() -
mat.all-legacy-component-typographies()→mat.all-component-typographies() -
mat.all-legacy-component-colors()→mat.all-component-colors() -
CSS selectors updated:
.mat-table→.mat-mdc-table,.mat-header-row→.mat-mdc-header-row,.mat-row→.mat-mdc-row, etc. -
styles.css: Slider rules updated withTODO(mdc-migration)comments. -
Note: The CLI migration produced some duplicate
@includecalls and leftoverTODOcomments that were cleaned up in the next commit. -
Files: 38 files across all components, specs, modules, theme, and global styles
6. Fix: Resolve All MDC Migration TODOs (d414cb90)
-
Action: Manually resolved every
TODO(mdc-migration)comment generated by the CLI schematics, replacing legacy CSS selectors with their MDC-compliant equivalents. -
Files: 15 files across
progress-slider,report-config-modal,circular-heatmap,mapping,matrix,settingscomponents +custom-theme.scss+styles.css
7. Fix: Migrate Sidenav List Directives to MDC (b8b39d4c)
-
Action: Updated
sidenav-buttons.component.htmlto use MDC list directives. -
Key Changes:
-
mat-list-icon→matListItemIcon,mat-line→matListItemTitle -
Added component CSS for
[matListItemIcon]with spacing overrides (margin-right: 18px,margin-left: 22px) to restore icon alignment matching the legacy layout. -
Reason: The MDC
mat-listuses structural directives (matListItemIcon,matListItemTitle,matListItemLine) instead of legacy attribute selectors (mat-list-icon,mat-line). The CLI migration schematic did not catch these in the sidenav component. -
Files:
sidenav-buttons.component.html,sidenav-buttons.component.css
8. Fix: Resolve Heatmap Chip Selection and Styling Issues (769b63af)
-
Action: Rewrote the circular heatmap's team filter chip logic and template to work correctly with MDC chips.
-
Key Changes:
-
Template: Removed wrapping
<mat-form-field>from chip listboxes (MDC chips should not be inside form fields for selection-only use). Replaced with plain<label>+<mat-chip-listbox>structure. Added<mat-divider>separators. Changed filter toggle button frommat-buttontomat-icon-button. -
TypeScript: Completely rewrote
toggleTeamGroupFilter()andtoggleTeamFilter(): -
Reason: The initial MDC migration (commits 5-6) broke chip filtering because the MDC
MatChipOptionAPI differs fundamentally from legacyMatChip. The old imperativechip.toggleSelected()+(click)pattern doesn't work with MDC's(selectionChange)event model, which fires after internal state is already updated. The form field wrapper also caused rendering issues because MDC chips render their own outline. -
Files:
circular-heatmap.component.html,circular-heatmap.component.ts,custom-theme.scss
9. Fix: Resolve Button, Input, and Panel CSS Issues (8582349b)
-
Action: Fixed broken styling across multiple components after the MDC migration.
-
Reason: MDC components use different DOM structures and default spacing than legacy components. The migration schematics update import paths and top-level selectors but cannot account for deep CSS customizations or layout assumptions built around legacy internal structures.
-
Files: 7 files across
add-evidence-modal,report-config-modal,team-selector,circular-heatmap,settings,custom-theme.scss
-
⚠️ A few minor visual regressions were flagged after this manual UI change (see Backlog below). -
Decision: move ahead with the next upgrade cycle (Angular 15 → 16 → ... → 21) and track the remaining visual polish items as backlog.
10. Fix: Resolve Matrix Chip Selection and Rendering Issues (30aa3ee1)
-
Action: Fixed the Matrix page's chip filters and table rendering.
-
Reason: The Matrix page had the same chip API incompatibility as the heatmap. Additionally, the
<div>inside<table>rendered silently under legacy Material but broke under MDC's stricter DOM expectations. -
Files:
matrix.component.css,matrix.component.html,matrix.component.ts
11. Fix: Update Matrix Spec to Use MatChipSelectionChange API (9970e77e)
-
Action: Updated
matrix.component.spec.tsto match the newMatChipSelectionChangeevent-based API. -
Reason: The component's filter functions now accept
MatChipSelectionChangeevents instead ofMatChipinstances, and usesetTimeout()internally. Tests neededfakeAsync/tickto properly exercise the async filter logic. -
Files:
matrix.component.spec.ts
12. Refactor: Migrate All Components to Standalone (9ec0c58f)
-
Action: Converted every component, directive, and pipe in the application to
standalone: true, then deletedAppModuleandMaterialModule. -
Reason: Angular 15 is the first version to support standalone components as stable. Migrating removes the centralized
AppModule/MaterialModulebarrel pattern, enabling: -
Files: 52 files — all components, directives, pipes, specs,
main.ts
Angular 15 → 16
A straightforward upgrade. No breaking changes affected this codebase. The migration was limited to dependency bumps, a sidenav icon color fix, and cleaning up a deprecated CLI flag.
1. Chore: Upgrade TypeScript to 4.9 (f18ec072)
- Bumped
typescriptfrom^4.8.0to^4.9.3(minimum required by Angular 16).
2. Chore: Upgrade Angular Core & CLI to v16 (82b79fc3)
- Executed
ng update @angular/core@16 @angular/cli@16 @angular-eslint/schematics@16. Zone.js bumped to~0.13.3.
3. Chore: Upgrade Angular Material & CDK to v16 (a6bac0aa)
- Executed
ng update @angular/material@16 @angular/cdk@16.
4. Fix: Apply Primary Color to All Sidenav Icons (afb3d58f)
- Ensured all navigation icons use the theme's primary color consistently.
5. Fix: Replace Deprecated --prod Flag (fe8893be)
- Replaced
ng build --aot --prodwithng build --configuration=productionin theheroku-postbuildscript. The--prodflag was removed in Angular CLI v12+.
Angular 16 → 17
A relatively smooth upgrade. Core, CLI, Material, CDK, and ESLint were bumped to v17. The MDC theme required replacing auto-generated TODO placeholders with the proper all-component-themes mixin. A few CSS regressions on buttons and info icons were fixed using MDC CSS variables. Spec files needed minor updates for RouterTestingModule deprecation and MatChip becoming standalone. ESLint deps were cleaned up to resolve peer conflicts introduced by the upgrade. Ended with a Prettier 3 reformat. Commit messages are detailed with more information about the specific changes.
Angular 17 → 18 + Complete UI Revamp
Upgraded Angular Core, CLI, Material, and CDK to v18. TypeScript version pinning was tightened (^ → ~). An ESLint 18 warning required renaming the cancel output binding to cancelEdit across 3 files. Material 18 introduced the M3 theming system. The custom theme was regenerated via the CLI (ng generate @angular/material:m3-theme) and the custom-theme.scss file was refactored to unify dark/light mode overrides. Multiple UI component fixes followed to align with M3's updated DOM structure and default styles.
1. Chore: Pin TypeScript Ranges in package-lock.json (959bb88f)
- Converted
^(caret) ranges to~(tilde) inpackage-lock.jsonfor tighter version pinning.
2. Chore: Upgrade Angular Core & CLI to v18 (18fafd7f)
- Executed
ng update @angular/core@18 @angular/cli@18.
3. Fix: Rename cancel Output to cancelEdit (8859ce34)
- Renamed
cancel→cancelEditacross 3 files. - Reason: ESLint 18 warning — output bindings (including aliases) should not be named as standard DOM events.
4. Chore: Upgrade Angular Material & CDK to v18 (1575ec8c)
- Executed
ng update @angular/material@18 @angular/cdk@18.
5. Chore: Generate M3 Theme via CLI (58b77590)
- Ran
ng generate @angular/material:m3-themeto scaffold the new M3 theme configuration.
6. Fix(UI): Sidenav Component (d9b526e4)
- Fixed sidenav styling for M3 compatibility.
7. Fix(UI): Matrix Page Icons (b7eb30be)
- Fixed icon rendering on the Matrix page.
8. Refactor: Unify Dark/Light Theme Overrides (2514ae93)
- Cleaned up
custom-theme.scss— consolidated duplicate styles that were identical across dark and light themes into shared rules.
9. Fix(UI): Mat-Chips (ae994674)
- Fixed chip styling for M3.
10. Fix(UI): Mat-Expansion-Panel (8ddcc878)
- Fixed expansion panel styling for M3.
11. Fix(UI): Mat-Button (7e7a4411)
- Fixed button styling for M3.
12. Fix(UI): Mat-Accordion Trailing Line (dae53b67)
- Removed trailing line artifact from accordion panels.
13. Fix(UI): MatDialog Pop-Up Modal (fdaa7db8)
- Fixed dialog/modal styling for M3.
14. Fix(UI): Mat-Slider (6185748f)
- Fixed slider styling for M3.
15. Chore: Remove Unnecessary Comments (6f10efda)
- Removed obvious/redundant comments from the codebase.
16. Chore: Pin All Dependency Versions (f1ec329)
- Removed
~and^ranges from every dependency for strict version pinning + regression fix.
17. Refactor: Standardize MatDialog Sizing (b95e65c2)
- Introduced semantic size tiers for
MatDialogwidth/height, replacing scattered hard-coded pixel values with a centralized sizing utility.
18. Fix: Remove Redundant Mat-Select Global Styles (b2361d88)
- Removed unused
mat-selectCSS overrides from global styles: the rules were not being applied and the default M3 background color is already appropriate.
19. Chore: Bump markdown-it Dependencies (ff70f84d)
- Bumped
markdown-itand@types/markdown-itto their latest versions.
Angular 18 → 20
Two clean version bumps (19, then 20) across Core, CLI, Material, and CDK, interspersed with a Control Flow migration, a chip filter loop fix, an RxJS upgrade for bundler module resolution, and a dialog theming fix.
- Upgraded Core & CLI to v19, then Material & CDK to v19.
- Migrated templates to the new Control Flow syntax (
ng generate @angular/core:control-flow). - Removed unnecessary
this.prefix when accessing template reference variables. - Fixed an infinite filter loop by switching chip listboxes from
(selectionChange)to(change). - Bumped
@typescript-eslint/eslint-pluginand@typescript-eslint/parserto8.62.1. - Upgraded Core & CLI to v20, then Material & CDK to v20.
- Upgraded
rxjsto7.8.1and switched tomoduleResolution: bundler(rxjs 7.5.0 lacked anexportsfield required for bundler resolution). - Fixed dialog surface background override (Material now paints background via
--mat-dialog-container-coloron.mat-mdc-dialog-surface, not.mat-mdc-dialog-container). - Migrated constructor DI to the
inject()function across the codebase (ng generate @angular/core:inject), resolving all@angular-eslint/prefer-injectlint errors. - Updated CI workflow to run on Node.js 20 instead of 18.
Angular 20 → 21 + Dependency Security Audit
Two straightforward ng update passes (Core/CLI, then Material/CDK) to reach Angular 21, followed by a round of test fixes required by Angular 21's stricter TestBed change-detection error rethrow (NG0100), and a full dependency security audit that dropped vulnerability count from 33 to 1.
1. Chore: Upgrade Angular Core & CLI to v21 (186d547a)
- Executed
ng update @angular/core@21 @angular/cli@21.
2. Chore: Upgrade Angular Material & CDK to v21 (fe574695)
- Executed
ng update @angular/material@21 @angular/cdk@21.
3. Fix: Resolve NG0100 Test Failures from Angular 21 TestBed Error Rethrow (da2bdb34)
- Action: Fixed test failures surfaced by Angular 21's stricter enforcement around change-detection errors during
TestBedruns. - Key Changes:
progress-slider.component.spec.ts,top-header.component.spec.ts: Movedfixture.detectChanges()out of the sharedbeforeEach()into each individual test, since a globaldetectChanges()call before test-specific state was set (e.g.component.state) caused a second, differingdetectChanges()later in the same test to throwNG0100.teams.component.spec.ts: Pre-loaded mock data viamockLoaderService.load()before component creation and now sets it synchronously withsetYamlData()prior to the firstdetectChanges(), resolving an asyncNG0100caused by data arriving after the component's first render.usage.component.ts: Added a null guard (if (page && page.match(...))) before the CWE-79 sanitization check, sinceparams['page']could beundefinedon some routes.main.ts: Removed unusedReactiveFormsModule/FormsModuleimports left over from the standalone migration.
- Files:
progress-slider.component.spec.ts,top-header.component.spec.ts,teams.component.spec.ts,usage.component.ts,main.ts
4. Chore: Remove Unused Grafana SDK, Patch Vulnerabilities via Bumps/Overrides (33→1) (2a14047e)
- Action: Ran a full dependency security audit against
package.json. - Key Changes:
- Removed
@grafana/faro-web-sdkand@grafana/faro-web-tracing, unused anywhere insrc/. Eliminated ~20 vulnerabilities on its own by dropping the entire@opentelemetry/*stack - Bumped
js-yaml4.1.0 → 4.3.0 - Bumped
yaml2.8.1 → 2.9.0 - Bumped
@types/node12.11.1 → 20.19.0 (dev-only types, years out of date). - Bumped
karma6.3.0 → 6.4.4 (satisfies Angular 21'skarma@^6.4.0peer dependency, clearing anERESOLVEwarning). - Bumped
prettier-eslint16.3.0 → 17.1.1 (drops its bundled EOL ESLint 8, clearing 3 deprecation warnings and a vulnerableminimatch). - Bumped
qs6.11.0 → 6.15.3 - Added an
overridesentry pinninguuidto11.1.1across the tree, fixing a buffer bounds-check issue nested inside Angular's own build tooling (webpack-dev-server → sockjs → uuid@8.3.2). - Also bumped
@ngneat/until-destroy,d3,markdown-it,rxjs, andprettieras part of the same pass.
- Removed
- Result: Vulnerabilities reduced from 33 → 1. The one remaining issue is an unfixable
xlsx/SheetJS ReDoS + prototype pollution vulnerability, deferred to a future PR since resolving it requires code changes whereverxlsxis imported. - Files:
package.json,package-lock.json
Vulnerability Reduction
| Stage | Vulnerabilities | Deprecation Warnings |
|---|---|---|
| Starting point (Angular 21) | 33 | 5 |
| After Grafana removal | 14 | 5 |
After npm audit fix + bumps |
9 | 4 |
After uuid override |
4 | 3 |
After prettier-eslint bump + minimatch override removed |
1 | 0 |
5. Chore: Remove unused deps and migrate test env to static platform (431328a)
- Removed
@angular/platform-browser-dynamic(runtime + types) after completing thebootstrapApplicationmigration inmain.ts. - Dropped unused packages:
js-yaml,@types/js-yaml,@types/node,@angular-eslint/schematics,@typescript-eslint/eslint-plugin,prettier-eslint,qs. - Bumped
@typescript-eslint/parserto8.64.0. - Migrated
test.tsfromBrowserDynamicTestingModuletoBrowserTestingModule(static platform).
6. Chore(deps): Remove @angular/animations (d55c9b8)
- Removed
@angular/animationspackage and all related imports (provideAnimations,BrowserAnimationsModule,NoopAnimationsModule) frommain.tsand test specs.
7. Chore: Migrate build toolchain from @angular-devkit/build-angular to @angular/build (a7e3cf6)
- Switched build, serve, and extract-i18n builders to the leaner
@angular/buildpackage (esbuild/Vite only, no Webpack baggage). - Karma test builder remains on
@angular-devkit/build-angular(karma plugin not available in@angular/build).
8. Chore: Approve install scripts for build toolchain dependencies (426666c)
- Allowlisted
esbuild,lmdb,msgpackr-extract,@parcel/watcherinstall scripts in both npm (allowScripts) and pnpm (pnpm-workspace.yamlallowBuilds). - Moved
uuidoverride intopnpm-workspace.yamlfor pnpm v11 compatibility.
Each component toggle below documents a single commit.
MatrixComponent (2f020c46)
- Converted
levels,filtersTag,filtersDim,columnNames, andMATRIX_DATAfrom plain properties tosignal(). - Replaced the imperative
updateActivitiesBeingDisplayed()method with a singledataSource = computed()that derives filtered rows automatically wheneverMATRIX_DATA,filtersTag, orfiltersDimchange. - Removed
MatTableDataSourcewrapper anddeepCopy()call —computed()already produces a fresh derivation on every dependency change. - Filter chip handlers (
toggleTagFilters/toggleDimensionFilters) now callsignal.update()instead of mutating a plain object, and no longer need to manually trigger a re-filter. buildMatrixData()takesallDimensionNamesas a parameter instead of reading a class property, since it was previously only used once during init.- Files:
matrix.component.ts,matrix.component.html,matrix.component.spec.ts
ThemeService & TitleService (408342c3)
Services
ThemeService.themechanged fromBehaviorSubject<AppTheme>→signal<AppTheme>. AtoObservable()bridge (theme$) is kept for any remaining subscribers.TitleService.titleInfochanged fromBehaviorSubject<TitleInfo | null>→signal<TitleInfo | null>, with the sametoObservable()bridge.
Consumers
AppComponent: Replaced manualsubscribe()+ instance properties fortitle/subtitlewithcomputed()values that read directly fromTitleService.titleInfo().SidenavButtonsComponent: Replacedsubscribe()onThemeService.theme$withisNightMode = computed(() => themeService.theme() === 'dark').- Both consumers no longer need
OnDestroy/ manual unsubscribe logic. - Files:
theme.service.ts,title.service.ts,app.component.ts,app.component.html,app.component.spec.ts,sidenav-buttons.component.ts,sidenav-buttons.component.html,sidenav-buttons.component.spec.ts(8 files, −56 / +50)
ReportComponent & ReportConfigModalComponent (44480759)
ReportComponent
reportConfigandallActivitiesconverted tosignal().filteredDimensions,levelByLevelOverviewFromActivties, andtotalFilteredActivitiesare nowcomputed()values that automatically re-derive whenreportConfigorallActivitieschange — no manual refresh calls needed.- Config changes from the modal or team selector write back via
signal.set().
ReportConfigModalComponent
configconverted tosignal<ReportConfig>, deep-copied from dialog input on construction.filteredActivitiesandhasAnyMarkdownAttributearecomputed()values.activitySearchQueryis asignal('')driving thefilteredActivitiescomputation.- Files:
report.component.ts,report.component.html,report-config-modal.component.ts,report-config-modal.component.html(4 files)
CircularHeatmapComponent (d7abc966)
- Full signal migration:
filtersTeams,filtersTeamGroups,teamGroups,allSectors,selectedSector,showOverlay,showFilters,showActivityCard,showActivityDetails, anddataStoreconverted from plain properties tosignal(). hasTeamsFilterderived ascomputed()fromfiltersTeams(no manual bookkeeping)- Replaced
ngOnInit+requestAnimationFramehack withafterNextRender(Angular 17+ DOM-ready API). - Replaced
themeService.theme$RxJS subscription with aneffect()tracking theThemeService.themesignal for reactive heatmap repaint. - Dissolved
destroy$Subject /takeUntil/OnDestroy: teardown handled byDestroyRef(destroyRef.onDestroy()andtakeUntilDestroyed()). - Extracted
readThemeColors()helper to DRY up CSS custom property reads (previously duplicated in init and theme subscriber). - Group chip filter switched from listbox-level
(change)to per-chip(selectionChange)withMatChipSelectionChange— prevents deselection of the active group chip via a three-tier guard (isUserInputcheck → programmatic deselection ignore → already-active check). - Bug fix: Replaced
equalArray()with set-based comparison for group highlight, fixing order-sensitive mismatch between chip/DOM order and YAML declaration order. - Bug fix: All filter mutations now create new object references via
.set(), fixing thekeyvaluepipe caching bug that caused group-selected teams to be silently dropped on subsequent single-chip clicks. - Bug fix: Group chip deselection no longer leaves stale team selections — the per-chip
(selectionChange)handler prevents visual deselection entirely. - D3 click/hover handlers updated to use
signal.set()forselectedSector,showActivityCard. - Template updated: all signal properties called with
()in bindings. - Files:
circular-heatmap.component.ts,circular-heatmap.component.html
MappingComponent, SettingsComponent & TeamsComponent (d0089a97)
MappingComponent
allTeams,dataStore, andsearchTermsconverted from plain properties tosignal().- Search-term chip handlers (
removeSearchTerm,clearFilter) andonSearchKeydownnow use.update()/.set()instead of direct array mutation. setYamlData()writesdataStoreandallTeamsvia.set().- Template updated:
searchTerms(),allTeams(),dataStore()called as functions, including the optional-chaineddataStore().progressStore?.getTeamActivityTitle(...).
SettingsComponent
meta,dataStoreMaxLevel,selectedMaxLevel,selectedMaxLevelCaption,editingProgressDefinitions,remoteReleaseCheck, andselectedDateFormatconverted tosignal().- Removed unused
GithubReleaseInfoimport and deadcheckingLatest/latestReleaseInfo/latestCheckError/isNewerAvailable/latestDownloadUrl/latestReleasePublishedDatefields. These were leftover state never wired to the template, superseded byremoteReleaseCheck. checkForLatestRelease()rewritten to build the release-check result via local variables (latestRelease,checkError) and commit them in a single.update()/.set()call per branch, instead of mutating individualremoteReleaseCheckfields in place across try/catch/finally.onMaxLevelChange,updateMaxLevelCaption,toggleProgressDefinitionsEdit,saveProgressDefinitions,resetProgressDefinitionsupdated to read/write via signal()/.set()/.update().- Template updated: all signal properties called with
(), includingmeta()?.activityMeta?.getDsommVersion()andremoteReleaseCheck().latestRelease?.tagName-style chains. - Spec updated:
component.meta.set({...})andcomponent.selectedMaxLevel()assertions.
TeamsComponent
-
dataStore,canEdit,teams,teamGroups,progressTitleImplemented,infoTitle,infoTeams,info,allColumnNames, andprogressColumnNamesconverted tosignal(). -
onSelectionChangedandonTeamsChangedreworked to derive a newinfo/currentInfoobject and commit it via.set(), rather than mutating the existing record in place (avoids the same stale-reference class of bug fixed in the heatmap migration). -
setYamlData(),updateColumnNames(),onExportTeamGroups(),onResetTeamGroups(),makeTeamSummary()updated to read signals via(). -
Template updated:
teams(),teamGroups(),canEdit(),dataStore(),infoTitle(),infoTeams(),info(),allColumnNames(),progressColumnNames()called as functions throughout. -
Spec updated:
component.teams(),component.teamGroups()assertions. -
Files:
mapping.component.ts,mapping.component.html,settings.component.ts,settings.component.html,settings.component.spec.ts,teams.component.ts,teams.component.html,teams.component.spec.ts(8 files)
| # | Area | Issue | Priority | Notes |
|---|---|---|---|---|
| 1 | xlsx (SheetJS) dependency |
Prototype pollution + ReDoS vulnerability, no upstream fix available (maintainers stopped publishing security patches) | Medium | Requires code changes wherever xlsx is imported for spreadsheet export. Options: replace with exceljs or xlsx-js-style (community fork), or accept risk if only used for non-sensitive data export. Needs a dedicated PR. |
| 2 | CircularHeatmapComponent |
• Layout shift on scroll: Heatmap shifts vertically at certain viewport widths. | Low | Remaining issue after signal migration. The three chip/filter bugs (order-sensitive group highlight, group selection wipe, stale group deselection) were resolved in the CircularHeatmapComponent signal migration. |
| 3 | Logging | Replace console.log() and boolean environment.production checks with a proper logging library using log-level feature toggles. Preferred Library: Winston. |
Low | Discussed in team meeting. |
| 4 | Test Runner | • Deprecated subdependencies: Karma pulls in glob@7.2.3, inflight@1.0.6, and rimraf@3.0.2 — all deprecated, cluttering pnpm install with warnings. • pnpm incompatibility: Karma's Webpack-based builder ( @angular-devkit/build-angular:karma) cannot resolve transitive dependencies (e.g. @babel/runtime) under pnpm's strict symlinked node_modules. Currently requires node-linker=hoisted in .npmrc as a workaround, defeating pnpm's strictness benefits. • Modern tooling alignment: Build/serve already use esbuild/Vite via @angular/build. Tests are the last piece still on the legacy Webpack pipeline. Migrating would allow dropping @angular-devkit/build-angular entirely. |
High | Karma is deprecated. Migrate to a Vite-based test runner (e.g. Vitest or @angular/build native test support). |
Note
Add new backlog items here as they are discovered during future upgrades. Remove items once resolved.