Repository navigation
Migrate translatr-components to standalone components - #352
Merged
Merged
Conversation
Adds proposal, design, and tasks for converting libs/translatr-components (30 components, 22 NgModule wrappers) to standalone components, using the Nx scam-to-standalone generator where it applies before it's removed in Nx v24. First step of a libs-first, per-package rollout to standalone across the monorepo. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Converts EllipsisPipe, ShortNumberPipe, DisableControlDirective, FeatureFlagDirective, and FeatureFlagClassDirective to standalone: true, deletes their now-empty NgModule wrappers, and updates every consumer in libs/translatr-components, apps/translatr, and apps/translatr-admin to import the class directly. Tasks 1.1-1.4 of the standalone migration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…y-graph, confirm-button to standalone Continues the standalone migration: the scam-to-standalone generator only supports inline SCAMs (component + NgModule in the same file), which this codebase never uses, so single-declaration modules are converted by hand like the multi-declaration ones (design.md updated to reflect this). Updates every consumer across both apps to import the component class directly. Tasks 2.1-2.3. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tandalone Tasks 2.4-2.6. FilterFieldComponent's own spec dropped DisableControlTestingModule in favor of the real (now standalone) DisableControlDirective baked into the component's imports. FooterComponent's spec needed RouterTestingModule added: its routerLink now actually activates in tests since standalone component templates resolve directives from their own decorator imports rather than whatever NgModule TestBed happens to wrap them in. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 2.7. Required touching apps/translatr's route config (a scoped exception, confirmed with the user): app-routing.module.ts lazy-loaded LoginPageModule via loadChildren, which no longer exists once the component is standalone, so it now uses loadComponent instead. The FontAwesome icon registration that used to run as an NgModule constructor side effect is replaced with direct IconDefinition references in the icons map, removing the side effect (and the need to special-case it in tests) entirely. login-page-routing.module.ts is deleted as fully orphaned dead code. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…onents to standalone Tasks 2.8-2.14, completing group 2. Converts ProjectEditDialogComponent, ProjectInfographicComponent, TagComponent, UserEditDialogComponent, and UserEditFormComponent to standalone: true, updates their consumers, and deletes the now-empty NgModule wrappers. UserEditDialogComponent depends on UserEditFormComponent (also converted here) - both bake the real component into their imports, so their specs needed TestBed.overrideComponent to swap in the existing Mock* TestingModule the same way login-page's spec did for navbar. apps/translatr has its own unrelated, same-named ProjectEditDialogModule (under shared/project-edit-dialog) - verified by import path and left untouched; only the lib's own module was in scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 3.1, first multi-declaration module. EmptyViewComponent, EmptyViewHeaderComponent, EmptyViewContentComponent, and EmptyViewActionsComponent are unrelated siblings composed via ng-content projection in consumer templates, not via each other's own templates, so no cross-component imports were needed. Updates all 8 app consumers to import all four classes directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 3.2. EntityTableComponent and SelectionActionsComponent are unrelated siblings (content-projected, not template-composed). EntityTableComponent's own spec needed TestBed.overrideComponent to swap the real FilterFieldComponent for FilterFieldTestingModule. access-tokens.component.spec.ts had EntityTableComponent sitting in `declarations`, which standalone components reject at runtime - moved to `imports`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 3.3. NavbarComponent, AuthBarItemComponent, SearchBarComponent, and AuthBarLanguageSwitcherComponent converted to standalone: true, each with its own precise imports (not a shared pool). navbar.module.ts used NgModule.forRoot() to provide the LanguageSwicher DI token plus a singleton-loaded-once guard - neither has a standalone equivalent. Per explicit user confirmation, the provider now lives in each of the 4 consuming NgModules' own `providers` array instead (apps/translatr and apps/translatr-admin sidenav modules, editor-page, main-page), and the guard is dropped since each consumer is already its own lazy-loaded injector boundary. login-page.component.ts (converted in task 2.7, deferred to the real NavbarModule since navbar wasn't standalone yet) now imports the real NavbarComponent and AuthBarLanguageSwitcherComponent directly. Several specs needed RouterTestingModule added: routerLink now actually activates in tests since standalone templates resolve directives from their own decorator imports (same pattern as footer in an earlier commit). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 3.4. ErrorPageComponent, ErrorPageHeaderComponent, and ErrorPageMessageComponent are unrelated siblings composed via ng-content projection, same pattern as empty-view. Updates all 3 app consumers to import all three classes directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Task 3.5, completing group 3. Converts UserCardComponent and UserCardLinkComponent to standalone: true. UserCardLinkComponent composes the real UserCardComponent in its own template (not content projection), so its spec needed TestBed.overrideComponent to swap in the existing UserCardTestingModule mock. Also discovered and converted TimeAgoPipe/TimeAgoModule (pipes/time-ago/time-ago.pipe.ts), an inline-SCAM pipe missed by the original proposal/design inventory that blocked user-card. Updated all 20 consumers across both apps and this lib to import TimeAgoPipe directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Part of task group 4 (testing modules). Converts and de-modularizes: MockActivityGraphComponent, MockConfirmButtonComponent (and removes the now-redundant ButtonTestingModule wrapper), MockEmptyViewComponent family (4 mocks), MockNavbarComponent, MockAuthBarItemComponent, and MockAuthBarLanguageSwitcherComponent. Deletes the now-fully-unused DisableControlTestingModule (its only consumer was removed back in task 1.2 when filter-field started using the real, now-standalone DisableControlDirective directly). Updates every consumer spec across both apps to import the mock classes directly instead of the deleted wrapper modules. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…lone Completes task group 4. Converts and de-modularizes MockEntityTableComponent, MockSelectionActionsComponent, MockFeatureFlagDirective, MockFeatureFlagClassDirective, MockFilterFieldComponent, MockMetricComponent, MockFooterComponent, MockErrorPageComponent (and its header/message siblings), MockProjectInfographicComponent, MockUserCardComponent, MockUserCardLinkComponent, and MockUserEditFormComponent - the remaining testing doubles in libs/translatr-components. Renames each surviving file to mock-*.component.ts since it no longer defines an NgModule. Updates every consumer spec across both apps to import the mock classes directly instead of the deleted wrapper modules, using TestBed.overrideComponent where the real (now standalone) component under test bakes the mocked dependency into its own imports and can no longer have it swapped via TestBed's module imports alone. All 50 lib specs, 159 translatr specs, and 88 translatr-admin specs pass; both apps build clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All 32 tasks done. Final verification: zero remaining *Module imports from @dev/translatr-components anywhere in the workspace; both apps build clean; all three test suites pass (50 lib + 159 translatr + 88 translatr-admin = 297 specs); manual browser smoke test confirms no Angular/DI/template errors on every screen reachable without a backend (home, language switcher, login, forbidden page). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Sep 19, 2026
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.
Summary
libs/translatr-components(30 components, 4 pipes, 4 directives) to standalone, deleting all 22 production NgModule wrappers plus 14 testing-module wrappers.@nx/angular:scam-to-standalonedoesn't apply anywhere in this repo (it only supports inline SCAMs; this codebase always keeps theNgModulein a separate file), so every conversion was done by hand.TimeAgoPipe) missed by the original inventory.navbar.module.tsusedNgModule.forRoot()to provide aLanguageSwicherDI token with no standalone equivalent — moved into each of the 4 consuming modules' ownprovidersinstead.login-page.module.tsbrokeapps/translatr'sloadChildrenroute (it lazy-loaded the module class) — switched that one route toloadComponent.Test plan
nx test translatr-components— 50/50 passingnx test translatr— 159/159 passingnx test translatr-admin— 88/88 passingnx build translatrandnx build translatr-admin— both succeed, no TypeScript errors*Moduleimports from@dev/translatr-components/login(lazyloadComponentroute),translatr-admin→ shared login redirect (eager import path),/forbiddenerror page — no Angular/DI/template console errors, only expected backend-unavailable 500sFull task-by-task detail in openspec/changes/migrate-translatr-components-standalone.
🤖 Generated with Claude Code