Skip to content

Commit f95015d

Browse files
ChristianHuehnchristian-huehn-mwclaude
authored
Feature/1/go zoneless (#4502)
* refactor(visualization): add OnPush to features/ components for zoneless (#1) Backfill ChangeDetectionStrategy.OnPush across all 25 features/ components (3dPrint, changelog, globalSettings, scenarios). Convert importFeedbackDialog's mutable feedback field to a signal so it updates under OnPush/zoneless. Part of the convert-first, flip-last zoneless migration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(visualization): add OnPush to ui/ + root components for zoneless (#1) Backfill ChangeDetectionStrategy.OnPush across all remaining ui/ components and the root codeCharta component. Convert fileExtensionBar's metricDistribution subscribe to a requireSync toSignal and showAbsoluteValues to a signal so they update under OnPush/zoneless. All async sources (viewCube Three.js callbacks render directly; zoomSlider uses detectChanges; segment/dialogs/buttons set signals) are zoneless-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(visualization): run unit tests zoneless (#1) Switch the Jest test env from setupZoneTestEnv to setupZonelessTestEnv so TestBed uses zoneless change detection, matching the app target. Drop zone.js/testing from the angular.json karma test polyfills. Fixes surfaced by removing zone's error/rejection swallowing: - Remove waitForAsync wrappers around synchronous TestBed setup (needs zone). - Polyfill the JSDOM Popover API (:popover-open, show/hide/togglePopover). - ScenarioIndexedDBService: await the request and tx.done together so an aborted transaction's done rejection is always handled (no orphaned reject). - Stub the heavy 3D export dialog in the export3DMapButton button test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(visualization)!: enable zoneless change detection, remove zone.js (#1) Flip the app to provideZonelessChangeDetection and drop zone.js entirely: - main.ts: provideZoneChangeDetection -> provideZonelessChangeDetection, remove the zone.js side-effect import. - angular.json: empty the build polyfills (no zone.js needed; modern browsers). - Delete the dead app/polyfills.ts and drop it from tsconfig.app.json. - Uninstall zone.js from package.json and refresh the lockfile. All components are OnPush and every async source is signal/markForCheck driven, so change detection is now fully explicit. The production bundle ships zero zone symbols. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * build(visualization): remove unused dependencies Drop dependencies no longer referenced anywhere in source or build config: @ngrx/operators, @ngrx/store-devtools, percent-round, @babel/plugin-transform-class-static-block, autoprefixer, html-loader, webpack-glsl-loader. Remove the now-obsolete @ngrx/store-devtools exception from the dependency-cruiser ngrx rule. Verified: dependency-cruiser passes (0 errors), production build succeeds, full unit suite (2244 tests) green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Christian Hühn <christian.huehn@maibornwolff.de> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent af03fd0 commit f95015d

52 files changed

Lines changed: 239 additions & 1131 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

visualization/.dependency-cruiser.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ module.exports = {
9898
pathNot: ["^app/codeCharta/features/[^/]+/(stores|selectors)/", "\\.spec\\.ts$"]
9999
},
100100
to: {
101-
path: "@ngrx/store",
102-
pathNot: "@ngrx/store-devtools"
101+
path: "@ngrx/store"
103102
}
104103
}
105104
],

