Feature/2/migrate UI feature architecture - #4503
Conversation
…hared Story #2, PR 1 of 5. Move the framework-agnostic leaf UI out of ui/ into the feature-slice architecture: - actionIcon, errorDialog (component+service+model+po), loadingFileProgressSpinner, resetSettingsButton -> features/shared/components/ - getPartialDefaultState(+spec) -> state/store/util/ (pure store helper) Keep the slices dep-cruiser compliant: - Replace direct @ngrx/store injection in loadingFileProgressSpinner and resetSettingsButton with shared stores/ + services/ (component -> service -> store), so only stores/ touch @ngrx/store. - Convert actionIcon.component.scss to daisyUI/Tailwind host classes (cc-primary -> bg-primary, cc-emphasized -> hover:bg-secondary); drop the dead .disabled rule. - Break the errorDialog component<->service cycle by extracting ErrorDialogData into errorDialog.model.ts and typing the service host via a local interface (features may not contain internal cycles). - errorDialog.service lives under components/ so external (non-feature) callers can still import it through the slice's public surface. Behavior unchanged. tsc, full Jest suite, and dep-cruiser (0 errors) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Story #2, PR 2 of 5. Move ui/fileExtensionBar into the feature-slice architecture (components/, services/, selectors/, stores/, facade.ts) and expose the public component via features/fileExtensionBar/facade. Keep the slice dep-cruiser compliant: - Add stores/ (MetricDistributionStore, BlackListExtensionStore, DistributionMetricStore) so only stores/ touch @ngrx/store; the three services and the distributionMetric component now go component -> service -> store. BlackListExtensionStore wraps dispatchAfterPaint. - Convert the 3 SCSS files (fileExtensionBar, distributionMetric, fileExtensionBarSegment) to daisyUI/Tailwind host + utility classes; keep cc-bar-section(-text) as semantic anchors and switch the segment spec to containment selectors. - Extract the pure FileExtensionCalculator (+spec) out of the slice into util/fileExtension/. It is shared by codeMap's threeSceneService, so leaving it inside the feature created a codeMap -> fileExtensionBar -> facade -> component cycle. Moving it to util/ breaks that and pre-empts the same cycle once codeMap becomes a feature (PR 3). - Repoint threeSceneService and codeCharta.component accordingly. Behavior unchanged. tsc, full Jest suite (378 suites), and dep-cruiser (0 errors) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Story #2, PR 3 of 5. Move ui/codeMap into features/codeMap, expose its public surface via a facade, and bring it into the feature architecture. - Move the whole codeMap tree (component, render/tooltip/mouseEvent/arrow services, threeViewer/, rendering/) to features/codeMap; add facade.ts re-exporting the component + the render/tooltip/mouseEvent/three* services + CodeMapBuilding/CodeMapMesh/indicesPerNode/CodeMapPageObject. Repoint all 66 external importers (incl. ui/viewCube) to the facade. - Full ngrx stores refactor: add stores/ (codeMap, codeMapTooltip, codeMapArrow, codeMapMouseEvent, codeMapRender, threeScene) so only stores/ touch @ngrx/store; the 6 service/component files now read/dispatch through purpose-specific store accessors. Move the two pure createSelector files (+ setEdgeVisibility helper) into selectors/. - Convert codeMap.component.scss to Tailwind (Tailwind `hidden` + #codeMap utility classes; keep the id for querySelector). - Downgrade feature-no-circular-dependencies-between-features to 'warn': making codeMap a feature surfaced pre-existing bidirectional couplings codeMap<->labelSettings and codeMap<->sidebarInspector (mouse/render events drive labels; labels draw into the scene). These need dependency inversion and are tracked as a follow-up; the rule is documented to be raised back to 'error' once cleared. Behavior unchanged. tsc, full Jest suite (378 suites), and dep-cruiser (0 errors) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Story #2, PR 4 of 5. Move ui/viewCube into features/viewCube (the last ui/ folder) and finish the feature-architecture migration of the UI. - Move the cube component + meshGenerator/materials/mouseEvents service + zoomSlider into features/viewCube; add facade.ts exposing ViewCubeComponent and ViewCubeMouseEventsService. viewCube has no @ngrx/store usage, so no stores are needed. Repoint codeMap's three viewCube imports to the facade (codeMap <-> viewCube is a cross-feature cycle, allowed as a warning). - Convert the 2 SCSS files to Tailwind: viewCube host (absolute/right/ transition + [&.sideBarVisible]:right-[var(--cc-inspector-width)]) and the zoomSlider (vertical range input incl. ::-webkit/-moz thumb via arbitrary variants); tests key off data-testid, not classes. ui/ is now empty. Fix a production-build regression introduced in PR 3: the codeMap facade re-exported CodeMapPageObject from codeMap.po, which esbuild does not tree-shake, pulling codeMap.po -> playwright.helper -> node "path" into the browser bundle (ng build failed with `Could not resolve "path"`). Drop the page-object re-export, import it directly in the one cross-feature e2e, and exempt .e2e.ts/.po.ts from feature-cross-feature-only-via-public-api. Behavior unchanged. tsc, full Jest suite (378 suites), dep-cruiser (0 errors) and `ng build` (exit 0) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Story #2, PR 5 of 5. The ui/ -> features/ migration is complete (the ui/ directory was emptied and removed across PRs 1-4), so tighten the guard rails: - Broaden the dependency-cruiser SCSS rule from features/ to all of app/codeCharta/ (renamed no-component-scss-files): component SCSS is now forbidden app-wide; only the global app/app.scss + app/mixins.scss remain. - Add a CHANGELOG Chore entry summarizing the migration. Note: feature-no-circular-dependencies-between-features stays 'warn' (not raised to 'error' as originally envisioned) because making codeMap a feature surfaced real codeMap<->labelSettings and codeMap<->sidebarInspector cycles that still need dependency inversion — tracked as a follow-up. dep-cruiser (0 errors) and `ng build` (exit 0) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r codeMap/viewCube Raise feature-no-circular-dependencies-between-features back to 'error' instead of leaving it 'warn'. To keep the known rendering-cluster cycles from blocking it: - Scope the rule to cross-feature cycles only (add the same-feature `$1` exclusion the cross-feature-public-api rule uses); intra-feature cycles stay covered by the app-wide 'no-circular' warn. This stops dep-cruiser from reporting the cycles on intra-feature first-hop edges. - Grandfather the codeMap/viewCube rendering pair via pathNot. Every current cross-feature cycle edge (codeMap<->viewCube, codeMap<->labelSettings, codeMap<->sidebarInspector, viewCube->viewCubeToolbox->codeMap) touches codeMap or viewCube, so the rest of the feature graph is now enforced as an error. Verified the rule is live: injecting a legend<->metricsBar cycle errors, and the clean tree reports 0 errors. Follow-up: break the cluster cycles via dependency inversion and drop the exemption. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
idToBuilding maps node ids to CodeMapBuilding objects (a codeMap rendering concept) and was a shared service in services/ that imported codeMap while codeMap imported it back — a services->feature layering smell and one of the grandfathered codeMap cycles. - Move services/idToBuilding/idToBuilding.service.ts to features/codeMap/idToBuilding.service.ts and point its CodeMapBuilding import at the internal ./rendering/codeMapBuilding (no longer via facade). - Repoint codeMap's internal consumers (arrow, mouseEvent, threeScene) to the intra-feature path; expose IdToBuildingService via the codeMap facade for the two external consumers (sidebarExplorer, nodeContextMenu). The codeMap<->idToBuilding dependency is now intra-feature (covered by the app-wide no-circular warn) instead of a cross-feature edge. Behavior unchanged. tsc, full Jest suite (378 suites), and dep-cruiser (0 errors) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 3D-print export engine (3DPreview mesh models, geometry/color strategies, generateXML, serialize3mf) lived in services/ but is consumed only by features/3dPrint's export dialog. Move the whole services/3DExports tree to features/3dPrint/3DExports so the print engine lives with its feature. - It is largely self-contained; the only outward relative imports are codeCharta.model and codeMap's facade (indicesPerNode/CodeMapMesh) — bumped by one level for the deeper location. 3dPrint now depends one-way on codeMap via the facade (no new cycle). - Repoint the export3DMapDialog consumer to the intra-feature path and fix the serialize3mf spec's __dirname fixture path (resources/minimalScene.json). Behavior unchanged. tsc, full Jest suite (378 suites), dep-cruiser (0 errors) and `ng build` (exit 0) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ts to low layers
Structural prep (Tidy First) before turning the loaders into a feature:
- Extract CC_FILE_EXTENSION (".cc.json") from a static on LoadFileService into
model/files/files.ts, so util/fileNameHelper and util/fileDownloader stop
importing the service for a constant (removes a util->service inversion).
- Extract the MetricQueryParemter enum out of updateQueryParameters.effect into
a sibling metricQueryParameter.ts; loadInitialFile.service imported the enum
from the effect while the effect injects the service — extracting it breaks
that cycle.
- Move the pure, ngrx-free helpers fileParser, fileRoot, and urlExtractor (+spec)
from services/ into util/, where their util/state/feature consumers can use
them without a layering inversion.
No behavior change. tsc, full Jest suite (378 suites), and dep-cruiser
(0 errors) pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…File slice Move loadFile.service and loadInitialFile.service out of services/ into features/loadFile (the services/ folder is now gone), behind a facade. - Full ngrx stores refactor: only stores/ touch @ngrx/store. LoadFileStore wraps loadFile's few selects/dispatches; LoadInitialFileStore holds the ~53 dispatches that hydrate the whole store from a saved file/URL/IndexedDB (the apply*/map* settings logic moved in verbatim). The services keep the orchestration (flow, error dialogs, URL reading via UrlExtractor) and call store methods; loadInitialFile reads URL params and passes the values to LoadInitialFileStore.setMetricsFromUrlValues/setRenderState. - facade.ts exposes LoadFileService, LoadInitialFileService, sampleFile1/2. Repoint navBar, globalSettings, codeCharta.component and the updateQueryParameters effect to the facade. Behavior unchanged. tsc, full Jest suite (378 suites), dep-cruiser (0 errors) and `ng build` (exit 0) pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 314 files, which is 164 over the limit of 150. To get a review, narrow the scope: Upgrade to a paid plan to raise the limit. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (9)
📒 Files selected for processing (314)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…gration
Address the 32 new code smells flagged on the PR:
- S3863 (x27): merge the duplicate same-module imports left by repointing
several symbols to one feature facade (Biome's organizeImports is off, so it
didn't merge them). 11 files across codeMap/viewCube/loadFile facade users.
- S7735 (x3): invert the negated `if (!(key in saved)) ... else` conditions in
LoadInitialFileStore.apply{File,Dynamic,App}Settings (branch swap, equivalent).
- S2933 (x2): mark ThreeSceneService#subscription and #threeSceneStore readonly.
No behavior change. tsc, full Jest suite (378 suites), and dep-cruiser
(0 errors) pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ices
Move utils that are used exclusively by a single feature out of util/ and
co-locate them next to their consumer, following the feature-slice
architecture (features have no util/ folder):
- selectTopNByValue -> features/codeMap/
- formatCompactNumber -> features/sidebarExplorer/
- clipboardWriter -> features/viewCubeToolbox/services/
- loadFilesValidationToErrorDialog -> features/loadFile/services/
- uploadFiles/{createCCFileInput,readFiles} -> features/navBar/services/
- pipes/removeExtension.pipe -> features/navBar/
Also relocate the misplaced loadFilesValidationToErrorDialog.spec.ts (it
sat under util/uploadFiles/) next to its source, and fix the clipboardWriter
spec filename casing. Shared utils (algorithm/, codeMapHelper, color/,
blacklist/, ...) remain in util/.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|



{Meaningful title}
Please read the CONTRIBUTING.md before opening a PR.
Closes: #
Description
Descriptive pull request text, answering:
Definition of Done
A PR is only ready for merge once all the following acceptance criteria are fulfilled:
Screenshots or gifs