chore(ui): migrate the remaining templates to the built-in control flow (schematic)
Summary
This PR runs Angular's own control-flow schematic (@angular/core:control-flow, Angular 22.2.2) on the four places that still had *ngIf / *ngFor / *ngSwitch templates. Every template change comes from the schematic. Prettier was then run on the files it touched, so the re-indented blocks use the repo's tabs. Signal inputs/outputs/queries and inject() are not touched, as the owner asked.
Part of #9552 (the issue stays open for the manual signal migrations).
What changed, by path (one commit each)
| Path | Command | Files kept | Excluded |
|---|---|---|---|
packages/plugins/docs-ui | nx g @angular/core:control-flow --path=packages/plugins/docs-ui | 56 of 57 | components/detail/docs-detail-panel.component.html (see below) |
packages/plugins/legal-ui | ... --path=packages/plugins/legal-ui | 2 of 2 | none |
packages/ui-core/shared | ... --path=packages/ui-core/shared | 4 of 4 | none |
apps/gauzy | ... --path=apps/gauzy | 2 of 3 | pages/goals/goals.component.ts (see below) |
All runs used the default options (--format=true). The schematic also removed CommonModule from standalone components whose templates no longer use anything from it: 15 components and one spec test host in docs-ui, plus EmailVerificationNoticeComponent in ui-core/shared. The strict template check below confirms that nothing they still use came from CommonModule. Nothing was removed by hand.
One small hand-written follow-up commit, test(docs-ui): read the thumbnail bindings in the @if syntax, is kept separate from the generated commits. Two layout specs read the component source and looked for the old *ngIf ... as thumbnail string, so they now look for the @if (...; as thumbnail) form. What they check has not changed: the image binds the sanitizing accessor, never the raw thumbUrl.
Templates left as they were (the schematic got them wrong)
packages/plugins/docs-ui/src/lib/components/detail/docs-detail-panel.component.html: the schematic moved<ng-template #taxonomyReadonly>into an@elseblock and deleted it. The surrounding*ngxPermissionsOnly="docsPermissions.update; else taxonomyReadonly"still points at that template, so ngc fails with TS2339 (taxonomyReadonlydoes not exist on the component). This file keeps its 40 lines of*ngIf/*ngFor. It needs a small manual migration that keeps the template forngxPermissionsOnly.apps/gauzy/src/app/pages/goals/goals.component.ts: its template was already migrated. The schematic rewrote theimportsarray only to dropCommonModule. The rewrite also deleted the`[nbPopover]` drives the Add Objective / Group By / Filter menuscomment inside the array and re-indented it with spaces. That file was not one of the two templates in scope and the rewrite loses a comment, so it is unchanged.
No template was refused outright: the schematic reported no migration errors on any path.
Overlap with open PRs
None of the changed files is touched by #11588, #11590 or #11592. #11588 changes packages/ui-core/shared/src/lib/contact-selector/contact-selector.component.ts, but this PR does not touch that component: its only *ngFor is inside an HTML comment, and the schematic skips it.
Before / after
git grep -c -E '\*ng(If|For|Switch)', lines per path:
| Path | Before | After | What is left |
|---|---|---|---|
packages/plugins/docs-ui | 389 lines in 63 files | 66 lines in 19 files | 40 lines are docs-detail-panel.component.html (excluded above). The other 26 are comments, JSDoc and spec text that mention the old directives, left as written (for example menu-editor-rebinding.spec.ts still says "under *ngIf", and its host template now uses @if; the test still passes). |
packages/plugins/legal-ui | 7 lines in 2 files | 0 | none |
packages/ui-core/shared | 43 lines in 7 files | 4 lines in 4 files | All four are comments (one is the commented-out <nb-select> in contact-selector). |
apps/gauzy | 16 lines in 2 files | 0 | none |
ESLint on every changed file, compared with the base commit: @angular-eslint/template/prefer-control-flow goes from 308 to 0. Every other rule has the same count before and after (the existing prefer-inject, prefer-standalone, a11y and no-restricted-imports findings are not part of this change).
Tests and type-checks
All run locally on Node 26.10.0 in this branch.
- docs-ui jest:
npx jest -c packages/plugins/docs-ui/jest.config.ts --rootDir packages/plugins/docs-ui: 45 suites, 613 tests passed. Before the spec follow-up, the two source-string assertions above were the only failures. - docs-ui templates (strictTemplates):
ngc -ponpackages/plugins/docs-ui/tsconfig.lib.jsonwithnoEmit, plustypes: ["node", "google.maps"]because the path-mapped ui-core sources need those types. Result: 0 diagnostics in docs-ui. This check is what caught thedocs-detail-panelbreakage. The run also lists existing strict-mode errors inside ui-core sources, which ui-core itself compiles withstrictTemplates: false. - legal-ui jest:
npx jest -c packages/plugins/legal-ui/jest.config.ts --rootDir packages/plugins/legal-ui: 1 suite, 19 tests passed. The samengccheck on itstsconfig.lib.json(strictTemplates) gives 0 diagnostics in legal-ui. - ui-core shared jest:
npx jest -c packages/ui-core/jest.config.ts --rootDir packages/ui-core shared/: 65 suites, 485 tests passed. - ui-core shared templates:
ngcon thesharedentry point (packages/ui-core/shared/src/index.ts, using ui-core'stsconfig.lib.json), run before and after the migration:- with ui-core's own settings (
strictTemplates: false): 0 errors before, 0 after; - with
strictTemplates: true: the same 128 diagnostics before and after (all existing), and none new.
- with ui-core's own settings (
- apps/gauzy: neither migrated component has a spec, and no other spec refers to them. Instead, I type-checked the whole app with the AOT compiler:
ngc -ponapps/gauzy/tsconfig.app.jsonwithnoEmit. This compiles every lazy route, including the docs-ui and ui-core sources changed here.- With the app's own settings: exit 0, no errors. The only output is 6
NG8011warnings inai-chat-react-ui, a file this PR does not touch. - With
strictTemplates: trueadded: 0 diagnostics inbilling.component.htmloredit-employee-documents.component.html.
- With the app's own settings: exit 0, no errors. The only output is 6
- nx builds (ng-packagr):
nx build ui-corepasses, and so do all 8 entry points,@gauzy/ui-core/sharedamong them.nx build plugin-legal-uipasses.nx build plugin-docs-uistops on 11TS2883errors in+state/documents.actions.ts: "the inferred type ... cannot be named without a reference to ...ts-action". This PR does not touch that file. The build fails the same way, with the same 11 errors, when the docs-ui sources are put back to the base commit. On this machinenode_modulesis a junction into another checkout, which is probably what makests-action"not portable". So I could not get a clean ng-packagr build of docs-ui here; the strictngccheck above covers its templates.
- Not run: the webpack
nx build gauzy, and no check of the UI in a browser.
Risk and rollback
These are template-syntax changes only. @for uses the existing trackBy functions where a template had one (track trackById($index, item)), and otherwise tracks by identity (track item), as *ngFor did by default. Whitespace can differ slightly where the schematic put a block on its own line (Angular collapses it, the same way it does for the old ng-container wrappers). Each path is its own commit, so one area can be reverted without touching the others.
š¤ Generated with Claude Code