Skip to content

Commit c4d51ef

Browse files
authored
Standalone Component (#622)
- Enhancement: `transitionAfterChanges`, `transitionDuringTransform`, `layoutTransitionEffect`, and `applyVisualContinuityBeforeLayout` inputs configure rich continuity when a prior graph had nodes, allowing for animations between graph updates. - Breaking: `useLayoutTransitions` (default `true` controls `layout-js-driven`; when `false` it applies only during JS `mode: 'tween'`); - Enhancement: `GraphComponent` `edgePathSampleCount` input (default 48, clamped 2–512) for edge resampling in layout, morph, and `redrawEdge` - Enhancement: `transitionAfterChanges.morphCapture` for prior translate source (model vs main-chart DOM, optional model fallback) and `syncTargetsFromPositionAfterTick` / `snapAddedNodeIds`; `mergeGraphLayoutTransition` merges `morphCapture` with defaults - Enhancement: `drawComplete` emits after a completed draw/tick pass (paths bound, graph ready). Use to hide loading UI or run one-shot center/zoomToFit without flashing before first layout. - Enhancement: Minimap can be displayed on bottom. - Fix: Observable layouts (Cola, D3 force) faster than `afterNextRender`—superseded passes repaint link paths from the current model without full `redrawLines` so layout morph is not cancelled. - Fix: Layout morph keeps `oldLine` / `oldTextPath` on paths that are not resampled-tweening until the tween ends instead of snapping to the new route early. - Fix: Drag `updateEdge` for Dagre and DagreCluster uses orientation-aware paths aligned with DagreNodesOnly. - Chore: Update Storybook with documentation, examples - Enhancement: upgrade component to latest - Enhancement: give minimap an optional margin - Fix: blocker for drawing minimap in some instances - Fix: restyle minimap colors - Fix: drawComplete should fire when all nodes are ready
1 parent 548907f commit c4d51ef

46 files changed

Lines changed: 4399 additions & 737 deletions

Some content is hidden

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

.cursor/rules/angular-20.mdc

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
description: Angular 20 best practices and coding standards for the projects/web application.
3+
globs: ['projects/web/**/*.{ts,html,scss,css}']
4+
---
5+
6+
# Angular 20 Best Practices — `projects/web`
7+
8+
## Project Structure
9+
10+
- Source root: `projects/web/src/`
11+
- App code: `src/app/` (feature modules), `src/common/` (shared), `src/orchestration/`
12+
- Path aliases: `@app/*`, `@common/*`, `@api-clients/*`, `@assets/*`, `@tests/*`, `orchestration/*`
13+
- Always use path aliases for cross-directory imports; use relative imports only within the same feature folder.
14+
15+
## TypeScript
16+
17+
- **Strict mode is NOT enabled** — `tsconfig.json` has `strict: false`, `noImplicitAny: false`, `strictNullChecks: false`. Do not assume strict checks. Be defensive with null/undefined handling. Existing `any` usage exists but should not be introduced in new code.
18+
- For TypeScript guidelines (inference, avoid any, interfaces, no magic numbers, no console.log) see **code-quality** skill.
19+
20+
## UI Library: `@swimlane/ngx-ui`
21+
22+
**Always use Swimlane ngx-ui controls** — never recreate standard UI with raw `<div>`/`<span>` + ARIA when an ngx-ui component exists.
23+
Docs: [https://swimlane.github.io/ngx-ui/](https://swimlane.github.io/ngx-ui/)
24+
25+
| Category | Components |
26+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27+
| **Buttons** | `ngx-button`, `ngx-button-toggle`, `ngx-button-toggle-group`, `ngx-long-press-button`, `ngx-plus-menu` |
28+
| **Form controls** | `ngx-input`, `ngx-input-prefix`, `ngx-input-suffix`, `ngx-input-hint`, `ngx-select`, `ngx-select-option`, `ngx-checkbox`, `ngx-toggle`, `ngx-radiobutton`, `ngx-radiobutton-group`, `ngx-slider`, `ngx-datetime`, `ngx-date-range-picker`, `ngx-codemirror` |
29+
| **Layout** | `ngx-card` (+ `ngx-card-header`, `ngx-card-body`, `ngx-card-footer`, `ngx-card-title`, `ngx-card-subtitle`, `ngx-card-avatar`, `ngx-card-tag`, `ngx-card-section`), `ngx-section`, `ngx-section-header`, `ngx-tabs`, `ngx-tab`, `ngx-toolbar`, `ngx-toolbar-content`, `ngx-split`, `ngx-split-area` |
30+
| **Navigation** | `ngx-dropdown` (+ `ngx-dropdown-toggle`, `ngx-dropdown-menu`), `ngx-navbar`, `ngx-navbar-item`, `ngx-nav-menu`, `ngx-stepper`, `ngx-step` |
31+
| **Overlays** | `ngx-dialog`, `ngx-large-format-dialog-content`, `ngx-large-format-dialog-footer`, `ngx-drawer`, `ngx-dialog-drawer-content`, `ngx-overlay` |
32+
| **Feedback** | `ngx-notification`, `ngx-nag`, `ngx-loading`, `ngx-progress-spinner`, `ngx-tip`, `ngx-alert` |
33+
| **Data** | `ngx-datatable`, `ngx-datatable-column`, `ngx-tree`, `ngx-tree-node`, `ngx-list`, `ngx-json-editor`, `ngx-json-editor-flat` |
34+
| **Directives** | `ngx-tooltip` (attribute), `[autosize]`, `[dblClickCopy]`, `[long-press]`, `[resizeObserver]` |
35+
| **Icons** | `ngx-icon` (726 usages — the most used component) |
36+
37+
- If an ngx-ui component exists for the need, **use it**. Do not build custom buttons, inputs, dropdowns, dialogs, or tabs from scratch.
38+
- Import components from `@swimlane/ngx-ui` in the component's `imports` array.
39+
40+
## Components
41+
42+
- **Any new component is standalone** — do not create non-standalone components or add new components to `NgModules`. Declare dependencies in the component’s `imports` array and import the component where it is used (or via a barrel that re-exports it).
43+
- **Implicit standalone** — do NOT set `standalone: true` in the decorator; it is the default in Angular 20.
44+
- **`ChangeDetectionStrategy.OnPush`** — required on all components.
45+
- **External templates** — use `templateUrl` with a separate `.html` file. Inline templates are not the convention here.
46+
- **Host bindings** — use the `host` object in the decorator, NOT `@HostBinding` / `@HostListener`.
47+
- **No `ngClass` / `ngStyle`** — use native `[class.active]="flag"` and `[style.font-size.px]="size"` bindings.
48+
- For structure and signal inputs/outputs see **angular-component** skill.
49+
50+
## Code Style
51+
52+
See **code-quality** skill (max ~30 lines per method, max 3 parameters, `private`, single responsibility, no business logic in components).
53+
54+
## Dependency Injection
55+
56+
- **New code:** prefer the `inject()` function. Mark injected services as `private readonly`.
57+
- **Existing code:** constructor injection is prevalent (~460 components). Do not rewrite working constructor injection unless refactoring the component.
58+
- **Do not mix** `inject()` and constructor injection within the same class.
59+
- See **angular-di** skill for tokens and providers.
60+
61+
## Signals & Reactivity
62+
63+
- **`input()` / `output()`** — use signal-based inputs and outputs for new components.
64+
- **`signal()` / `computed()`** — use for local component state and derived values.
65+
- **`effect()`** — use for signal-based side effects (e.g., logging, syncing to localStorage). Avoid heavy logic inside effects; keep them lean.
66+
- **`viewChild()` / `viewChildren()` / `contentChild()` / `contentChildren()`** — use signal-based queries instead of the `@ViewChild` / `@ContentChild` decorators.
67+
- **`linkedSignal()`** — available in Angular 20 for two-way derived signals (e.g. a writable signal that resets when a parent signal changes).
68+
- **`resource()`** — available in Angular 20 for declarative async data loading tied to signals.
69+
- **Signal updates** — use `set()` or `update()`, never `mutate()`.
70+
- Adoption is growing (~30 components). Prefer signals for all new component state.
71+
- See **angular-signals** skill for patterns.
72+
73+
## Templates
74+
75+
- **No inline logic in templates** — do not put expressions or method calls directly in template bindings. Always define a method in the component `.ts` file with a meaningful name and call it from the template. This keeps templates readable and logic testable.
76+
- **Native control flow** — always use `@if`, `@for`, `@switch`, `@empty`. **Never** use `*ngIf`, `*ngFor`, `*ngSwitch`, or any structural directive syntax in new code. The codebase has fully migrated (~4,400 usages, <25 legacy instances remaining — do not add more).
77+
- Do NOT import `CommonModule`, `NgIf`, `NgFor`, or `NgSwitch` in new components — they are not needed with built-in control flow.
78+
- **`@for` track** — always provide a `track` expression. Prefer `track item.id` over `track $index`.
79+
- **`@defer`** — use for lazy-loading heavy template sections.
80+
- **Async pipe or `toSignal()`** — never manually subscribe in templates. Use `async` pipe for observables or convert with `toSignal()`.
81+
- **Accessibility** — see the dedicated `accessibility.mdc` rule for full WCAG 2.2 AA standards.
82+
- See **angular-component** and **angular-signals** skills for template patterns.
83+
84+
## Subscriptions
85+
86+
- Never subscribe manually in components — use `async` pipe or `toSignal()`.
87+
- If you must subscribe in a service, always clean up with `takeUntilDestroyed()` or `DestroyRef`.
88+
89+
## Async: Prefer RxJS over Promises
90+
91+
Prefer RxJS Observables over Promises for all async APIs, data flows, and service methods. The codebase has undergone significant refactoring to eliminate Promise-based APIs; do not introduce new ones. See **angular-http** skill (references: Prefer Observables over Promises).
92+
93+
## Services & HTTP
94+
95+
- **`providedIn: 'root'`** for singleton services.
96+
- **Single responsibility** — one service, one concern.
97+
- **`inject()` function** preferred for new services.
98+
- **`HttpClient`** — use with typed responses. Handle errors with RxJS `catchError` or `tapResponse` in stores.
99+
- **Interceptors** — use `HttpInterceptorFn` (functional) for cross-cutting concerns (auth headers, error handling, CSRF).
100+
- **Caching** — use `shareReplay({ bufferSize: 1, refCount: true })` for shared observables that shouldn't re-fetch.
101+
- See **angular-http** and **angular-di** skills.
102+
103+
## Reactive Forms
104+
105+
- Prefer Reactive Forms (`FormGroup`, `FormControl`) over template-driven forms.
106+
- Use typed forms (`FormGroup<{ name: FormControl<string> }>`).
107+
- Use built-in and custom `ValidatorFn` / `AsyncValidatorFn` for validation — keep validation logic in the form definition, not the template.
108+
- See **angular-forms** skill (including Signal Forms reference).
109+
110+
## Testing
111+
112+
- **Framework:** Jasmine + Karma (NOT Jest). This project uses Karma + Jasmine.
113+
- **Always generate tests with new code:** for every new component, service, directive, pipe, store, guard, or resolver, create the co-located `*.spec.ts` file in the same edit. Do not deliver new production code without corresponding tests.
114+
- **Code coverage:** maintain >80% coverage for `projects/web`. New and modified code must include tests that cover main behavior and important edge cases so coverage stays above this target.
115+
- Test behavior, not implementation details.
116+
- Test file path alias: `@tests/*` → `projects/web/tests/*`.
117+
- See **angular-testing** skill for patterns (TestBed, mocking, HTTP testing, signal component tests). See **web-testing** rule for runner, coverage config, and project test utilities.
118+
119+
## Routing & Lazy Loading
120+
121+
- Lazy-load feature routes with `loadComponent` / `loadChildren`.
122+
- Heavy components can be lazy-loaded in templates with `@defer`.
123+
- Use functional route guards (`CanActivateFn`, `CanDeactivateFn`) for authentication and authorization.
124+
- Avoid direct DOM manipulation — use Angular's templating and renderer APIs instead.
125+
- See **angular-routing** skill.
126+
127+
## Format and lint after editing
128+
129+
- **After modifying any file under `projects/web`**, run format-check, then format only if needed, then lint. Use as **few files as possible** — only the files you actually changed. All commands from the **workspace root**; paths space-separated, relative to the workspace root.
130+
- **1. Check if format is required** (same file list as modified files):
131+
```bash
132+
npx nx run web:format-check --files="projects/web/src/app/foo/foo.component.ts projects/web/src/app/foo/foo.component.html"
133+
```
134+
If this fails (exit non-zero), formatting is required for those files.
135+
- **2. Format** only when format-check indicated format is needed. Use the same file list:
136+
```bash
137+
npx nx run web:format --files="projects/web/src/app/foo/foo.component.ts projects/web/src/app/foo/foo.component.html"
138+
```
139+
If you modified many files and listing them is impractical, use `npx nx run web:format-check` then `npx nx run web:format` (whole project). Prefer listing the specific files.
140+
- **3. Lint:** Always run lint with auto-fix after any format step:
141+
```bash
142+
npx nx run web:lint --fix
143+
```
144+
- Summary: run `format-check --files="..."` for the modified files; if format is required, run `format --files="..."` with the same list; then always run `npx nx run web:lint --fix`.

.cursor/rules/code-quality.mdc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
description: Linting, formatting, DRY, and clean-code requirements for all generated code in projects/web
3+
globs: ['projects/web/**/*.{ts,html,scss,css}']
4+
---
5+
6+
# Code quality — `projects/web`
7+
8+
**Generated code must** follow the repo's existing **linting and formatting**, **DRY**, **KISS**, **functional programming**, and **clean-code** principles, plus **testing requirements**. This applies to TypeScript, HTML, SCSS, and any other code in `projects/web`.
9+
10+
- **Tests:** Generate co-located `*.spec.ts` files for all new components, services, directives, pipes, stores, guards, and resolvers. Aim for >80% code coverage (see **web-testing** rule).
11+
- For lint/format/DRY/KISS/functional programming/clean-code requirements see **code-quality** skill.
12+
13+
## Cursor hook (project-specific)
14+
15+
- **`.cursor/hooks.json`** runs format and lint after each edit (`afterFileEdit`). By default it runs only for files under **allowed paths** (e.g. `projects/web`) and only on the **edited file(s)**. It uses the same tools/configs as the repo.
16+
- You can switch to full project tasks (`task format:swimlane-web`, `task lint:swimlane-web`) by setting `USE_TASK_COMMANDS = true` in **`.cursor/hooks/format-and-lint-web.mjs`**. See that file for `ALLOWED_PATHS` and options.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
name: code-quality
3+
description: Apply linting, formatting, DRY, KISS, functional programming, and clean-code principles to generated or edited code. Use for conforming to project lint/format config, avoiding duplication, and writing maintainable code. Triggers on code review, refactoring, or quality requirements.
4+
---
5+
6+
# Code quality
7+
8+
Generated or edited code must follow the project's **linting and formatting**, **DRY**, **KISS**, **functional programming** principles, and **clean-code** practices.
9+
10+
## Linting and formatting
11+
12+
- Conform to the **lint and format config already in the repo** (e.g. ESLint, Prettier).
13+
- Do not introduce lint or style violations. Run the project's linter and formatter and fix any issues before considering the change complete.
14+
15+
## DRY (Don't Repeat Yourself) — required
16+
17+
- Do not copy-paste blocks of logic or styles.
18+
- Extract repeated values into constants, variables, tokens, mixins, or shared utilities.
19+
- Reuse existing components, services, and helpers instead of duplicating behavior.
20+
21+
## KISS (Keep It Simple, Stupid) — required
22+
23+
- Prefer the **simplest solution** that solves the problem; avoid over-engineering.
24+
- Avoid unnecessary abstractions, layers, or indirection until they are justified by reuse or clarity.
25+
- Prefer clear, readable code over clever or "elegant" code when they conflict.
26+
27+
## Functional programming principles — required
28+
29+
- Prefer **pure functions** where possible: same inputs → same outputs, no side effects.
30+
- Avoid **mutable state**; prefer immutable data and updates (e.g. new objects/arrays instead of mutating in place).
31+
- Use **declarative** patterns: `map`, `filter`, `reduce`, and composition over imperative loops when they improve readability.
32+
- Keep **side effects** (I/O, DOM, subscriptions) at the edges; isolate them in services or explicit effect boundaries.
33+
34+
## Clean code — required
35+
36+
- Use full, descriptive names; avoid unnecessary abbreviations (unless a well-known project or domain term).
37+
- Keep units of code focused and single-purpose; prefer small, reusable pieces.
38+
- Avoid deep nesting and tangles; code should be easy to change without breaking unrelated behavior.
39+
- Add brief comments or JSDoc for non-obvious behavior and document _why_ when intent is not clear from the code alone.
40+
41+
## Code style (Angular / TypeScript)
42+
43+
- **Max ~30 lines per method** — extract private helpers for anything longer.
44+
- **Max 3 parameters** — use an options/config object beyond that.
45+
- **Use `private`** on internal methods and fields.
46+
- **Single responsibility** — one function does one thing.
47+
- **No business logic in components** — delegate to stores/services.
48+
49+
## TypeScript guidelines
50+
51+
- Prefer type inference where obvious; annotate return types on public methods and service APIs.
52+
- Avoid `any` — use `unknown` and type-narrow.
53+
- Define clear interfaces and types for component state, service responses, and data models. Co-locate in the feature folder or a shared `models/` directory.
54+
- No magic numbers/strings — extract to named constants or enums.
55+
- No `console.log` in production code — use `console.warn` for caught errors only.

0 commit comments

Comments
 (0)