visualization/angular.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"outputPath": "dist/bundler",
2424
"index": "app/index.html",
2525
"browser": "app/main.ts",
26-
"polyfills": ["zone.js"],
26+
"polyfills": [],
2727
"tsConfig": "tsconfig.app.json",
2828
"inlineStyleLanguage": "scss",
2929
"loader": {
@@ -85,7 +85,7 @@
8585
"test": {
8686
"builder": "@angular/build:karma",
8787
"options": {
88-
"polyfills": ["zone.js", "zone.js/testing"],
88+
"polyfills": [],
8989
"tsConfig": "tsconfig.spec.json",
9090
"inlineStyleLanguage": "scss",
9191
"assets": [

visualization/app/codeCharta/codeCharta.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnInit, signal } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, OnInit, signal } from "@angular/core"
22
import { Store } from "@ngrx/store"
33
import { LoadInitialFileService } from "./services/loadInitialFile/loadInitialFile.service"
44
import { setIsLoadingFile } from "./state/store/appSettings/isLoadingFile/isLoadingFile.actions"
@@ -31,7 +31,8 @@ import { ErrorDialogComponent } from "./ui/dialogs/errorDialog/errorDialog.compo
3131
ChangelogDialogComponent,
3232
ErrorDialogComponent,
3333
BottomBarComponent
34-
]
34+
],
35+
changeDetection: ChangeDetectionStrategy.OnPush
3536
})
3637
export class CodeChartaComponent implements OnInit {
3738
isInitialized = signal(false)

visualization/app/codeCharta/features/3dPrint/components/export3DMapButton/export3DMapButton.component.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1+
import { Component, output } from "@angular/core"
12
import { TestBed } from "@angular/core/testing"
23
import { State, Store } from "@ngrx/store"
34
import { render, screen } from "@testing-library/angular"
45
import { of } from "rxjs"
56
import { ColorMode } from "../../../../codeCharta.model"
67
import { setColorMode } from "../../../../state/store/dynamicSettings/colorMode/colorMode.actions"
8+
import { ActionIconComponent } from "../../../../ui/actionIcon/actionIcon.component"
9+
import { ErrorDialogComponent } from "../../../../ui/dialogs/errorDialog/errorDialog.component"
710
import { Export3DMapButtonComponent } from "./export3DMapButton.component"
811

12+
// The real export dialog needs a fully initialized Three.js scene in its constructor.
13+
// This button test only cares about the showDialog signal, so the dialog is stubbed.
14+
@Component({ selector: "cc-export-3D-map-dialog", template: "", standalone: true })
15+
class StubExport3DMapDialogComponent {
16+
readonly closed = output<void>()
17+
}
18+
19+
const componentImports = [ActionIconComponent, ErrorDialogComponent, StubExport3DMapDialogComponent]
20+
921
describe("Export3DMapButtonComponent", () => {
1022
beforeEach(() => {
1123
TestBed.configureTestingModule({
@@ -21,7 +33,7 @@ describe("Export3DMapButtonComponent", () => {
2133
})
2234

2335
it("should render the button", async function () {
24-
await render(Export3DMapButtonComponent)
36+
await render(Export3DMapButtonComponent, { componentImports })
2537
const exportButton = screen.getByRole("button")
2638
expect(exportButton).not.toBe(null)
2739
})
@@ -32,6 +44,7 @@ describe("Export3DMapButtonComponent", () => {
3244

3345
const { fixture } = await render(Export3DMapButtonComponent, {
3446
excludeComponentDeclaration: true,
47+
componentImports,
3548
providers: [
3649
{ provide: State, useValue: state },
3750
{ provide: Store, useValue: store }
@@ -54,6 +67,7 @@ describe("Export3DMapButtonComponent", () => {
5467

5568
const { fixture } = await render(Export3DMapButtonComponent, {
5669
excludeComponentDeclaration: true,
70+
componentImports,
5771
providers: [
5872
{ provide: State, useValue: state },
5973
{ provide: Store, useValue: store }
@@ -78,6 +92,7 @@ describe("Export3DMapButtonComponent", () => {
7892

7993
const { fixture } = await render(Export3DMapButtonComponent, {
8094
excludeComponentDeclaration: true,
95+
componentImports,
8196
providers: [
8297
{ provide: State, useValue: state },
8398
{ provide: Store, useValue: store }

visualization/app/codeCharta/features/3dPrint/components/export3DMapButton/export3DMapButton.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, signal, viewChild } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, signal, viewChild } from "@angular/core"
22
import { take } from "rxjs"
33
import { ColorMode } from "../../../../codeCharta.model"
44
import { ActionIconComponent } from "../../../../ui/actionIcon/actionIcon.component"
@@ -9,7 +9,8 @@ import { Export3DMapDialogComponent } from "../export3DMapDialog/export3DMapDial
99
@Component({
1010
selector: "cc-export-3d-map-button",
1111
templateUrl: "./export3DMapButton.component.html",
12-
imports: [ActionIconComponent, Export3DMapDialogComponent, ErrorDialogComponent]
12+
imports: [ActionIconComponent, Export3DMapDialogComponent, ErrorDialogComponent],
13+
changeDetection: ChangeDetectionStrategy.OnPush
1314
})
1415
export class Export3DMapButtonComponent {
1516
showDialog = signal(false)

visualization/app/codeCharta/features/3dPrint/components/export3DMapDialog/export3DMapDialog.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AfterViewInit, Component, ElementRef, output, signal, viewChild } from "@angular/core"
1+
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, output, signal, viewChild } from "@angular/core"
22
import { Color, Mesh, PerspectiveCamera, Scene, ShaderMaterial, Vector3, WebGLRenderer } from "three"
33
import { OrbitControls } from "three/addons/controls/OrbitControls.js"
44
import { STLExporter } from "three/addons/exporters/STLExporter.js"
@@ -36,7 +36,8 @@ import { SecondRowTextInputComponent } from "./secondRowTextInput/secondRowTextI
3636
QrCodeSettingsComponent,
3737
LogoUploadComponent,
3838
ExportActionsComponent
39-
]
39+
],
40+
changeDetection: ChangeDetectionStrategy.OnPush
4041
})
4142
export class Export3DMapDialogComponent implements AfterViewInit {
4243
dialog = viewChild.required<ElementRef<HTMLDialogElement>>("dialog")

visualization/app/codeCharta/features/3dPrint/components/export3DMapDialog/exportActions/exportActions.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Component, input, output } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, input, output } from "@angular/core"
22

33
@Component({
44
selector: "cc-export-actions",
5-
templateUrl: "./exportActions.component.html"
5+
templateUrl: "./exportActions.component.html",
6+
changeDetection: ChangeDetectionStrategy.OnPush
67
})
78
export class ExportActionsComponent {
89
isPrintMeshLoaded = input.required<boolean>()

visualization/app/codeCharta/features/3dPrint/components/export3DMapDialog/frontTextInput/frontTextInput.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Component, input, output } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, input, output } from "@angular/core"
22

33
@Component({
44
selector: "cc-front-text-input",
5-
templateUrl: "./frontTextInput.component.html"
5+
templateUrl: "./frontTextInput.component.html",
6+
changeDetection: ChangeDetectionStrategy.OnPush
67
})
78
export class FrontTextInputComponent {
89
frontText = input<string>("")

visualization/app/codeCharta/features/3dPrint/components/export3DMapDialog/logoUpload/logoUpload.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { Component, ElementRef, input, output, viewChild } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, ElementRef, input, output, viewChild } from "@angular/core"
22
import { InlineColorPickerComponent } from "../../../../shared/components/inlineColorPicker/inlineColorPicker.component"
33

44
@Component({
55
selector: "cc-logo-upload",
66
templateUrl: "./logoUpload.component.html",
7-
imports: [InlineColorPickerComponent]
7+
imports: [InlineColorPickerComponent],
8+
changeDetection: ChangeDetectionStrategy.OnPush
89
})
910
export class LogoUploadComponent {
1011
fileInput = viewChild.required<ElementRef<HTMLInputElement>>("fileInput")

visualization/app/codeCharta/features/3dPrint/components/export3DMapDialog/printerPresetSelection/printerPresetSelection.component.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, input, output } from "@angular/core"
1+
import { ChangeDetectionStrategy, Component, input, output } from "@angular/core"
22

33
export interface Printer {
44
name: string
@@ -16,7 +16,8 @@ export const PRINTER_PRESETS: Printer[] = [
1616

1717
@Component({
1818
selector: "cc-printer-preset-selection",
19-
templateUrl: "./printerPresetSelection.component.html"
19+
templateUrl: "./printerPresetSelection.component.html",
20+
changeDetection: ChangeDetectionStrategy.OnPush
2021
})
2122
export class PrinterPresetSelectionComponent {
2223
selectedPrinter = input.required<Printer>()

0 commit comments

Comments
 (0)