Skip to content

feat(translatr): convert pages layer to standalone components - #356

Merged
resamsel merged 11 commits into
mainfrom
migrate-translatr-pages-standalone
Sep 19, 2026
Merged

resamsel merged 11 commits into
mainfrom
migrate-translatr-pages-standalone

Conversation

@resamsel

Copy link
Copy Markdown
Owner

Summary

  • Converts all apps/translatr/src/app/modules/pages/** components to standalone: true, completing the third phase of the standalone-components migration (after libs/translatr-components in Migrate translatr-components to standalone components #352 and apps/translatr/src/app/modules/shared in Migrate translatr shared modules to standalone components #355).
  • Deletes all 10 page-level declarations NgModules, relocating their NgRx StoreModule.forFeature/EffectsModule.forFeature wiring and facade/guard providers into each page's already-existing, zero-component *-routing.module.ts.
  • Repoints all 9 affected app-routing.module.ts loadChildren entries from .then(m => m.XxxPageModule) to .then(m => m.XxxPageRoutingModule), atomically with each page's own conversion.
  • Converts the 6 page-scoped Mock* testing-double components (editor, key-list, locale-list, member-list) to standalone, replacing their *TestingModule NgModule wrappers.
  • Fixes a masked bug in KeyEditorPageComponent: its standalone imports was missing MatInputModule, which only worked in tests because the TestBed's ambient imports covered it — a standalone component's template only resolves directives from its own imports, not the surrounding TestBed module.

Test plan

  • nx test translatr — 159/159 passing
  • nx build translatr — clean build, no new warnings
  • tsc -p apps/translatr/tsconfig.app.json --noEmit — clean
  • Manual smoke test via browser: main page renders with zero console errors beyond expected unauthenticated 401s; every guarded lazy route (dashboard/users/projects/editor/user-page/project-page) redirects to login cleanly with no DI or router errors, confirming their relocated NgRx/facade/guard wiring resolves correctly
  • Deeper interactive smoke test of authenticated nested-tab routes wasn't possible without login credentials for the running dev instance

🤖 Generated with Claude Code

renepanzar and others added 11 commits September 19, 2026 08:45
Adds proposal, design, and tasks for converting
apps/translatr/src/app/modules/pages (10 page modules, 28 components,
4 testing doubles) to standalone components. Third and final layer of
apps/translatr's standalone rollout, after libs/translatr-components
and apps/translatr/src/app/modules/shared.

Key finding: each page's *-routing.module.ts is already zero-component
route config, so app-routing.module.ts's loadChildren entries repoint
to it instead of being rewritten to loadComponent, avoiding a much
larger routing rewrite. NgRx forFeature wiring for the 4 stateful pages
relocates into the surviving routing module.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tasks 1.1-1.4, completing group 1. Converts ForbiddenPageComponent,
NotFoundPageComponent, MainPageComponent, and RegistrationPageComponent
to standalone: true, deleting their NgModule wrappers.

Repoints each page's app-routing.module.ts loadChildren entry to the
already-existing, already-zero-component *RoutingModule atomically with
its own conversion (not batched into a later step) so every commit
stays independently buildable.

Caught a real bug in main-page: provideSvgIcons() returns
EnvironmentProviders, which Angular rejects in a component's own
providers array (NG0207) - moved it to main-page-routing.module.ts's
NgModule providers instead, which is still environment-scoped.

registration-page had the same FontAwesome module-constructor icon
registration pattern seen in login-page during the libs change - fixed
the same way, with direct IconDefinition references.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tasks 2.1-2.6, completing group 2. Converts all 10 project-page
components (KeyListComponent, LocaleListComponent, MemberListComponent,
ProjectInfoComponent, ProjectKeysComponent, ProjectLocalesComponent,
ProjectMembersComponent, ProjectActivityComponent,
ProjectSettingsComponent, ProjectPageComponent) to standalone: true,
deletes project-page.module.ts, and repoints app-routing.module.ts's
project-page loadChildren to the surviving ProjectPageRoutingModule.

ProjectStateModule (shared NgRx feature state for the whole project-page
route subtree) and the AppFacade/guard providers that used to live on
the deleted declarations module move into project-page-routing.module.ts
instead, preserving the same one-registration-per-lazy-subtree semantics.

A grep-based scan of project-info.component.html initially missed
FeatureFlagDirective and MetricComponent; project-page.component.html
missed FeatureFlagClassDirective (different attribute name than
FeatureFlagDirective's [featureFlag]). Switched to systematically
extracting every custom tag and *directive from each template before
finalizing its imports array, and retroactively re-verified the
already-converted list components the same way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Convert all 6 user-page sub-components and UserPageComponent to
standalone: true. Delete user-page.module.ts, moving its NgRx
forFeature wiring and UserFacade/UserGuard providers into
user-page-routing.module.ts. Repoint app-routing.module.ts's
user-page loadChildren to UserPageRoutingModule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Convert EditorSelectorComponent, EditorComponent, KeyEditorPageComponent,
and LocaleEditorPageComponent to standalone: true. Delete
editor-page.module.ts, moving its ProjectStateModule import, NgRx
forFeature wiring, and EditorFacade/LanguageSwicher providers into
editor-page-routing.module.ts. Repoint app-routing.module.ts's
editor-page loadChildren to EditorPageRoutingModule.

Fixes a masked bug where KeyEditorPageComponent's standalone imports
were missing MatInputModule - its matInput input only worked in tests
because the TestBed's ambient imports covered it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Convert DashboardPageComponent and ProjectsPageComponent to
standalone: true. Delete dashboard-page.module.ts and
projects-page.module.ts, moving their NgRx forFeature wiring and
facade providers into their respective routing modules.
DashboardPageComponent's dependency on ProjectsFacade (previously
satisfied by importing all of ProjectsPageModule) is now satisfied by
importing ProjectsPageRoutingModule. Repoint app-routing.module.ts's
dashboard and projects loadChildren entries to the routing modules.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Convert UsersPageComponent to standalone: true. Delete
users-page.module.ts, moving its zero-component UsersModule
(+state/users.module.ts) import into users-page-routing.module.ts.
Repoint app-routing.module.ts's users-page loadChildren to
UsersPageRoutingModule.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All 9 loadChildren entries in app-routing.module.ts were already
repointed to *RoutingModule atomically during their own group's
conversion; this verifies the sweep found nothing left to do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Convert the Mock* test-double components in editor-page, key-list,
locale-list, and member-list testing modules to standalone: true,
renaming each file to mock-*.component.ts. Update consumer specs to
import the Mock*Component classes directly instead of the
now-deleted *TestingModule NgModule wrappers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
All groups done: routing repoint verified, testing doubles converted,
and final cleanup/build/test verification passed (159/159 tests,
clean build, clean tsc). Manual smoke test covered the login/main-page
flow and confirmed all guarded lazy routes resolve without DI or
router errors.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
e2e ran the real component tree (unlike unit specs, which override real
children with mocks), surfacing several components missing directives/
pipes their templates actually use - each masked in unit tests by the
TestBed's ambient modules covering for a standalone component's own
incomplete imports:

- UserAccessTokensComponent, UserInfoComponent, MemberListComponent:
  missing TimeAgoPipe/ShortNumberPipe (amTimeAgo/shortNumber pipes
  used in templates)
- UserProjectsComponent: missing TranslocoModule, so its outer
  *transloco structural directive never activated and the entire
  template (including the real ProjectListComponent) silently never
  rendered
- UserAccessTokenComponent, KeyEditorPageComponent,
  LocaleEditorPageComponent, MainPageComponent, ProjectInfoComponent:
  missing RouterModule/MatButtonModule/MatListModule for
  routerLink/mat-button/mat-list-item usages in their templates

Also fixes a routing bug introduced in this branch: DashboardPageRoutingModule
imported the whole ProjectsPageRoutingModule just to reuse its NgRx state
wiring, which also pulled in ProjectsPageRoutingModule's own
RouterModule.forChild([{path: '', component: ProjectsPageComponent}]) -
colliding with dashboard's own path: '' route and making /dashboard render
ProjectsPageComponent instead. Fixed by importing the Projects state
pieces (StoreModule.forFeature, EffectsModule.forFeature, ProjectsFacade)
directly instead of the whole routing module.

Also fixes a pre-existing bug on main (predates this branch, in
ProjectMemberEditDialogComponent/ProjectOwnerEditDialogComponent from
the shared-layer standalone conversion): both dialogs inject ProjectFacade
(directly or via ProjectMemberEditFormComponent) but never imported
ProjectStateModule themselves, unlike the sibling KeyEditDialogComponent/
LocaleEditDialogComponent which already follow that pattern - since
MatDialog creates dialog content in a fresh injector chained to root, not
the caller's local route injector, ProjectFacade was never resolvable.

All 159 unit tests and the full local e2e suite (187 specs) pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@resamsel
resamsel merged commit 18e05b9 into main Sep 19, 2026
6 checks passed
@resamsel
resamsel deleted the migrate-translatr-pages-standalone branch September 19, 2026 11:33
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