Skip to content

Migrate translatr-components to standalone components - #352

Merged
resamsel merged 14 commits into
mainfrom
migrate-translatr-components-standalone
Sep 18, 2026
Merged

resamsel merged 14 commits into
mainfrom
migrate-translatr-components-standalone

Conversation

@resamsel

Copy link
Copy Markdown
Owner

Summary

  • Converts every component, pipe, and directive in libs/translatr-components (30 components, 4 pipes, 4 directives) to standalone, deleting all 22 production NgModule wrappers plus 14 testing-module wrappers.
  • No behavior change: rendering, inputs/outputs, and public API surface stay identical — only the internal module architecture changes. First step of a libs-first, per-package rollout to standalone components across the monorepo (root bootstrap, NgRx wiring, and route config for both apps are tracked as separate follow-up changes).
  • Notable deviations from the original plan, resolved along the way:
    • @nx/angular:scam-to-standalone doesn't apply anywhere in this repo (it only supports inline SCAMs; this codebase always keeps the NgModule in a separate file), so every conversion was done by hand.
    • Discovered and converted an uncounted pipe (TimeAgoPipe) missed by the original inventory.
    • navbar.module.ts used NgModule.forRoot() to provide a LanguageSwicher DI token with no standalone equivalent — moved into each of the 4 consuming modules' own providers instead.
    • Deleting login-page.module.ts broke apps/translatr's loadChildren route (it lazy-loaded the module class) — switched that one route to loadComponent.

Test plan

  • nx test translatr-components — 50/50 passing
  • nx test translatr — 159/159 passing
  • nx test translatr-admin — 88/88 passing
  • nx build translatr and nx build translatr-admin — both succeed, no TypeScript errors
  • Workspace-wide grep confirms zero remaining *Module imports from @dev/translatr-components
  • Manual browser smoke test (no backend available locally): home page, language switcher dropdown, /login (lazy loadComponent route), translatr-admin → shared login redirect (eager import path), /forbidden error page — no Angular/DI/template console errors, only expected backend-unavailable 500s

Full task-by-task detail in openspec/changes/migrate-translatr-components-standalone.

🤖 Generated with Claude Code

renepanzar and others added 14 commits September 18, 2026 08:28
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>
@resamsel
resamsel merged commit d9faa12 into main Sep 18, 2026
6 checks passed
@resamsel
resamsel deleted the migrate-translatr-components-standalone branch September 18, 2026 17:53
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.

2 participants