Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@imolorhe
Copy link
Collaborator

@imolorhe imolorhe commented Oct 8, 2025

Fixes

Checks

  • Ran yarn test-build
  • Updated relevant documentations
  • Updated matching config options in altair-static

Changes proposed in this pull request:

Summary by CodeRabbit

  • Refactor
    • Migrated numerous UI components and services to use Angular reactive signals for inputs and state, replacing traditional @input bindings and constructor injection. This unifies data access patterns across dialogs, editors, viewers, headers, panels, and services.
    • Transitioned dependency injection from constructor parameters to inline Angular inject() calls throughout components, services, effects, and directives, simplifying initialization.
    • Updated templates to use function-call bindings for data and state, improving consistency and reactivity.
  • Performance
    • Enhanced reactive state management and effect-driven updates in key components like doc viewer, query editor, and collection dialogs for smoother UI responsiveness.
  • Bug Fixes
    • Improved null-safety in account-related UI displays and conditional rendering.
    • Added explicit button type attributes to prevent accidental form submissions.
    • Refined safer bindings and signal usage eliminated binding inconsistencies.
  • Tests
    • Updated unit and integration tests to adapt to reactive input patterns and new signal-based public APIs, ensuring robust coverage of refactored components and effects.
  • Style
    • Standardized HTML templates with self-closing tags for components and icons, cleaner bindings, and consistent attribute formatting.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @imolorhe, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai
Copy link

coderabbitai bot commented Oct 8, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Migrates many Angular components/services/effects from @Input/constructor DI to signal/model/input() and inject(), updates templates to call inputs as functions, replaces lifecycle hooks with computed/effect, normalizes markup (self-closing tags, button types), upgrades linting/dev deps, and adjusts a few types/actions.

Changes

Cohort / File(s) Change summary
Components β€” inputs β†’ signals (bulk)
packages/altair-app/src/app/modules/altair/components/** (e.g., dialog/*, account-dialog/*, action-bar/*, beta-indicator/*, plugin-manager/*, settings-dialog/*, teams-dialog/*, history-dialog/*, import-curl-dialog/*, request-handler-dialog/*, request-extensions-dialog/*, query-revision-dialog/*, edit-collection-dialog/*, add-collection-query-dialog/*, set-variable-dialog/*, variables-editor/*, variable-file-item/*, fancy-input*, x-input/*, icon/*, banner/*, query-editor/*, query-result/*, query-collections/*, query-collection-item/*, codemirror/*, url-box/*, ...)
Replaced many @Input()s with readonly ... = input(...) / model(...) / signal(...); templates updated to call inputs (e.g., prop()), adapted code to use signals/computeds/effects, typed some EventEmitters, and converted many tags to self-closing and added explicit type="button".
Templates β€” property β†’ call & markup fixes
Numerous .html files across components
Converted template expressions from property access to callable signal access (e.g., foo β†’ foo() / foo() as foo), adjusted attribute bindings (aria, nzCloseIcon), normalized self-closing tags, and added explicit button types.
Services & Effects β€” constructor DI β†’ inject()
packages/altair-app/src/app/modules/altair/services/**, .../effects/**, altair.module.ts, .../store/reducer-bootstrapper.ts
Removed many constructor parameters; dependencies now declared via private foo = inject(FooService) fields; constructors simplified/removed across services, effects, module bootstrapper and many services.
Editor / Query / Collections
.../query-editor/*, .../query-result/*, .../query-collections/*, .../query-collection-item/*, .../codemirror/*, .../url-box/*
Major refactors to signals/computeds: inputs β†’ signals, editor value now a signal, debounced computed search, CodeMirror extensions built from signal getters, and templates adapted to new APIs.
Doc viewer & Schema form
.../doc-viewer/**, .../schema-form/**
Inputs converted to signals/computed, added computed helpers (fieldType/typeData), template bindings updated to call accessors, list/item components moved to model/signal patterns and emit via explicit change handlers.
Windowing, Header & Switcher
.../window/*, .../window-switcher/*, .../window-switcher-item/*, .../header/*, .../element-wrapper/*
Inputs become signals; templates and methods now use windowId()/windowIds() etc.; added computed helpers (iconState, isWindowUnsaved, isWindowInCollection); adapted observables to toObservable(this.windowId).
Directives & Theming
.../directives/* (e.g., cached-if, set-css-variables, theme.directive.ts)
Replaced Input setters and OnChanges/OnInit with input() signals and effect() blocks to manage cached views, apply CSS variables and reapply theme/CSP nonce reactively.
Testing infra & wrappers
packages/altair-app/src/testing/**, packages/altair-app/src/testing/wrapper/*, many spec files
Test utilities updated to understand signal inputs (ComponentMeta, AllowedPropsDataKeys/Value), buildTestHostComponentTemplate/mount API changed, wrapper.setProps became async, many specs updated to use .set(...) or .setInput(...) and TestBed-based injection.
Types, actions & small libs
services/gql/generateQuery.ts, gql.service.ts, helpers.ts, store/collection/collection.action.ts, workspace.interface.ts, basic.ts
Small type and API tweaks: explicit local typings, collection action ID types changed number→string, removed as const from WORKSPACES, replaced dynamic abab.btoa with global btoa, helper typing refinements.
Linting & tooling
packages/altair-app/.eslintrc.js, packages/altair-app/e2e/.eslintrc.json, packages/altair-app/package.json
ESLint configs switched to stricter rule sets (plugin:@angular-eslint/all/template/all), added @angular-eslint/no-uncalled-signals in e2e config, and bumped @angular-eslint / @typescript-eslint devDependencies.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Parent as Parent Component
  participant Child as Refactored Component
  note right of Child #F6FBFF: public inputs exposed as signals via input()/model()/signal()
  Parent->>Child: bind [prop]="value"
  activate Child
  Child->>Child: Angular sets signal value (prop.set)
  Child->>Child: computed/effect runs (update internal state)
  Child->>Parent: template reads via prop() rendering output
  deactivate Child
  alt Parent updates bound value
    Parent->>Child: new value bound
    Child->>Child: signal updates β†’ recomputed effects β†’ re-render
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • sourcery-ai

Poem

I nibbled props and swapped them for calls,
I hopped through templates and tiny signals' halls.
Computeds hum softly, effects wake and play,
Buttons now honest, and tags closed away.
The rabbit refactored, then hopped off to play. πŸ₯•

Pre-merge checks and finishing touches

βœ… Passed checks (3 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check βœ… Passed The title succinctly describes the primary refactor to adopt Angular signals across the codebase, matching the extensive migration of component state and input bindings to signal-based accessors. It is clear, concise, and directly related to the changeset, avoiding vagueness or off-topic noise.
Docstring Coverage βœ… Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch imolorhe/signals-migration

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.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @imolorhe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request is a large-scale migration to Angular Signals, converting numerous @Input() properties to input() signals across many components and updating their usage in both templates and component logic. This refactoring aligns the codebase with Angular's new reactive primitive for improved performance and maintainability.

Highlights

  • Intent: This pull request aims to migrate various Angular components to use the new Angular Signals API. This is a significant refactoring effort to adopt a more reactive and performant change detection mechanism.
  • Key Changes: The primary change across numerous components involves converting @Input() properties into input() signals. This includes:
  1. Component TypeScript Files: Replaced @Input() propertyName = defaultValue; with readonly propertyName = input(defaultValue); for most input properties.
  2. Component Templates: Updated all references to these input properties from propertyName to propertyName() to correctly access the signal's value.
  3. Component Logic: Modified internal component logic to call propertyName() when reading the value of an input signal.
  4. New Signal Primitives: Introduced input and computed imports from @angular/core where necessary, such as in QueryEditorComponent for derived state like isAuthorizationEnabled.

This migration impacts a wide range of components, including dialogs, editors, doc viewers, and various UI elements, ensuring consistency with the new signal-based reactivity model.

  • Reviewer Activity: No reviewer activity has been recorded yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with πŸ‘ and πŸ‘Ž on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@github-actions
Copy link

github-actions bot commented Oct 8, 2025

Visit the preview URL for this PR (updated for commit e8c26bd):

https://altair-gql--pr2905-imolorhe-signals-mig-cxc5lzog.web.app

(expires Sat, 18 Oct 2025 22:13:03 GMT)

πŸ”₯ via Firebase Hosting GitHub Action 🌎

Sign: 02d6323d75a99e532a38922862e269d63351a6cf

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request focuses on migrating Angular components from using the @Input() decorator to the new signal-based input() function. This is a great step towards modernizing the application and leveraging Angular's new reactivity model.

My review has identified two main areas for improvement:

  1. Inconsistent Migration: In several components, some @Input() decorators have been migrated while others have not. For consistency and to fully embrace the new pattern, it would be best to migrate all inputs in the modified components.
  2. Lifecycle Hook Usage: A number of components use ngOnInit or ngOnChanges to react to changes in input values. With signal-based inputs, it is more idiomatic and robust to use effect() or computed() to react to these changes. This avoids potential bugs where the component does not update if the input changes after initialization.

I've left detailed comments on the specific files where these issues occur. Addressing them will improve the code's maintainability and correctness.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (1)

43-48: Signal inputs do not trigger ngOnChanges.

The component still implements OnChanges and relies on ngOnChanges to detect changes to the schema input. With signal-based inputs, the ngOnChanges lifecycle hook will NOT be triggered when signal values change. This breaks the component's ability to react to schema updates after initialization.

To fix this, replace ngOnChanges with Angular's effect() to reactively handle signal changes:

Apply this diff:

-import {
-  Component,
-  OnInit,
-  SimpleChanges,
-  OnChanges,
-  EventEmitter,
-  Output,
-  ChangeDetectionStrategy,
-  input
-} from '@angular/core';
+import {
+  Component,
+  OnInit,
+  EventEmitter,
+  Output,
+  ChangeDetectionStrategy,
+  input,
+  effect
+} from '@angular/core';
-export class SchemaFormComponent implements OnInit, OnChanges {
+export class SchemaFormComponent implements OnInit {
   readonly schema = input({});
   readonly data = input(null);

   @Output() dataChange = new EventEmitter<IDictionary>();

   schemaProperties: SchemaFormProperty[] = [];
   formData: IDictionary = {};

+  constructor() {
+    effect(() => {
+      const schema = this.schema();
+      if (schema) {
+        this.updateSchemaProperties(schema);
+      }
+    });
+  }
+
   ngOnInit() {
-    // console.log('SCHEMA:', this.schema);
-    const schema = this.schema();
-    if (schema) {
-      this.updateSchemaProperties(schema);
-    }
+    // Initial update handled by effect
   }

-  ngOnChanges(changes: SimpleChanges) {
-    // If there is a new schema, update the schema properties
-    if (changes?.schema?.currentValue) {
-      this.updateSchemaProperties(changes.schema.currentValue);
-    }
-  }
-
🧹 Nitpick comments (22)
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (2)

35-35: Consider completing the signal input migration for consistency.

The migration of showEnvironmentManager to a signal-based input using input() is correctly implemented. However, the component now has mixed input patterns:

  • Line 35: showEnvironmentManager uses input() (signal-based)
  • Line 34: environments still uses @Input() (decorator-based)

For consistency and maintainability, consider migrating the remaining @Input() decorator to input() as well.

Note: This signals migration represents an intentional architectural shift in the PR. While previous learnings indicated using @Input decorators, Angular 17.1+ signal-based inputs offer improved change detection and type safety. Based on learnings.


34-35: Consider completing the signal input migration for consistency.

The showEnvironmentManager property has been migrated to a signal input, but the environments property on line 34 still uses the @Input decorator. This creates an inconsistency within the same component.

For a more uniform API and to fully benefit from the signal migration, consider migrating environments as well:

-@Input() environments?: EnvironmentsState;
+readonly environments = input<EnvironmentsState>();

If migrated, you'd also need to update all internal references from this.environments to this.environments() throughout the component (lines 58, 59, 64, 110, 116, 118).

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (1)

27-28: Consider adding explicit type annotations.

The signal declarations are correctly implemented with readonly and proper default values. However, explicit type annotations would improve type safety and code clarity.

Apply this diff to add type annotations:

-  readonly schema = input({});
-  readonly data = input(null);
+  readonly schema = input<JSONSchema6>({});
+  readonly data = input<IDictionary | null>(null);
packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts (1)

11-11: Note: Migration pattern conflicts with coding guidelines.

The coding guidelines specify "Use Input and Output decorators to define the component API," but this PR adopts Angular 17+'s signal-based input() function, which is the modern recommended pattern for reactive inputs.

While this conflicts with the existing guidelines, the input() approach is a best practice for Angular 17+ and provides better type safety and reactivity. Consider updating the coding guidelines to reflect this migration strategy.

Based on learnings.

Also applies to: 37-37, 40-41

packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.ts (1)

6-6: Signal-based inputs are correct; update coding guidelines
The migration from @input() to input() aligns with Angular 17+ best practices. The existing guideline requiring @Input/@output is now outdatedβ€”please update it to allow (or prefer) signal-based inputs and plan migrating the remaining components still using @input().

packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-search-results/doc-viewer-search-results.component.ts (1)

49-49: Migrate remaining outputs to signals or update guidelines

All components (e.g., doc-viewer-search-results) still use @Output()/EventEmitter and no output() signals were detected. For consistency, either replace these with readonly foo = output<…>(); or revise the guideline to permit mixing.

packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

89-89: Improve type casting for array check.

The cast as [] is too narrow. Use as any[] or check the type properly before casting.

   this.invalidFileData =
-    (this.fileVariable()?.data as [])?.length > this.validFileData.length;
+    (this.fileVariable()?.data as any[])?.length > this.validFileData.length;
packages/altair-app/src/app/modules/altair/components/fancy-input-marker/fancy-input-marker.component.ts (1)

31-33: Signal access pattern correctly applied.

The function-call syntax this.section().content correctly retrieves the signal's value. The logic properly hydrates the resolved value using the environment service.

Optional enhancement: While ngOnChanges works correctly with signal inputs, consider using signal-based reactivity patterns for consistency:

import { Component, input, effect } from '@angular/core';

export class FancyInputMarkerComponent {
  readonly section = input<HighlightSection>({ content: '' });
  readonly activeEnvironment = input<IDictionary>({});
  
  resolvedValue = '';

  constructor(private environmentService: EnvironmentService) {
    effect(() => {
      this.resolvedValue = this.environmentService.hydrate(this.section().content);
    });
  }
}

This approach leverages signal reactivity more idiomatically and eliminates the need for the OnChanges lifecycle hook.

packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.ts (1)

26-34: Template binding is correctβ€”no direct size usage

  • The template applies [ngStyle]="styles" computed in ngOnInit; it doesn’t reference size or size(), so no changes needed.
  • Optional: replace the ngOnInit style assignment with a computed() signal for styles to embrace Angular 17+ reactive patterns.
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (1)

9-9: Verify the partial input migration.

Four inputs (showCollections, sortBy, queriesSortBy, loggedIn) were migrated to signal-based inputs, but collections and workspaces (lines 30-37) remain as @Input() with setters. This partial migration creates an inconsistent component API.

Confirm whether the setters (which pipe values into BehaviorSubjects) are the reason these weren't migrated, or if this is an oversight.

If the setter logic is the blocker, consider refactoring to use signal-based patterns with effect() to synchronize with the BehaviorSubjects:

readonly collections = input<IQueryCollection[] | undefined>(undefined);
readonly workspaces = input<WorkspaceOption[]>([]);

constructor(private collectionService: QueryCollectionService) {
  effect(() => {
    const cols = this.collections();
    if (cols) {
      this.collections$.next(cols);
    }
  });
  effect(() => {
    this.workspaces$.next(this.workspaces());
  });
}

Also applies to: 29-29, 38-40

packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts (1)

28-28: Document or migrate collectionTree input for consistency

The collectionTree property remains a classic @Input(), while loggedIn, queriesSortBy, and expanded have been migrated to signals. Either migrate collectionTree to a signal input (e.g. readonly collectionTree = input<IQueryCollectionTree|undefined>(undefined); and update usages to this.collectionTree()) or add a code comment explaining why it’s intentionally excluded.

packages/altair-app/src/app/modules/altair/components/tips/tips.component.ts (2)

91-91: Signal invocations are correct; consider using effect() for more idiomatic signal reactivity.

The signal invocations (this.activeWindowId(), this.windowId(), this.loading()) correctly retrieve values from the signal-based inputs.

However, the component still uses ngOnChanges to react to input changes. With signal-based inputs, using Angular's effect() function would be more idiomatic:

import { effect } from '@angular/core';

constructor() {
  effect(() => {
    // Automatically re-runs when any signal read inside changes
    if (this.activeWindowId() === this.windowId() && !this.loading()) {
      // setup interval logic
    }
  });
}

Note: ngOnChanges still works with signal inputs, so this is an optional refactor rather than a required fix.


30-32: Signal migration correct; no template invocation changes needed.
Optional: add explicit type generics to input(), e.g., readonly activeWindowId = input<string>('').

packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts (1)

42-42: Migrate requestScriptLogs to input(...)
Replace the decorator-based input with a signal-based input for consistency:

-  @Input() requestScriptLogs: LogLine[] = [];
+  readonly requestScriptLogs = input<LogLine[]>([]);

If this property must remain mutable, add a comment explaining why it’s excluded from the migration.

packages/altair-app/src/app/modules/altair/components/action-bar/action-bar.component.ts (1)

6-6: LGTM! Consider explicit type annotations.

The migration is correct and both boolean inputs are properly converted to signals with default values.

For improved type clarity and consistency with other files in this PR (e.g., post-request-editor.component.ts line 21), consider adding explicit type parameters:

-  readonly showDocs = input(false);
-  readonly isSubscribed = input(false);
+  readonly showDocs = input<boolean>(false);
+  readonly isSubscribed = input<boolean>(false);

Also applies to: 17-18

packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts (1)

216-220: Remove redundant store selection

This select(...) call without subscription is a no-op and should be removed.

-          const windowId = self.windowId();
-          self.store.select(selectActiveEnvironmentsList(windowId));
+          const windowId = self.windowId();
           this.unsubscribe = self.store
             .select(selectActiveEnvironmentsList(windowId))
             .subscribe((list) => {
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)

1-1: Tidy imports and enable OnPush change detection

  • Remove unused OnInit import.
  • Prefer ChangeDetectionStrategy.OnPush (project guideline).
-import { Component, OnInit, input } from '@angular/core';
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';

Apply outside this range in the decorator:

 @Component({
   selector: 'app-beta-indicator',
   templateUrl: './beta-indicator.component.html',
-  styles: [],
+  styles: [],
+  changeDetection: ChangeDetectionStrategy.OnPush,
   standalone: false,
 })

As per coding guidelines

packages/altair-app/src/app/modules/altair/components/upgrade-dialog/upgrade-dialog.component.ts (1)

22-24: Use computed() for proPlanInfo and call signal getters in template

  • Signal inputs still fire ngOnChanges in Angular 17.1.x, but the recommended pattern is
    readonly proPlanInfo = computed(() =>
      this.planInfos().find(p => p.role === 'pro')
    );
  • Invoke your signals in the template as functions: showDialog(), userPlan(), and planInfos().
packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.ts (1)

21-31: Migrate remaining @input properties to signal-based inputs.
Convert apiUrl, selectedOperation, and streamState to use readonly … = input() since they don’t require two-way binding.

packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.ts (1)

19-23: Type your outputs; keep API clear

EventEmitters are untyped; add generics for stronger API. Mixing classic @Input (showDialog) with signal inputs is OK.

-  @Output() toggleDialog = new EventEmitter();
-  @Output() saveChange = new EventEmitter();
+  @Output() toggleDialog = new EventEmitter<boolean>();
+  @Output() saveChange = new EventEmitter<Event>();

Also applies to: 24-26, 27-35

packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.ts (1)

52-71: Prefer emit() over next() for EventEmitter; type outputs

For consistency and clarity, use emit() and add generics.

-  @Output() activeWindowChange = new EventEmitter();
+  @Output() activeWindowChange = new EventEmitter<string>();
@@
-    this.activeWindowChange.next(windowId);
+    this.activeWindowChange.emit(windowId);
@@
-  @Output() windowNameChange = new EventEmitter();
+  @Output() windowNameChange = new EventEmitter<{ windowId: string; windowName: string }>();
@@
-      this.windowNameChange.next({ windowId, windowName });
+      this.windowNameChange.emit({ windowId, windowName });
@@
-  @Output() removeWindowChange = new EventEmitter();
+  @Output() removeWindowChange = new EventEmitter<string>();
@@
-    return this.removeWindowChange.next(windowId);
+    return this.removeWindowChange.emit(windowId);
@@
-  @Output() reorderWindowsChange = new EventEmitter<string[]>();
+  @Output() reorderWindowsChange = new EventEmitter<string[]>();
@@
-    this.reorderWindowsChange.next(windowIds);
+    this.reorderWindowsChange.emit(windowIds);
@@
-  @Output() duplicateWindowChange = new EventEmitter();
+  @Output() duplicateWindowChange = new EventEmitter<string>();
@@
-    this.duplicateWindowChange.next(windowId);
+    this.duplicateWindowChange.emit(windowId);

Also applies to: 73-91, 93-99, 101-107

packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.ts (1)

28-34: Use an effect to react to collections signal changes
While signal-based inputs still fire ngOnChanges, an effect ensures setTreeNodes() runs whenever collections() updates:

-import { Component, Output, EventEmitter, Input, OnChanges, SimpleChanges, input } from '@angular/core';
+import { Component, Output, EventEmitter, Input, OnChanges, SimpleChanges, input, effect } from '@angular/core';
@@
 export class AddCollectionQueryDialogComponent implements OnChanges {
@@
   constructor(private collectionService: QueryCollectionService) {
     effect(() => {
       const cols = this.collections();
       if (cols) this.setTreeNodes(cols);
     });
   }

Also apply the same pattern at lines 51–59.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (9)
packages/altair-app/src/app/modules/altair/components/header/header.component.html (1)

63-75: Fix inactive-environment guard

activeEnvironment is now a signal; comparing the signal function itself to undefined always returns false, so the β€œno environment” fallback never renders. Call the signal (or use @else) when checking for an undefined value.

-      @if (activeEnvironment === undefined) {
+      @if (activeEnvironment() === undefined) {
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (1)

102-139: Fix signal value emitted on outputs.

Line 102, Line 113, and Line 138 emit this.selectedEnvironmentId directly, which passes the signal function instead of the current environment id. Parents will receive a callable object rather than the expected string, breaking downstream logic. Call the signal to read its value before emitting.

         this.subEnvironmentJsonChange.next({
-          id: this.selectedEnvironmentId,
+          id: this.selectedEnvironmentId(),
           value: content,
         });
@@
     this.subEnvironmentTitleChange.next({
-      id: this.selectedEnvironmentId,
+      id: this.selectedEnvironmentId(),
       value: content,
     });
@@
-      this.deleteSubEnvironmentChange.next({ id: this.selectedEnvironmentId });
+      this.deleteSubEnvironmentChange.next({ id: this.selectedEnvironmentId() });
packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)

408-415: Invoke the signal when checking dialog visibility

this.showVariableDialog is now an InputSignal<boolean>, so the truthy function object makes this guard perpetually pass and the resize validator no longer blocks actions when the dialog is hidden. Call the signal to restore the original behaviour.

-    if (!this.showVariableDialog) {
+    if (!this.showVariableDialog()) {
packages/altair-app/src/app/modules/altair/components/codemirror/codemirror.component.ts (1)

116-139: Critical: Signal inputs don't trigger ngOnChanges.

Signal-based inputs created with input() do not trigger ngOnChanges. The logic that reconfigures extensions (line 117) and redraws the layout (line 125) will never execute because changes.extensions and changes.redrawLayout will be undefined.

Migrate to effect() to watch for changes:

+  constructor(
+    private zone: NgZone,
+    private altairConfig: AltairConfig
+  ) {
+    effect(() => {
+      this.onChange(this.value());
+    });
+    
+    // Watch for extensions changes
+    effect(() => {
+      const currentExtensions = this.extensions();
+      if (this.view) {
+        this.view.dispatch({
+          effects: StateEffect.reconfigure.of(
+            Prec.high(this.getExtensions(currentExtensions))
+          ),
+        });
+      }
+    });
+    
+    // Watch for redrawLayout changes
+    effect(() => {
+      if (this.redrawLayout() && this.view) {
+        setTimeout(() => {
+          if (this.view) {
+            this.view.dispatch({
+              changes: {
+                from: 0,
+                to: this.view.state.doc.length,
+                insert: this.view.state.doc.sliceString(0),
+              },
+            });
+          }
+        }, 250);
+      }
+    });
+  }

-  ngOnChanges(changes: SimpleChanges): void {
-    if (this.view && changes.extensions?.currentValue) {
-      this.view.dispatch({
-        effects: StateEffect.reconfigure.of(
-          Prec.high(this.getExtensions(changes.extensions.currentValue))
-        ),
-      });
-    }
-
-    if (changes.redrawLayout?.currentValue) {
-      // wait for animations to finish
-      setTimeout(() => {
-        if (this.view) {
-          this.view.dispatch({
-            changes: {
-              from: 0,
-              to: this.view.state.doc.length,
-              insert: this.view.state.doc.sliceString(0),
-            },
-          });
-        }
-      }, 250);
-    }
-  }

Also remove OnChanges and SimpleChanges imports:

  import {
    AfterViewInit,
    ChangeDetectionStrategy,
    Component,
    ElementRef,
    EventEmitter,
    forwardRef,
    HostBinding,
    NgZone,
-   OnChanges,
    OnDestroy,
    Output,
-   SimpleChanges,
    ViewChild,
    input,
    signal,
    effect,
  } from '@angular/core';

And remove from the implements clause:

  export class CodemirrorComponent
-   implements AfterViewInit, OnChanges, ControlValueAccessor, OnDestroy
+   implements AfterViewInit, ControlValueAccessor, OnDestroy
packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.ts (1)

26-29: Direct property access inconsistent with signal pattern.

Lines 27 and 33 reference this.showDialog directly instead of calling it as a function (this.showDialog()). This is inconsistent with the signal-based input pattern used throughout this PR.

Apply this diff to fix the property access:

   onClickSave(e: Event) {
-    this.toggleDialog.emit(!this.showDialog);
+    this.toggleDialog.emit(!this.showDialog());
     this.saveChange.emit(e);
   }

   onSubmit(e: Event) {
-    this.toggleDialog.emit(!this.showDialog);
+    this.toggleDialog.emit(!this.showDialog());
     this.saveChange.emit(e);
   }

Also applies to: 31-34

packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html (1)

65-73: Fix two-way binding on signal-backed field

newCollectionParentCollectionId is now a writable signal. Leaving [(ngModel)]="newCollectionParentCollectionId" expands to this.newCollectionParentCollectionId = $event, so the first change will overwrite the signal with a string/null and the later call newCollectionParentCollectionId() (Line 72) will explode. Read the signal and update it explicitly:

-          <nz-tree-select
-            [nzNodes]="collectionNodes()"
-            [nzNotFoundContent]="'No collections found'"
-            nzShowSearch
-            nzPlaceHolder="Select collection"
-            [(ngModel)]="newCollectionParentCollectionId"
-            (ngModelChange)="newCollectionParentCollectionIdChange.emit($event)"
-          ></nz-tree-select>
+          <nz-tree-select
+            [nzNodes]="collectionNodes()"
+            [nzNotFoundContent]="'No collections found'"
+            nzShowSearch
+            nzPlaceHolder="Select collection"
+            [ngModel]="newCollectionParentCollectionId()"
+            (ngModelChange)="onParentCollectionChange($event)"
+          ></nz-tree-select>

and in the component set the signal plus emit inside onParentCollectionChange. Same applies to other [(ngModel)] bindings that now target signals.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (1)

42-47: OnChanges hook won't fire for signal-based inputs.

The component still implements OnChanges and checks changes?.schema?.currentValue, but signal-based inputs created with input() don't trigger Angular's change detection lifecycle hooks like OnChanges. This code path will never execute.

Replace OnChanges with an effect to react to schema changes:

-export class SchemaFormComponent implements OnInit, OnChanges {
+export class SchemaFormComponent implements OnInit {
   readonly schema = input<JSONSchema6>({});
   readonly data = input<unknown>(null);

   @Output() dataChange = new EventEmitter<IDictionary>();

   schemaProperties: SchemaFormProperty[] = [];
   formData: IDictionary = {};

+  constructor() {
+    effect(() => {
+      const schema = this.schema();
+      if (schema) {
+        this.updateSchemaProperties(schema);
+      }
+    });
+  }
+
   ngOnInit() {
-    // console.log('SCHEMA:', this.schema);
-    const schema = this.schema();
-    if (schema) {
-      this.updateSchemaProperties(schema);
-    }
+    // Effect handles schema updates
   }

-  ngOnChanges(changes: SimpleChanges) {
-    // If there is a new schema, update the schema properties
-    if (changes?.schema?.currentValue) {
-      this.updateSchemaProperties(changes.schema.currentValue);
-    }
-  }
-
   updateSchemaProperties(schema: JSONSchema6) {
packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts (1)

217-219: Minor: Access signal value via function call.

hasSearchIndex is now a signal and should be accessed via hasSearchIndex() with parentheses to read its value.

Apply this diff:

   async addToEditor(name: string, parentType: string) {
-    if (!this.hasSearchIndex) {
+    if (!this.hasSearchIndex()) {
       debug.log('No search index, so cannot add to editor');
       return false;
     }
packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts (1)

96-100: Unify collectionId to string in ExportCollectionAction and its caller.

  • In collection.action.ts, change
    constructor(public payload: { collectionId: number }) {}
    to
    constructor(public payload: { collectionId: string }) {}
  • In altair.component.ts (line 776), update
    exportCollection({ collectionId }: { collectionId: number })
    to use string and adjust any callers to pass string IDs.
♻️ Duplicate comments (4)
packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts (1)

70-75: Reuse signals only after initialization

this.tabSize() runs while creating class fields, before Angular wires up the input signal. This will crash or at least lock in the default value, so later input changes never update the editor config. Move the array setup into a lifecycle hook (e.g., ngOnInit) or wrap it in a computed(() => …) so it reads tabSize() lazily.

packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)

164-227: Replace ngOnChanges logic with signal effects

All the properties referenced here are now input() signals. Angular does not invoke ngOnChanges for signal inputs, so none of these update branches (schema, tab size, line numbers, variables, window ID, shortcut mapping, etc.) will ever fire after the initial render. Any runtime updates pushed in from the parent will silently be ignored, leaving the editor desynced. Please move these reactions into effect(() => …) blocks (or convert the inputs back to @Input) so they run whenever the corresponding signal changes, and drop the SimpleChanges plumbing altogether. The betaDisableNewEditor branch can be removed at the same timeβ€”it references an input that no longer exists.

packages/altair-app/src/app/modules/altair/components/codemirror/codemirror.component.ts (1)

69-77: Signal input migration complete.

All @Input properties have been successfully migrated to signal-based input() functions with appropriate defaults and types.

Note: The past review comment about an unmigrated @Input decorator is no longer applicable, as all inputs have now been migrated.

packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts (1)

25-25: Signal inputs don't trigger ngOnChanges (duplicate issue).

The expanded input was migrated to a signal at line 29, but ngOnChanges at lines 53-57 attempts to react to changes in expanded. Signal-based inputs created with input() do not trigger the OnChanges lifecycle hook, so the logic updating showContent will never execute when expanded changes externally.

This issue was previously flagged. Apply the suggested fix from the earlier review: replace ngOnChanges with an effect() that watches the expanded signal and updates showContent accordingly.

Also applies to: 53-57

🧹 Nitpick comments (3)
packages/altair-app/src/app/modules/altair/containers/window/window.component.ts (1)

297-301: TODO reminder: Consider completing the signal migration for store selects.

The current implementation correctly uses this.windowId() to read the signal value. However, as noted in the TODO comment, the entire store subscription pattern could be migrated to use signal-based selectors for consistency.

Do you want me to generate a signal-based refactor for this store subscription or open a new issue to track this migration task?

packages/altair-app/src/app/modules/altair/components/banner/banner.component.ts (1)

6-6: Remove unused Input import.

The Input decorator is no longer used after migrating to the signal-based input() function.

Apply this diff to remove the unused import:

 import {
   ChangeDetectionStrategy,
   Component,
   EventEmitter,
   input,
-  Input,
   Output,
 } from '@angular/core';
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

93-101: Remove commented-out code.

The old subscription-based code should be deleted now that the migration to effects is complete.

Apply this diff:

-    // this.selectedTeam$.subscribe(async (team) => {
-    //   if (!team) {
-    //     return;
-    //   }
-    //   this.teamName = team.name;
-    //   this.teamDescription = team.description ?? '';
-
-    //   this.membersOfSelectedTeam = await accountService.getTeamMembers(team.id);
-    // });

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (1)

91-131: Fix signal payload: call selectedEnvironmentId() before emitting

linkedSignal returns a callable signal, so emitting this.selectedEnvironmentId passes the function itself instead of the selected id string. This breaks every consumer of subEnvironmentJsonChange, subEnvironmentTitleChange, and deleteSubEnvironmentChange (they will receive a function where a string id is expected), regressing environment updates and deletion. Always invoke the signal before emitting.

         this.subEnvironmentJsonChange.next({
-          id: this.selectedEnvironmentId,
+          id: this.selectedEnvironmentId(),
           value: content,
         });
...
     this.subEnvironmentTitleChange.next({
-      id: this.selectedEnvironmentId,
+      id: this.selectedEnvironmentId(),
       value: content,
     });
...
-      this.deleteSubEnvironmentChange.next({ id: this.selectedEnvironmentId });
+      this.deleteSubEnvironmentChange.next({ id: this.selectedEnvironmentId() });
packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts (1)

111-111: Invoke windowId signal in test
In window.component.spec.ts at line 111, call the signal accessor instead of using the signal object:

- const expectedAction = new ClearResultAction(component.windowId);
+ const expectedAction = new ClearResultAction(component.windowId());
packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.ts (1)

65-89: Guard windowIds() against nullish values before mutating.

input<string[]>([]) still delivers null/undefined when the async-bound parent emits those, so this.windowIds() can be null during initial renders. Spreading, reading .length, or chaining .filter on a null value will throw and break drag/drop and context-menu flows. Please coerce to an array (or bail early) before calling moveItemInArray, .filter, or .map.

   moveWindow(currentPosition: number, newPosition: number) {
-    const windowIds = [...this.windowIds()];
+    const windowIds = [...(this.windowIds() ?? [])];
+    if (!windowIds.length) {
+      return;
+    }
     moveItemInArray(windowIds, currentPosition, newPosition);
     this.reorderWindowsChange.next(windowIds);
   }

   closeWindowsToTheRight(curIndex: number) {
-    const lowerBound = curIndex + 1;
-    if (lowerBound >= this.windowIds().length) {
+    const windowIds = this.windowIds() ?? [];
+    const lowerBound = curIndex + 1;
+    if (lowerBound >= windowIds.length) {
       return;
     }
-    return this.windowIds()
+    return windowIds
       .filter((wid, i) => i > curIndex)
-      .map((_) => this.closeWindow(_));
+      .map((wid) => this.closeWindow(wid));
   }

   closeOtherWindows(windowId: string) {
-    return this.windowIds()
+    const windowIds = this.windowIds() ?? [];
+    if (!windowIds.length) {
+      return;
+    }
+    return windowIds
       .filter((wid) => wid !== windowId)
-      .map((_) => this.closeWindow(_));
+      .map((wid) => this.closeWindow(wid));
   }
packages/altair-app/src/app/modules/altair/containers/window/window.component.ts (1)

296-337: Fix stale state when windowId changes.

This subscription only reacts to store emissions and keeps calling this.windowId() inside the handler. When the parent switches to a different window, the store dispatch that triggered the change fires before Angular updates this signal. We end up reading the previous ID and the handler never reruns once the new windowId value arrives, leaving all the plain fields (apiUrl, query, dialogs, schema reload, etc.) stuck on the old window until some other store change happens.

Please drive this subscription from the windowId signal (e.g. use the existing windowState$ derived from this.windowId$, or combineLatest with this.windowId$) so the handler re-executes immediately whenever the input changes.

-    this.store
-      .pipe(
-        untilDestroyed(this),
-        map((data) => data.windows[this.windowId()]),
-        distinctUntilChanged()
-      )
-      .subscribe((data) => {
+    this.windowState$
+      .pipe(untilDestroyed(this))
+      .subscribe((data) => {
         if (!data) {
           return false;
         }
 
         this.apiUrl = data.query.url;
         const query = data.query.query ?? '';
         this.query = query;
packages/altair-app/src/app/modules/altair/services/electron-app/electron-app.service.ts (1)

354-360: Stop instantiating StorageService with new.

StorageService now relies on Angular's inject(); calling new StorageService() runs it outside an injection context and will crash at runtime (NG0203: inject() must be called…). Reuse the injected instance instead.

-    const asyncStorage = new StorageService();
+    const asyncStorage = this.storageService;
♻️ Duplicate comments (20)
packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts (1)

72-77: Initialize CodeMirror extensions reactively.

editorExtensions is constructed in a class field, so this.tabSize() is read before Angular delivers input updates and never re-evaluates. After the migration, any runtime tabSize changes silently stop updating the editor configuration. Move this setup into a computed (or a lifecycle hook) so it reacts to signal updates, and add the corresponding import.

-  editorExtensions: Extension[] = [
-    json(),
-    EditorState.readOnly.of(true),
-    indentUnit.of(' '.repeat(this.tabSize())),
-    EditorState.tabSize.of(this.tabSize()),
-  ];
+  readonly editorExtensions = computed<Extension[]>(() => [
+    json(),
+    EditorState.readOnly.of(true),
+    indentUnit.of(' '.repeat(this.tabSize())),
+    EditorState.tabSize.of(this.tabSize()),
+  ]);

Don’t forget to import computed from @angular/core.

packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts (1)

22-25: Handle CSP nonce changes when caching Emotion instance.

The effect never re-reads cspNonce() once the Emotion instance is cached, so a nonce rotation leaves the cached instance stuck with the stale nonce and the effect won’t rerun. This recreates the CSP issue noted earlier. Please track cspNonce() inside the effect and clear/recreate the cache whenever it changes.

-  constructor() {
-    effect(() => {
-      this.applyTheme(this.appTheme(), this.appDarkTheme(), this.appAccentColor());
-    });
-  }
+  private lastNonce?: string;
+
+  constructor() {
+    effect(() => {
+      const nonce = this.cspNonce();
+      if (this.lastNonce !== nonce) {
+        this.emotionInstance = undefined;
+        this.lastNonce = nonce || undefined;
+      }
+
+      this.applyTheme(
+        this.appTheme(),
+        this.appDarkTheme(),
+        this.appAccentColor(),
+      );
+    });
+  }
@@
-        nonce: this.cspNonce() || undefined,
+        nonce: this.lastNonce,
       });

Also applies to: 63-66

packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts (1)

1-1: Critical: Signal-based inputs don't trigger OnChanges (still unresolved).

The migration from @Input() to input() signals breaks the ngOnChanges lifecycle hook. Signal-based inputs don't populate the SimpleChanges object, so changes.queryId?.currentValue (line 23) will always be undefined, preventing revisions from being fetched when queryId changes.

This issue was already flagged in the previous review but remains unaddressed.

Replace the OnChanges approach with an effect() that watches the queryId signal:

 import {
   Component,
   EventEmitter,
-  OnChanges,
   Output,
-  SimpleChanges,
   input,
-  inject
+  inject,
+  effect
 } from '@angular/core';
 import { ApiService } from '../../services';
 import { QueryItemRevision } from '@altairgraphql/db';
 import { QueryItemRevisionWithUsername } from '@altairgraphql/api-utils';

 @Component({
   selector: 'app-query-revision-dialog',
   templateUrl: './query-revision-dialog.component.html',
   styles: ``,
   standalone: false,
 })
-export class QueryRevisionDialogComponent implements OnChanges {
+export class QueryRevisionDialogComponent {
-  private api = inject(ApiService);
-
   readonly showDialog = input(true);
   readonly queryId = input('');
   @Output() restoreRevision = new EventEmitter<QueryItemRevision>();
   @Output() toggleDialogChange = new EventEmitter<boolean>();

   revisions: QueryItemRevisionWithUsername[] = [];
+  
+  private api = inject(ApiService);
+
+  constructor() {
+    effect(() => {
+      const id = this.queryId();
+      if (id) {
+        this.api.getQueryRevisions(id).then((res) => {
+          this.revisions = res;
+        });
+      }
+    });
+  }

-  ngOnChanges(changes: SimpleChanges) {
-    if (changes.queryId?.currentValue) {
-      const queryId = changes.queryId.currentValue;
-      // fetch revisions
-      this.api.getQueryRevisions(queryId).then((res) => {
-        this.revisions = res;
-      });
-    }
-  }
 }

Also applies to: 12-12, 22-30

packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.ts (2)

61-66: Use effect() instead of ngOnInit to react to signal input changes.

With signal-based inputs, ngOnInit only executes once during component initialization. If authData changes after initialization, the form will not be updated, leading to stale data.

As noted in the previous review, replace ngOnInit with an effect() in the constructor to ensure the form updates whenever the authData signal changes:

+import { effect } from '@angular/core';
+
 export class AuthorizationOauth2Component implements OnInit {
+  constructor() {
+    effect(() => {
+      const authData = this.authData();
+      if (authData) {
+        this.form.patchValue(authData);
+      }
+    });
+  }
+
-  ngOnInit(): void {
-    const authData = this.authData();
-    if (authData) {
-      this.form.patchValue(authData);
-    }
-  }
+  ngOnInit(): void {}

62-65: Add type guard and cast for authData before patchValue.

authData is typed as unknown, but FormGroup.patchValue() expects a shape compatible with the form structure. Guard and cast the value to ensure type safety at build time and prevent runtime errors.

Apply this diff:

 const authData = this.authData();
-if (authData) {
-  this.form.patchValue(authData);
+if (authData && typeof authData === 'object') {
+  this.form.patchValue(authData as Partial<typeof this.form.value>);
 }
packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)

164-227: Critical: ngOnChanges does not work with signal inputs.

Signal inputs declared with input() do not participate in ngOnChanges or provide SimpleChanges when updated. The current implementation will not respond to input changes as expected.

Additionally, the betaDisableNewEditor block (lines 214-226) references a non-existent input and should be removed.

Recommended fix:

Remove the ngOnChanges hook entirely and replace with targeted effect() calls to react to signal changes:

-  ngOnChanges(changes: SimpleChanges) {
-    // If there is a new schema, update the editor schema
-    if (changes?.gqlSchema?.currentValue) {
-      this.updateNewEditorSchema(changes.gqlSchema.currentValue);
-      // Validate the schema to know if we can work with it
-      const validationErrors = this.gqlService.validateSchema(
-        changes.gqlSchema.currentValue
-      );
-      if (validationErrors.length) {
-        const errorList = validationErrors
-          .map((error) => '<br><br>' + error.message)
-          .join('');
-        this.notifyService.warning(
-          `
-          The schema definition is invalid according to the GraphQL specs.
-          Linting and other functionalities would be unavailable.
-          ${errorList}
-        `,
-          'Altair',
-          { disableTimeOut: true }
-        );
-      }
-    }
-
-    if (changes?.tabSize?.currentValue) {
-      this.updateNewEditorTabSize(changes.tabSize.currentValue);
-    }
-
-    if (changes?.disableLineNumbers?.currentValue) {
-      this.updateNewEditorDisableLineNumber(this.disableLineNumbers());
-    }
-
-    if (changes?.query?.currentValue && this.selectedIndex !== 0) {
-      // Set current tab to Query if query is updated
-      this.selectedIndex = 0;
-    }
-
-    if (changes?.shortcutMapping?.currentValue) {
-      // Update the editor shortcuts based on the provided shortcuts
-      this.updateEditorShortcuts(changes.shortcutMapping.currentValue);
-    }
-
-    if (changes?.variables?.currentValue && this.editor?.view) {
-      this.updateNewEditorVariableState(changes.variables.currentValue);
-    }
-
-    if (changes?.windowId?.currentValue && this.editor?.view) {
-      this.updateNewEditorWindowId(changes.windowId.currentValue);
-    }
-
-    if (changes?.betaDisableNewEditor) {
-      // Using timeout to wait for editor to be initialized.
-      // This is hacky but should be fine since the beta should be temporary
-      setTimeout(() => {
-        if (this.editor?.view) {
-          this.updateNewEditorSchema(this.gqlSchema());
-          this.updateNewEditorVariableState(this.variables());
-          this.updateNewEditorWindowId(this.windowId());
-          this.updateNewEditorTabSize(this.tabSize());
-          this.updateNewEditorDisableLineNumber(this.disableLineNumbers());
-        }
-      }, 10);
-    }
-  }

Add effects in the constructor or as class properties:

constructor() {
  // Schema change effect
  effect(() => {
    const schema = this.gqlSchema();
    if (schema && this.editor?.view) {
      this.updateNewEditorSchema(schema);
      const validationErrors = this.gqlService.validateSchema(schema);
      if (validationErrors.length) {
        const errorList = validationErrors
          .map((error) => '<br><br>' + error.message)
          .join('');
        this.notifyService.warning(
          `
          The schema definition is invalid according to the GraphQL specs.
          Linting and other functionalities would be unavailable.
          ${errorList}
        `,
          'Altair',
          { disableTimeOut: true }
        );
      }
    }
  });

  // Tab size change effect
  effect(() => {
    const tabSize = this.tabSize();
    if (this.editor?.view) {
      this.updateNewEditorTabSize(tabSize);
    }
  });

  // Line numbers change effect
  effect(() => {
    const disableLineNumbers = this.disableLineNumbers();
    if (this.editor?.view) {
      this.updateNewEditorDisableLineNumber(disableLineNumbers);
    }
  });

  // Query change effect (switch to query tab)
  effect(() => {
    const query = this.query();
    if (query && this.selectedIndex !== 0) {
      this.selectedIndex = 0;
    }
  });

  // Shortcut mapping change effect
  effect(() => {
    const shortcuts = this.shortcutMapping();
    if (this.editor?.view) {
      this.updateEditorShortcuts(shortcuts);
    }
  });

  // Variables change effect
  effect(() => {
    const variables = this.variables();
    if (this.editor?.view) {
      this.updateNewEditorVariableState(variables);
    }
  });

  // Window ID change effect
  effect(() => {
    const windowId = this.windowId();
    if (this.editor?.view) {
      this.updateNewEditorWindowId(windowId);
    }
  });
}

Note: The effects will run after view initialization, so the guards checking this.editor?.view will work correctly.

packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (2)

65-74: The race condition flagged in the previous review is still present.

This async effect remains vulnerable to race conditions when selectedTeamId changes rapidly. The previous review comment suggesting switchMap or request cancellation is still valid.


108-111: The type inconsistency flagged in the previous review is still present.

Line 109 still sets editTeamId to an empty string instead of undefined, which is inconsistent with the signal's type and with line 167 where editUserId.set(undefined) is used correctly.

packages/altair-app/src/app/modules/altair/components/window-switcher-item/window-switcher-item.component.ts (1)

43-52: Restore the null guard before calling getWindowCollection.

This repeats the regression flagged earlier: collections$ | async feeds null initially, so this.collections() can be nullish and getWindowCollection will blow up when it forwards that to getCollection(...). Please bail out (or coerce to []) before invoking the helper.

   readonly isWindowInCollection = computed(() => {
     const w = this.window();
     const collections = this.collections();
-    return !!w && !!getWindowCollection(w, collections);
+    if (!w || !Array.isArray(collections) || !collections.length) {
+      return false;
+    }
+    return !!getWindowCollection(w, collections);
   });
   readonly isWindowUnsaved = computed(() => {
     const w = this.window();
     const collections = this.collections();
-    return !!w && windowHasUnsavedChanges(w, collections);
+    if (!w || !Array.isArray(collections) || !collections.length) {
+      return false;
+    }
+    return windowHasUnsavedChanges(w, collections);
   });
packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts (1)

223-226: Remove dead code on Line 224.

Line 224 calls self.store.select(selectActiveEnvironmentsList(windowId)) without subscribing or assigning the result, making it dead code.

Apply this diff to remove the unused line:

 constructor(view: EditorView) {
   const windowId = self.windowId();
-  self.store.select(selectActiveEnvironmentsList(windowId));
   this.unsubscribe = self.store
     .select(selectActiveEnvironmentsList(windowId))
packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts (2)

162-166: Critical: Signal array mutation - duplicate of previous review.

This code still directly calls .pop() on the signal's array value, which mutates it. Signals require immutable updates using .set() or .update().

Apply the fix from the previous review:

   goBack() {
-    if (this.docHistory().length) {
-      this.setDocView(this.docHistory().pop());
+    const history = [...this.docHistory()];
+    const lastView = history.pop();
+    if (lastView) {
+      this.docHistory.set(history);
+      this.setDocView(lastView);
     }
   }

179-183: Critical: Signal array mutation - duplicate of previous review.

This code still directly calls .push() on the signal's array value, which mutates it. Signals require immutable updates using .update(). Additionally, the this.docView() existence check is unnecessary since docView is always a signal function.

Apply the fix from the previous review:

   updateDocHistory() {
-    if (this.docView() && this.docView().view !== 'search') {
-      this.docHistory().push({ ...this.docView() });
+    if (this.docView().view !== 'search') {
+      this.docHistory.update(history => [...history, { ...this.docView() }]);
     }
   }
packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (2)

1-1: Remove unused lifecycle imports.

OnChanges and SimpleChanges are no longer needed since signal inputs don't trigger ngOnChanges. These should be removed as part of fixing the critical reactivity issue flagged in the previous review.

Apply this diff:

-import { Component, OnInit, Output, EventEmitter, ViewChild, ElementRef, OnChanges, SimpleChanges, ChangeDetectionStrategy, input, inject } from '@angular/core';
+import { Component, OnInit, Output, EventEmitter, ViewChild, ElementRef, ChangeDetectionStrategy, input, inject } from '@angular/core';

13-13: Remove OnChanges interface implementation.

The OnChanges interface is incompatible with signal-based inputs. This should be removed as part of addressing the critical reactivity issue identified in the previous review.

Apply this diff:

-export class VariableFileItemComponent implements OnInit, OnChanges {
+export class VariableFileItemComponent implements OnInit {
packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts (1)

26-26: Signal inputs don't trigger ngOnChanges.

The expanded input was migrated to a signal, but the component still implements OnChanges and has an ngOnChanges method that attempts to react to changes in expanded. Signal-based inputs created with input() do not trigger the OnChanges lifecycle hook, so the logic updating showContent will never execute when expanded changes externally.

Replace ngOnChanges with an effect() to react to the expanded signal:

 import {
   Component,
   Output,
   EventEmitter,
   ChangeDetectionStrategy,
-  OnChanges,
-  SimpleChanges,
   input,
   inject,
+  effect,
 } from '@angular/core';

-export class QueryCollectionItemComponent implements OnChanges {
+export class QueryCollectionItemComponent {
   private modal = inject(NzModalService);

   readonly collectionTree = input.required<IQueryCollectionTree>();
   readonly loggedIn = input(false);
   readonly queriesSortBy = input<SortByOptions>('newest');
   readonly expanded = input(true);

   ...

   showContent = true;

-  ngOnChanges(changes: SimpleChanges) {
-    if (changes.expanded?.currentValue !== undefined) {
-      this.showContent = changes.expanded.currentValue;
-    }
+  constructor() {
+    effect(() => {
+      this.showContent = this.expanded();
+    });
   }

Also applies to: 54-58

packages/altair-app/src/app/modules/altair/components/authorization/authorization-basic/authorization-basic.component.ts (1)

1-26: Keep the form reactive to authData.

With the new signal-based authData, patching the form only in ngOnInit means later input changes are ignored, so the form shows stale credentials. Wire the signal into an effect (and bring in the effect import) so every authData() change refreshes the form, then drop the now-unused ngOnInit logic.

-import { ChangeDetectionStrategy, Component, OnInit, Output, input, inject } from '@angular/core';
+import { ChangeDetectionStrategy, Component, OnInit, Output, effect, input, inject } from '@angular/core';
@@
-  readonly authData = input<unknown>();
+  readonly authData = input<unknown>();
+  private readonly syncAuthData = effect(() => {
+    const authData = this.authData();
+    if (authData) {
+      this.basicForm.patchValue(authData as Partial<typeof this.basicForm.value>);
+    }
+  });
@@
-    const authData = this.authData();
-    if (authData) {
-      this.basicForm.patchValue(authData);
-    }
+    // kept empty because the signal-backed effect handles updates
   }
packages/altair-app/src/app/modules/altair/components/authorization/authorization-editor/authorization-editor.component.ts (1)

1-45: Keep form state in sync with the authorizationState signal

You still patch typeForm only in ngOnInit, so later updates to authorizationState() never reach the form. With signal inputs we need an effect that reacts whenever the signal changes. Please wire it reactively instead of relying on one-time init.

-import { ChangeDetectionStrategy, Component, EventEmitter, OnInit, Output, input, inject } from '@angular/core';
+import { ChangeDetectionStrategy, Component, EventEmitter, Output, effect, input, inject } from '@angular/core';
@@
-export class AuthorizationEditorComponent implements OnInit {
+export class AuthorizationEditorComponent {
@@
-  ngOnInit(): void {
-    const authorizationState = this.authorizationState();
-    if (authorizationState) {
-      this.typeForm.patchValue({
-        type: authorizationState.type,
-      });
-    }
-  }
+  private readonly syncAuthorizationTypeEffect = effect(() => {
+    const authorizationState = this.authorizationState();
+    if (authorizationState) {
+      this.typeForm.patchValue({ type: authorizationState.type });
+    }
+  });
packages/altair-app/src/app/modules/altair/components/authorization/authorization-bearer/authorization-bearer.component.ts (1)

1-26: Sync bearerForm with authData signal reactively

authData() is read only in ngOnInit, so later input updates never update the form. Hook an effect to the signal so the form stays current.

-import { ChangeDetectionStrategy, Component, OnInit, Output, input, inject } from '@angular/core';
+import { ChangeDetectionStrategy, Component, Output, effect, input, inject } from '@angular/core';
@@
-export class AuthorizationBearerComponent implements OnInit {
+export class AuthorizationBearerComponent {
@@
-  readonly authData = input<unknown>();
+  readonly authData = input<unknown>();
+  private readonly syncAuthDataEffect = effect(() => {
+    const authData = this.authData();
+    if (authData) {
+      this.bearerForm.patchValue(authData as Partial<{ token: string }>);
+    }
+  });
@@
-  ngOnInit(): void {
-    const authData = this.authData();
-    if (authData) {
-      this.bearerForm.patchValue(authData);
-    }
-  }
packages/altair-app/src/app/modules/altair/components/settings-dialog/settings-dialog.component.ts (1)

1-55: Signal inputs no longer trigger ngOnChanges.

With input() signals, Angular never calls ngOnChanges, so updateLocalSettings() is never invoked when the settings input updates. The dialog therefore shows stale data and fails to react to parent changes. Please remove the OnChanges implementation and replace it with an effect() that watches the signal.

-import { Component, OnInit, Output, EventEmitter, SimpleChanges, OnChanges, input, inject } from '@angular/core';
+import { Component, OnInit, Output, EventEmitter, input, inject, effect } from '@angular/core';
@@
-export class SettingsDialogComponent implements OnInit, OnChanges {
+export class SettingsDialogComponent implements OnInit {
@@
   readonly showSettingsDialog = input(false);
@@
-  ngOnChanges(changes: SimpleChanges) {
-    if (changes?.settings?.currentValue) {
-      this.updateLocalSettings(
-        JSON.stringify(changes.settings.currentValue, null, 2)
-      );
-    }
-  }
+  private readonly syncSettingsEffect = effect(() => {
+    const currentSettings = this.settings();
+    if (currentSettings) {
+      this.updateLocalSettings(JSON.stringify(currentSettings, null, 2));
+    }
+  });
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (1)

12-23: Critical: Add cleanup to prevent memory leak in debounce effect.

The debounce function's effect doesn't register a cleanup callback, which means:

  1. If the component is destroyed while a timeout is pending, the timeout won't be cleared, causing a memory leak
  2. The setTimeout callback may execute after component destruction, potentially causing errors

Apply this diff to add proper cleanup:

 export function debounce<T>(input: Signal<T>, delay = 300) {
   const out = signal(input());
-  let timeout: any;
+  let timeout: ReturnType<typeof setTimeout> | undefined;
 
-  effect(() => {
+  effect((onCleanup) => {
     const value = input();
     clearTimeout(timeout);
     timeout = setTimeout(() => out.set(value), delay);
+    onCleanup(() => {
+      if (timeout) clearTimeout(timeout);
+      timeout = undefined;
+    });
   });
 
   return out.asReadonly();
 }

Additionally, consider moving this utility to a shared utilities file (e.g., packages/altair-app/src/app/modules/altair/utils/signals.ts) rather than exporting from a component file, as it's likely to be reused across components.

🧹 Nitpick comments (9)
packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.ts (1)

7-12: Consider OnPush change detection strategy.

For components that rely primarily on observables with the async pipe (as this one likely does), ChangeDetectionStrategy.OnPush can improve performance by reducing unnecessary change detection cycles.

Apply this diff to add OnPush:

-import { Component, inject } from '@angular/core';
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

 @Component({
   selector: 'app-banner-container',
   templateUrl: './banner-container.component.html',
   styles: ``,
+  changeDetection: ChangeDetectionStrategy.OnPush,
   standalone: false,
 })

As per coding guidelines.

packages/altair-app/.eslintrc.js (2)

43-43: Remove commented-out code.

The commented rule appears to be replaced by the active prefer-standalone rule on line 44. Remove the comment to keep the configuration clean.

Apply this diff:

       '@angular-eslint/prefer-on-push-component-change-detection': 'warn',
-      // '@angular-eslint/prefer-standalone-component': 'warn',
       '@angular-eslint/prefer-standalone': 'warn',

42-52: Add explanatory comments for rule configurations.

Consider adding brief comments explaining why rules are set to 'off' or 'warn', especially for rules that are disabled. This improves maintainability and helps future contributors understand the rationale.

Example pattern:

// Disabled during signals migration; re-evaluate after completion
'@angular-eslint/consistent-component-styles': 'off',
// Defer key sorting to avoid noise during refactoring
'@angular-eslint/sort-keys-in-type-decorator': 'off',
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

85-93: Remove commented-out code.

This commented code appears to be the old subscription-based implementation that was replaced by the effect above. It should be removed to keep the codebase clean.

Apply this diff:

     });
-    // this.selectedTeam$.subscribe(async (team) => {
-    //   if (!team) {
-    //     return;
-    //   }
-    //   this.teamName = team.name;
-    //   this.teamDescription = team.description ?? '';
-
-    //   this.membersOfSelectedTeam = await accountService.getTeamMembers(team.id);
-    // });
   }
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)

17-21: Consider adding explicit type annotations for signal inputs.

While the input signals correctly default to InputSignal<string>, adding explicit type annotations improves code clarity and catches type mismatches earlier.

-  readonly title = input('');
-  readonly description = input('');
+  readonly title = input<string>('');
+  readonly description = input<string>('');
...
-  readonly featureKey = input('');
+  readonly featureKey = input<string>('');
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.ts (2)

8-9: Inconsistent type parameter usage in inject() calls.

Line 8 explicitly provides a type parameter inject<TemplateRef<unknown>>(TemplateRef) while line 9 omits it inject(ViewContainerRef). For consistency and clarity, either provide type parameters for both or rely on type inference consistently.

Apply this diff for consistency:

-private templateRef = inject<TemplateRef<unknown>>(TemplateRef);
-private viewContainer = inject(ViewContainerRef);
+private templateRef = inject(TemplateRef<unknown>);
+private viewContainer = inject(ViewContainerRef);

Or explicitly annotate both if preferred:

-private templateRef = inject<TemplateRef<unknown>>(TemplateRef);
-private viewContainer = inject(ViewContainerRef);
+private templateRef = inject<TemplateRef<unknown>>(TemplateRef);
+private viewContainer = inject<ViewContainerRef>(ViewContainerRef);

28-28: Consider preserving original view position on re-attachment.

viewContainer.insert(this.cachedViewRef) without an index parameter inserts the view at the end of the container. If the directive's original position matters, this could cause layout shifts. Consider inserting at index 0 or storing the original index.

If position matters, apply this diff:

-this.viewContainer.insert(this.cachedViewRef);
+this.viewContainer.insert(this.cachedViewRef, 0);
packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.ts (1)

43-43: Consider initializing with empty string for clarity.

The signal is initialized with this.windowTitle() which will return the default value (empty string) at construction time before Angular sets the input. The resetEffect (lines 56-60) then updates it when the input changes. While this works correctly, initializing directly to signal('') would make the intent clearer since the effect handles all updates.

Apply this diff if you prefer explicit initialization:

-  readonly newCollectionQueryTitle = signal(this.windowTitle());
+  readonly newCollectionQueryTitle = signal('');
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (1)

66-84: Normalize local storageType semantics
Ensure all local collections have storageType: 'local' (rather than relying on undefined) or update the filter to only check for 'local'. Confirm this aligns with how storageType is assigned in query-collection.service.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html (1)

19-27: Fix docHistory signal usage.

docHistory was migrated to a signal (readonly docHistory = this.state.docHistory;), so in the template you must read it via docHistory(). Accessing docHistory.length will throw at runtime because the signal function has no length property.

Update the guard to call the signal before checking length:

-@if (docView.view !== 'root' && docHistory.length) {
+@if (docView.view !== 'root' && docHistory().length) {
packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html (1)

75-88: Anchors used as buttons are not keyboard-accessible. Convert to or add role/tabindex and key handlers.

  • without href is not focusable and breaks keyboard nav.
  • Either switch to
or add role="button" tabindex="0" and handle Enter/Space.

Also expose state for toggles (e.g., [attr.aria-pressed]="panel.isActive") where applicable.

Example patch for a representative item:

-<a class="side-menu-item" (click)="toggleHeader(true)" [attr.aria-label]="'SET_HEADERS_BUTTON' | translate" track-id="show_set_headers">
+<button type="button" class="side-menu-item" (click)="toggleHeader(true)" [attr.aria-label]="'SET_HEADERS_BUTTON' | translate" track-id="show_set_headers">
   ...
-</a>
+</button>

As per coding guidelines; Based on learnings

Also applies to: 89-100, 101-113, 114-126, 133-146, 147-158, 159-171, 172-184, 185-197, 198-209, 219-237, 241-255, 256-269, 270-347

♻️ Duplicate comments (1)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html (1)

40-45: Fix select signal binding and dynamic name.

Same issue here: [(ngModel)]="data" overwrites the signal, and the literal name="item.key" never binds to the real key. Use the signal read/write helpers and bind the name.

-                <nz-select
-                  [(ngModel)]="data"
-                  name="item.key"
-                  nzPlaceHolder="Choose"
-                  (ngModelChange)="data.set($event)"
-                >
+                <nz-select
+                  [ngModel]="data()"
+                  [name]="item.key"
+                  nzPlaceHolder="Choose"
+                  (ngModelChange)="data.set($event)"
+                >
🧹 Nitpick comments (5)
packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html (5)

79-79: ARIA labels added β€” consider redundancy and state.

  • If visible text matches, aria-label may be redundant and can override inner text. Prefer relying on visible text unless you need a different label.
  • For active/toggle items, consider adding [attr.aria-current]="true" or [attr.aria-pressed]="..." appropriately.

As per coding guidelines; Based on learnings

Also applies to: 92-92, 104-104, 117-117, 137-137, 149-149, 163-163, 175-175, 188-188, 201-201, 222-222, 246-247, 259-259, 273-273


82-83: Ensure decorative icons are hidden from AT, or provide labels when meaningful.

If app-icon is decorative, set aria-hidden="true" (ideally internally by the component). If it conveys meaning not otherwise exposed, ensure an accessible name exists on the control/container.

As per coding guidelines; Based on learnings

Also applies to: 95-96, 108-109, 121-122, 130-131, 140-141, 153-154, 167-167, 179-179, 192-193, 204-205, 229-232, 249-250, 264-265, 281-282, 300-301, 314-315, 323-324, 331-332, 339-340


284-289: Use charAt(0) instead of at(0) for broader runtime support (avatar initial).

String.prototype.at is ES2022 and may not exist in older runtimes. Prefer charAt(0) or a safe fallback.

- [nzText]="(account$ | async)?.firstName?.at(0)"
+ [nzText]="(account$ | async)?.firstName?.charAt(0)"

214-239: Reduce repeated async pipe subscriptions with @let locals.

Multiple uses of (account$ | async), (windowsMeta$ | async), etc. cause multiple subscriptions and change detections. Use @let to cache.

Example:

@let account = account$ | async;
@let meta = windowsMeta$ | async;

<div [ngClass]="{ 'side-menu-item--active': account?.loggedIn }">...</div>
<app-upgrade-dialog [showDialog]="meta?.showUpgradeDialog" [userPlan]="account?.plan" ... />

Also applies to: 352-372, 443-461


242-255: Plugin manager menu visibility β€” OK. Consider aria-expanded on trigger if submenu toggles.

Looks good behind enableExperimental. If this item controls a submenu/popup, expose [attr.aria-expanded] reflecting the open state.

As per coding guidelines; Based on learnings

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between e733d69 and 5012e38.

πŸ“’ Files selected for processing (51)
  • packages/altair-app/.eslintrc.js (3 hunks)
  • packages/altair-app/src/app/app.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.html (3 hunks)
  • packages/altair-app/src/app/modules/altair/components/action-bar/action-bar.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-editor/authorization-editor.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.html (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/banner/banner.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-field/doc-viewer-field.component.html (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html (6 hunks)
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html (8 hunks)
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html (6 hunks)
  • packages/altair-app/src/app/modules/altair/components/fancy-input/fancy-input.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/fork-repo/fork-repo.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/header/header.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/headers-editor/headers-editor.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/history-dialog/history-dialog.component.html (3 hunks)
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/post-request-editor/post-request-editor.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.html (8 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html (9 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html (7 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/settings-dialog/settings-dialog.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/upgrade-dialog/upgrade-dialog.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html (7 hunks)
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.html (3 hunks)
  • packages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/window-switcher-item/window-switcher-item.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html (24 hunks)
  • packages/altair-app/src/app/modules/altair/containers/window/window.component.html (8 hunks)
  • packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.html (1 hunks)
βœ… Files skipped from review due to trivial changes (3)
  • packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.html
  • packages/altair-app/src/app/modules/altair/components/fork-repo/fork-repo.component.html
  • packages/altair-app/src/app/app.component.html
🚧 Files skipped from review as they are similar to previous changes (17)
  • packages/altair-app/src/app/modules/altair/components/fancy-input/fancy-input.component.html
  • packages/altair-app/src/app/modules/altair/components/window-switcher-item/window-switcher-item.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-field/doc-viewer-field.component.html
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-editor/authorization-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/headers-editor/headers-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/banner/banner.component.html
  • packages/altair-app/src/app/modules/altair/components/post-request-editor/post-request-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.html
  • packages/altair-app/src/app/modules/altair/components/upgrade-dialog/upgrade-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.html
  • packages/altair-app/src/app/modules/altair/components/settings-dialog/settings-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/header/header.component.html
  • packages/altair-app/src/app/modules/altair/containers/window/window.component.html
  • packages/altair-app/src/app/modules/altair/components/action-bar/action-bar.component.html
  • packages/altair-app/src/app/modules/altair/components/history-dialog/history-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.html
  • packages/altair-app/.eslintrc.js
🧰 Additional context used
πŸ““ Path-based instructions (4)
packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Files:

  • packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html
  • packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.html
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.html
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html
  • packages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html
  • packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.html
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html
  • packages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html
  • packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html
packages/altair-app/src/app/modules/altair/components/**/*.component.html

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.html: Use ng-zorro Ant Design components for UI in templates
Include proper ARIA attributes in templates for accessibility
Use semantic HTML elements in templates

Files:

  • packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html
  • packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.html
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.html
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html
  • packages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html
  • packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.html
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html
  • packages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html
  • packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html
packages/altair-app/src/app/modules/altair/components/**/*.component.{html,ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Ensure keyboard navigation works (focus management and keyboard handlers)

Files:

  • packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html
  • packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.html
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.html
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html
  • packages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html
  • packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.html
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html
  • packages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html
  • packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html
packages/altair-app/**/*.{ts,html}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Implement and modify the main web app using Angular conventions within packages/altair-app

Files:

  • packages/altair-app/src/app/modules/altair/components/plugin-manager/plugin-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/dialog/dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.html
  • packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.html
  • packages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html
  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
  • packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.html
  • packages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.html
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.html
  • packages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html
  • packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.html
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.html
  • packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html
  • packages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.html
  • packages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html
🧠 Learnings (8)
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.html : Use semantic HTML elements in templates

Applied to files:

  • packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.html
  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
  • packages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
  • packages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.html : Include proper ARIA attributes in templates for accessibility

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.html : Use ng-zorro Ant Design components for UI in templates

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
πŸ“š Learning: 2025-10-03T16:39:27.517Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/main.instructions.md:0-0
Timestamp: 2025-10-03T16:39:27.517Z
Learning: Applies to packages/altair-app/**/*.{ts,html} : Implement and modify the main web app using Angular conventions within packages/altair-app

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
  • packages/altair-app/src/app/modules/altair/components/tips/tips.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Place Angular component classes under packages/altair-app/src/app/modules/altair/components/

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts} : Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
  • packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.html
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Input and Output decorators to define the component API

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: tests / e2e-test (ubuntu-latest)
  • GitHub Check: tauri / tauri (ubuntu-22.04)
  • GitHub Check: tests / test (macos-latest)
  • GitHub Check: tests / test (ubuntu-latest)
  • GitHub Check: tests / e2e-test (macos-latest)
  • GitHub Check: tests / api-e2e-test
  • GitHub Check: electron / electron (windows-latest)
  • GitHub Check: electron / electron (macos-latest)
  • GitHub Check: electron / electron (ubuntu-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: tauri / tauri (windows-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target x86_64-apple-darwin)
  • GitHub Check: docker / docker
  • GitHub Check: sites / Deploy sites
  • GitHub Check: build_and_preview
πŸ”‡ Additional comments (4)
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html (1)

45-48: Signal setter usage looks great.

Switching the dialog toggle to showTeamForm.set($event) keeps the signal state in sync with the dialog and avoids the runtime error from direct assignment. Nicely done.

packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.html (1)

75-83: Explicit button type prevents accidental form submits.

Nice catch adding type="button"β€”this keeps the modal footer action from accidentally acting like a form submit when nested inside forms.

packages/altair-app/src/app/modules/altair/containers/altair/altair.component.html (2)

51-51: Self-closing components/templates look good; confirm Angular version.

The self-closing conversions are fine in Angular 15+ and keep the template tidy. Please confirm the project targets a version that supports this everywhere (including schematics/linters).

Also applies to: 54-54, 372-372, 377-377, 387-387, 403-403, 409-409, 418-418, 423-423, 435-435, 441-441, 448-448, 454-454, 460-460, 466-466, 469-469, 476-476


63-69: Good addition: type="button" prevents unintended form submits.

Also applies to: 482-490, 493-499

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 5012e38 and 5ec5813.

β›” Files ignored due to path filters (9)
  • packages/altair-app/src/app/modules/altair/components/account-dialog/__snapshots__/account-dialog.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/action-bar/__snapshots__/action-bar.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/dialog/__snapshots__/dialog.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/__snapshots__/edit-collection-dialog.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/history-dialog/__snapshots__/history-dialog.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/import-curl-dialog/__snapshots__/import-curl-dialog.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/url-box/__snapshots__/url-box.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/__snapshots__/variable-file-item.component.spec.ts.snap is excluded by !**/*.snap
  • packages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snap is excluded by !**/*.snap
πŸ“’ Files selected for processing (2)
  • packages/altair-app/src/app/modules/altair/components/header/header.component.html (5 hunks)
  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts (2 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (11)
packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Files:

  • packages/altair-app/src/app/modules/altair/components/header/header.component.html
packages/altair-app/src/app/modules/altair/components/**/*.component.html

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.html: Use ng-zorro Ant Design components for UI in templates
Include proper ARIA attributes in templates for accessibility
Use semantic HTML elements in templates

Files:

  • packages/altair-app/src/app/modules/altair/components/header/header.component.html
packages/altair-app/src/app/modules/altair/components/**/*.component.{html,ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Ensure keyboard navigation works (focus management and keyboard handlers)

Files:

  • packages/altair-app/src/app/modules/altair/components/header/header.component.html
packages/altair-app/**/*.{ts,html}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Implement and modify the main web app using Angular conventions within packages/altair-app

Files:

  • packages/altair-app/src/app/modules/altair/components/header/header.component.html
  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
{**/__tests__/**/*.ts,**/*.{spec,test}.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

{**/__tests__/**/*.ts,**/*.{spec,test}.ts}: Use Jest as the testing framework for all tests
Organize tests next to the code under test: use a tests folder or .test.ts/.spec.ts files alongside sources
Use clear, descriptive test names explaining what is being verified
Mock dependencies with Jest to isolate the unit under test
Leverage TypeScript types in tests; define interfaces/types for expected data shapes

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
**/*.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

Follow project code style using ESLint and Prettier

**/*.ts: Use explicit type annotations for function parameters and return types
Prefer interfaces over type aliases for object shapes
Use union types and literal types for better type safety
Leverage generic types for reusable components
Group imports: external libraries first, then internal modules
Use absolute imports from package roots when possible
Prefer named exports over default exports
Use custom error classes that extend Error
Implement proper error boundaries and handling
Log errors with sufficient context for debugging
Use observables (RxJS) for reactive programming patterns where appropriate
Manage subscriptions to avoid memory leaks
Use appropriate RxJS operators for data transformation
Handle errors in observable streams
Use async/await for sequential operations
Handle promise rejections properly
Use Promise.all() for concurrent operations
Implement timeout handling for long-running operations
Dispose of resources properly (subscriptions, event listeners)
Use weak references where appropriate
Avoid creating unnecessary objects in hot paths
Profile memory usage for performance-critical code
Use tree-shaking-friendly imports
Lazy load heavy modules when possible
Monitor bundle size impacts of new dependencies
Use dynamic imports for code splitting
Validate and sanitize all user inputs
Implement proper XSS and injection prevention
Validate API responses before processing
Sanitize sensitive data in logs
Follow secure coding practices
Group related functionality in modules
Keep files focused and not too large
Use consistent naming conventions
Organize imports and exports clearly
Write JSDoc comments for public APIs
Keep documentation up to date with code changes (inline docs)
Use meaningful variable and function names
Handle environment-specific APIs properly
Use TypeScript features appropriate for the configured version

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
**/*.{ts,tsx}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Use TypeScript for implementation across the codebase

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
**/*.{spec,test}.{ts,tsx,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Write and maintain tests; Jest is used for most testing

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
**/*.{test,spec}.{ts,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

**/*.{test,spec}.{ts,js}: Follow the Arrange-Act-Assert (AAA) pattern in tests
Write descriptive test names that explain expected behavior
Keep tests focused and independent
Use consistent naming conventions across all test files
Group related tests using describe blocks
Use nested describe blocks for different methods or scenarios
Place setup code in beforeEach or beforeAll hooks
Clean up resources in afterEach or afterAll hooks
Mock external dependencies to isolate units under test
Use Jest's mocking capabilities effectively
Create reusable mock factories for common dependencies
Verify interactions with mocked dependencies when necessary
Use async/await for testing promises
Test both success and error scenarios in async code
Handle timeouts appropriately in async tests
Test concurrent operations when relevant
For NestJS controllers, test HTTP handling, response formatting, auth, and error/status codes; mock service dependencies
For NestJS services, test business logic, data transformations, error handling/validation, and verify logging/monitoring calls
For API integration tests, test endpoints end-to-end, use test DB/transactions, test auth flows, and verify API contracts/responses
For browser extensions, mock browser APIs (chrome., browser.), test message passing, content scripts, and verify manifest configuration
Write performance tests for critical code paths and set performance budgets/thresholds
Monitor test execution times and profile memory usage in tests
Load test API endpoints, verify graceful degradation, check for resource cleanup/memory leaks, and monitor performance metrics
E2E tests should focus on critical user journeys, use realistic data, test cross-browser, and verify integrations
Use dedicated test environments, mock external services appropriately, ensure data consistency, and clean up test artifacts
Create reusable test data factories and use realistic but anonymized data; version fixtures with code and clean up after tests
Maintain high t...

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
packages/altair-app/**/*.{test,spec}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

packages/altair-app/**/*.{test,spec}.ts: Use the custom testing framework in packages/altair-app/src/testing for Angular component tests
Focus on component business logic rather than UI library behavior
Mock services and external dependencies in component tests
Test component lifecycle methods appropriately
In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services
Do NOT test UI library component properties, template rendering details, CSS, or third-party library behavior in component tests

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
**/*.{spec,test}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{spec,test}.ts: Write unit tests focusing on business logic and behavior
Use descriptive test names
Mock external dependencies appropriately in tests
Test edge cases and error conditions

Files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
🧠 Learnings (10)
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component interactions with services using mocks

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test state management and property changes of components

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component lifecycle behavior

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Mock external dependencies and services in tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-10-03T16:40:52.954Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/nestjs-api.instructions.md:0-0
Timestamp: 2025-10-03T16:40:52.954Z
Learning: Applies to packages/altair-api/src/**/*.spec.ts : Mock dependencies properly in tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Avoid fragile emission index tracking across multiple actions in a single test; isolate scenarios per it block

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Focus on asserting state changes in response to actions

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-10-03T16:40:52.954Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/nestjs-api.instructions.md:0-0
Timestamp: 2025-10-03T16:40:52.954Z
Learning: Applies to packages/altair-api/src/**/*.spec.ts : Use NestJS testing utilities (TestingModule, Test) in unit tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Mock services and external dependencies in component tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
🧬 Code graph analysis (1)
packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts (1)
packages/altair-app/src/testing/index.ts (2)
  • mock (7-9)
  • mockStoreFactory (11-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: tauri / tauri (ubuntu-22.04)
  • GitHub Check: tauri / tauri (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: tauri / tauri (windows-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target x86_64-apple-darwin)
  • GitHub Check: tests / e2e-test (macos-latest)
  • GitHub Check: electron / electron (macos-latest)
  • GitHub Check: electron / electron (windows-latest)
  • GitHub Check: tests / test (macos-latest)
  • GitHub Check: docker / docker
  • GitHub Check: tests / api-e2e-test
  • GitHub Check: tests / test (ubuntu-latest)
  • GitHub Check: tests / e2e-test (ubuntu-latest)
  • GitHub Check: electron / electron (ubuntu-latest)
  • GitHub Check: sites / Deploy sites
  • GitHub Check: build_and_preview
πŸ”‡ Additional comments (1)
packages/altair-app/src/app/modules/altair/components/header/header.component.html (1)

65-76: Re-check the fallback condition for the environment label.
Splitting this into two standalone @if blocks means we only render the β€œno environment” state when activeEnvironment() is strictly undefined. If the signal ever yields null (or any other falsy-but-not-undefined placeholder), the menu item becomes blank. Please confirm the signal never resolves to null, or fold the logic into a single @if … @else with an alias (e.g. @if (activeEnvironment() as env) { … } @else { … }) so every nullish case still shows the fallback.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts (1)

100-101: Same concern as previously flagged.

The ngOnInit override remains problematic as noted in the previous review comment. This bypasses initialization logic and could hide bugs during the signals migration.

🧹 Nitpick comments (11)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts (1)

32-32: LGTM: Correct migration to signal-based API.

The change from direct assignment to .set() correctly adapts to the signal/model-based data property.

Consider adding tests for signal behavior and state changes:

it('should update data signal when set is called', () => {
  const testData = { key: 'value' };
  component.data.set(testData);
  expect(component.data()).toEqual(testData);
});

it('should handle null or undefined data', () => {
  expect(() => component.data.set(null)).not.toThrow();
  expect(() => component.data.set(undefined)).not.toThrow();
});
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts (1)

25-25: LGTM: Correct migration to signal-based API.

The change from direct assignment to .set('') correctly adapts to the signal/model-based data property.

Consider adding tests for string input handling:

it('should update data signal with string values', () => {
  component.data.set('test value');
  expect(component.data()).toBe('test value');
});

it('should handle empty string', () => {
  component.data.set('');
  expect(component.data()).toBe('');
});
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts (1)

27-27: LGTM: Correct migration to signal-based API.

The change from direct assignment to .set([]) correctly adapts to the signal/model-based data property.

Consider adding tests for array data handling:

it('should update data signal with array values', () => {
  const testData = [{ id: 1 }, { id: 2 }];
  component.data.set(testData);
  expect(component.data()).toEqual(testData);
});

it('should handle empty array', () => {
  component.data.set([]);
  expect(component.data()).toEqual([]);
});
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts (2)

1-1: Remove unused imports.

MockInstance (line 1) and ElementRef (line 3) are imported but never used in the test. Removing them improves code cleanliness.

-import { MockInstance } from 'ng-mocks';
 import { CachedIfDirective } from './cached-if.directive';
-import { ElementRef, TemplateRef, ViewContainerRef } from '@angular/core';
+import { TemplateRef, ViewContainerRef } from '@angular/core';
 import { mock } from 'testing';
 import { inject, TestBed } from '@angular/core/testing';

Also applies to: 3-3


26-31: Expand test coverage to verify directive behavior.

The test currently only verifies instantiation. Per coding guidelines, tests should focus on business logic and behavior. Consider adding tests for:

  • How the directive handles truthy/falsy conditions
  • View creation and caching behavior
  • Interaction with TemplateRef and ViewContainerRef

Example test structure:

it('should create view when condition is true', inject(
  [CachedIfDirective],
  (directive: CachedIfDirective) => {
    // Test view creation logic
  }
));

it('should cache and reuse view when toggling condition', inject(
  [CachedIfDirective],
  (directive: CachedIfDirective) => {
    // Test caching behavior
  }
));
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (2)

36-40: Add OnPush change detection strategy.

The component is now fully signal-based and should use ChangeDetectionStrategy.OnPush for optimal performance. This aligns with the coding guidelines and matches the pattern used in related components like AddCollectionQueryDialogComponent and QueryCollectionItemComponent.

Apply this diff:

+import { ChangeDetectionStrategy } from '@angular/core';
+
 @Component({
   selector: 'app-query-collections',
   templateUrl: './query-collections.component.html',
   standalone: false,
+  changeDetection: ChangeDetectionStrategy.OnPush,
 })

Based on coding guidelines.


71-73: Mark derived signal as readonly.

The searchTerm signal is derived from searchInput via the debounce utility and should be marked readonly to prevent accidental mutation and clarify that it's a computed value.

Apply this diff:

 readonly workspaceId = signal('');
 readonly searchInput = signal('');
-searchTerm = debounce(this.searchInput, 300);
+readonly searchTerm = debounce(this.searchInput, 300);
packages/altair-app/src/testing/utils.ts (1)

155-155: Consider preserving stricter propsData type.

The propsData variable is typed as Record<string, unknown>, which is less strict than mountOptions.propsData's type (Partial<{[K in AllowedPropsDataKeys<C>]-?: AllowedPropsDataValue<C, K>}>). This widens the type and loses compile-time safety.

Consider preserving the stricter type:

-  const propsData: Record<string, unknown> = mountOptions.propsData ?? {};
+  const propsData = mountOptions.propsData ?? {} as Partial<{
+    [K in AllowedPropsDataKeys<C>]-?: AllowedPropsDataValue<C, K>;
+  }>;

If the wider type is intentional for internal flexibility, this can be ignored.

packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts (1)

4-4: Simplify ElementRef mock.

The MockElementRef class is unnecessary since it doesn't add any functionality. You can provide ElementRef directly in the factory.

Apply this diff to simplify:

-class MockElementRef extends ElementRef {}
-
 describe('SetCssVariablesDirective', () => {
   beforeEach(() =>
     TestBed.configureTestingModule({
       teardown: { destroyAfterEach: false },
       imports: [],
       providers: [
         SetCssVariablesDirective,
         {
           provide: ElementRef,
-          useFactory: () => new MockElementRef(document.body),
+          useValue: new ElementRef(document.body),
         },
       ],
     })
   );

Also applies to: 13-16

packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts (2)

14-19: Modernize to use TestBed.inject() pattern.

The inject() function used here is from an older Angular testing pattern. Modern Angular tests use TestBed.inject() directly, which is more explicit and aligns with current best practices.

Apply this diff:

-  it('should create an instance', inject(
-    [ThemeDirective],
-    (directive: ThemeDirective) => {
-      expect(directive).toBeTruthy();
-    }
-  ));
+  it('should create an instance', () => {
+    const directive = TestBed.inject(ThemeDirective);
+    expect(directive).toBeTruthy();
+  });

9-9: Remove empty imports array.

The empty imports: [] array serves no purpose and can be removed for cleaner configuration.

Apply this diff:

     TestBed.configureTestingModule({
       teardown: { destroyAfterEach: false },
-      imports: [],
       providers: [ThemeDirective, NzConfigService],
     })
πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 5ec5813 and 9c0110a.

πŸ“’ Files selected for processing (9)
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts (1 hunks)
  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts (5 hunks)
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts (1 hunks)
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts (1 hunks)
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts (1 hunks)
  • packages/altair-app/src/testing/utils.ts (6 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (13)
{**/__tests__/**/*.ts,**/*.{spec,test}.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

{**/__tests__/**/*.ts,**/*.{spec,test}.ts}: Use Jest as the testing framework for all tests
Organize tests next to the code under test: use a tests folder or .test.ts/.spec.ts files alongside sources
Use clear, descriptive test names explaining what is being verified
Mock dependencies with Jest to isolate the unit under test
Leverage TypeScript types in tests; define interfaces/types for expected data shapes

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
**/*.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

Follow project code style using ESLint and Prettier

**/*.ts: Use explicit type annotations for function parameters and return types
Prefer interfaces over type aliases for object shapes
Use union types and literal types for better type safety
Leverage generic types for reusable components
Group imports: external libraries first, then internal modules
Use absolute imports from package roots when possible
Prefer named exports over default exports
Use custom error classes that extend Error
Implement proper error boundaries and handling
Log errors with sufficient context for debugging
Use observables (RxJS) for reactive programming patterns where appropriate
Manage subscriptions to avoid memory leaks
Use appropriate RxJS operators for data transformation
Handle errors in observable streams
Use async/await for sequential operations
Handle promise rejections properly
Use Promise.all() for concurrent operations
Implement timeout handling for long-running operations
Dispose of resources properly (subscriptions, event listeners)
Use weak references where appropriate
Avoid creating unnecessary objects in hot paths
Profile memory usage for performance-critical code
Use tree-shaking-friendly imports
Lazy load heavy modules when possible
Monitor bundle size impacts of new dependencies
Use dynamic imports for code splitting
Validate and sanitize all user inputs
Implement proper XSS and injection prevention
Validate API responses before processing
Sanitize sensitive data in logs
Follow secure coding practices
Group related functionality in modules
Keep files focused and not too large
Use consistent naming conventions
Organize imports and exports clearly
Write JSDoc comments for public APIs
Keep documentation up to date with code changes (inline docs)
Use meaningful variable and function names
Handle environment-specific APIs properly
Use TypeScript features appropriate for the configured version

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
  • packages/altair-app/src/testing/utils.ts
**/*.{ts,tsx}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Use TypeScript for implementation across the codebase

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
  • packages/altair-app/src/testing/utils.ts
packages/altair-app/**/*.{ts,html}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Implement and modify the main web app using Angular conventions within packages/altair-app

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
  • packages/altair-app/src/testing/utils.ts
**/*.{spec,test}.{ts,tsx,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Write and maintain tests; Jest is used for most testing

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
**/*.{test,spec}.{ts,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

**/*.{test,spec}.{ts,js}: Follow the Arrange-Act-Assert (AAA) pattern in tests
Write descriptive test names that explain expected behavior
Keep tests focused and independent
Use consistent naming conventions across all test files
Group related tests using describe blocks
Use nested describe blocks for different methods or scenarios
Place setup code in beforeEach or beforeAll hooks
Clean up resources in afterEach or afterAll hooks
Mock external dependencies to isolate units under test
Use Jest's mocking capabilities effectively
Create reusable mock factories for common dependencies
Verify interactions with mocked dependencies when necessary
Use async/await for testing promises
Test both success and error scenarios in async code
Handle timeouts appropriately in async tests
Test concurrent operations when relevant
For NestJS controllers, test HTTP handling, response formatting, auth, and error/status codes; mock service dependencies
For NestJS services, test business logic, data transformations, error handling/validation, and verify logging/monitoring calls
For API integration tests, test endpoints end-to-end, use test DB/transactions, test auth flows, and verify API contracts/responses
For browser extensions, mock browser APIs (chrome., browser.), test message passing, content scripts, and verify manifest configuration
Write performance tests for critical code paths and set performance budgets/thresholds
Monitor test execution times and profile memory usage in tests
Load test API endpoints, verify graceful degradation, check for resource cleanup/memory leaks, and monitor performance metrics
E2E tests should focus on critical user journeys, use realistic data, test cross-browser, and verify integrations
Use dedicated test environments, mock external services appropriately, ensure data consistency, and clean up test artifacts
Create reusable test data factories and use realistic but anonymized data; version fixtures with code and clean up after tests
Maintain high t...

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
packages/altair-app/**/*.{test,spec}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

packages/altair-app/**/*.{test,spec}.ts: Use the custom testing framework in packages/altair-app/src/testing for Angular component tests
Focus on component business logic rather than UI library behavior
Mock services and external dependencies in component tests
Test component lifecycle methods appropriately
In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services
Do NOT test UI library component properties, template rendering details, CSS, or third-party library behavior in component tests

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
**/*.{spec,test}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{spec,test}.ts: Write unit tests focusing on business logic and behavior
Use descriptive test names
Mock external dependencies appropriately in tests
Test edge cases and error conditions

Files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
packages/altair-app/src/app/modules/altair/components/**/*.spec.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.spec.ts: Only write tests for component business logic; do not test UI libraries (e.g., ng-zorro, Angular Material)
Test component business logic and methods
Test event emissions using wrapper.emitted()
Test state management and property changes of components
Test component lifecycle behavior
Always cover edge cases (null, rapid calls, invalid inputs) in component tests
Verify method return values and side effects in components
Test component interactions with services using mocks
Do not test UI library component props (e.g., nz-modal, nz-button)
Do not test template rendering details
Do not test third-party library behavior
Do not test Angular framework internals
Do not test CSS styling or visual appearance
Access component under test via wrapper.componentInstance for properties and methods
Use wrapper.emitted() to assert emitted events
Focus on asserting state changes in response to actions
Always include tests for error and edge conditions
Avoid fragile emission index tracking across multiple actions in a single test; isolate scenarios per it block

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts: Do not test ng-zorro component properties in unit tests; focus on business logic
Write unit tests that focus on component business logic (events, state changes, methods)
Use the custom testing utilities from packages/altair-app/src/testing in unit tests
Mock external dependencies and services in tests
Avoid testing UI library components or template rendering details in unit tests

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.ts: Place Angular component classes under packages/altair-app/src/app/modules/altair/components/
Prefer ChangeDetectionStrategy.OnPush for components when possible
Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)
Use Angular dependency injection for services and dependencies
Favor reactive programming with RxJS Observables for component state
Manage subscriptions and clean them up in ngOnDestroy
Emit component events using EventEmitter and expose a clear component API
Use @input and @output decorators to define the component API
Use Angular reactive forms for complex forms
Implement proper form validation and error handling
Provide trackBy functions for ngFor loops to improve performance
Avoid memory leaks by unsubscribing from Observables

Files:

  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.{html,ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Ensure keyboard navigation works (focus management and keyboard handlers)

Files:

  • packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
🧠 Learnings (25)
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component interactions with services using mocks

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Mock external dependencies and services in tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test state management and property changes of components

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Mock services and external dependencies in component tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component lifecycle behavior

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:40:52.954Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/nestjs-api.instructions.md:0-0
Timestamp: 2025-10-03T16:40:52.954Z
Learning: Applies to packages/altair-api/src/**/*.spec.ts : Mock dependencies properly in tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
πŸ“š Learning: 2025-10-03T16:36:10.024Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-services.instructions.md:0-0
Timestamp: 2025-10-03T16:36:10.024Z
Learning: Applies to packages/altair-app/src/**/*.service.spec.ts : Mock external dependencies using Jest in service tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Do not test Angular framework internals

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Use the custom testing utilities from packages/altair-app/src/testing in unit tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to **/*.{test,spec}.{ts,js} : Create reusable mock factories for common dependencies

Applied to files:

  • packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Focus on asserting state changes in response to actions

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Avoid fragile emission index tracking across multiple actions in a single test; isolate scenarios per it block

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Test component lifecycle methods appropriately

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component business logic and methods

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Do not test template rendering details

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Use the custom testing framework in packages/altair-app/src/testing for Angular component tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Avoid testing UI library components or template rendering details in unit tests

Applied to files:

  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Verify method return values and side effects in components

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Do not test CSS styling or visual appearance

Applied to files:

  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Access component under test via wrapper.componentInstance for properties and methods

Applied to files:

  • packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
πŸ“š Learning: 2025-10-03T16:39:27.517Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/main.instructions.md:0-0
Timestamp: 2025-10-03T16:39:27.517Z
Learning: Applies to packages/altair-core/**/*.ts : Modify shared logic/types/utilities in packages/altair-core carefully, as changes impact multiple packages; ensure thorough testing

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Focus on component business logic rather than UI library behavior

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Input and Output decorators to define the component API

Applied to files:

  • packages/altair-app/src/testing/utils.ts
🧬 Code graph analysis (4)
packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts (1)
packages/altair-app/src/app/modules/altair/store/query/query.action.ts (1)
  • ClearResultAction (256-260)
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts (1)
packages/altair-app/src/testing/index.ts (1)
  • mock (7-9)
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (6)
packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.ts (1)
  • Component (11-115)
packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts (1)
  • Component (19-198)
packages/altair-app/src/app/modules/altair/services/index.ts (1)
  • QueryCollectionService (10-10)
packages/altair-core/src/types/state/collection.interfaces.ts (3)
  • IQueryCollection (29-56)
  • SortByOptions (7-7)
  • IQueryCollectionTree (65-68)
packages/altair-app/src/app/modules/altair/store/workspace/selectors.ts (1)
  • WorkspaceOption (7-11)
packages/altair-core/src/types/state/workspace.interface.ts (1)
  • WORKSPACES (3-6)
packages/altair-app/src/testing/utils.ts (2)
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (1)
  • Component (36-147)
packages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.ts (1)
  • Component (11-115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: sites / Deploy Sandbox / Deploy Iframe Sandbox
  • GitHub Check: sites / Deploy Web App / Deploy Web App
  • GitHub Check: sites / Deploy Login Redirect / Deploy Login Redirect
  • GitHub Check: sites / Deploy Docs / Deploy Documentation
  • GitHub Check: docker / docker
  • GitHub Check: tests / test (macos-latest)
  • GitHub Check: tests / test (ubuntu-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: tauri / tauri (ubuntu-22.04)
  • GitHub Check: tauri / tauri (windows-latest)
  • GitHub Check: tests / api-e2e-test
  • GitHub Check: tauri / tauri (macos-latest, --target x86_64-apple-darwin)
  • GitHub Check: tests / e2e-test (macos-latest)
  • GitHub Check: tests / e2e-test (ubuntu-latest)
  • GitHub Check: electron / electron (macos-latest)
  • GitHub Check: electron / electron (windows-latest)
  • GitHub Check: electron / electron (ubuntu-latest)
  • GitHub Check: build_and_preview
πŸ”‡ Additional comments (12)
packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (2)

44-49: LGTM!

The migration from @Input decorators to Angular Signals using input() is correctly implemented with appropriate default values and type annotations.


77-109: LGTM!

The computed signals are well-structured with correct signal reading syntax. The filtering logic for collections and queries is sound, workspace filtering is properly implemented, and the auto-expansion logic during search enhances UX.

packages/altair-app/src/testing/utils.ts (6)

7-8: LGTM! Signal imports added for migration.

The addition of Signal and inject imports appropriately supports the signals-based testing infrastructure updates.


71-123: Well-structured signal detection and input separation.

The refactored getComponentMeta function correctly:

  • Separates normal @Input properties from signal inputs using member.isSignal
  • Provides clear JSDoc documentation for each input category
  • Maintains backward compatibility with availableInputs tracking

The signal detection logic aligns with Angular's signal input metadata structure.


125-125: Excellent type-safe signal property handling.

The new type utilities correctly:

  • Extract signal properties via FilteredSignalKeys<T>
  • Unwrap signal value types using AllowedPropsDataValue<T, K>
  • Maintain type safety for both regular properties and signal inputs in propsData

This design enables type-safe testing of signal-based components while preserving compile-time checks.

Also applies to: 139-146


127-132: Type definitions updated for signal support.

The updated BaseTestHostComponent and TestMountOptions correctly incorporate ComponentMeta and the new type utilities, maintaining type safety throughout the testing infrastructure.

Also applies to: 147-152


174-174: Correct inject() usage and signal value extraction.

The implementation correctly:

  • Uses inject(ViewContainerRef) as a class field (line 174), which is the recommended Angular pattern
  • Distinguishes signal inputs from normal inputs when extracting default values (lines 193-197)
  • Calls signal inputs as functions componentRef.instance[cur]() to retrieve their values
  • Accesses normal input properties directly
  • Properly cleans up the temporary component instance (line 208)

The default value resolution logic properly handles both signal and non-signal inputs while avoiding memory leaks.

Also applies to: 181-209


244-264: Template generation correctly handles both input types.

The updated buildTestHostComponentTemplate correctly:

  • Accepts ComponentMeta with separated input categories
  • Combines normalInputs and signalInputs for template generation (line 248)
  • Uses property binding syntax [input]="inputs.input" which works uniformly for both signal and normal inputs

The template construction properly reflects the unified binding approach for both input types.

packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts (1)

1-26: Ignore custom testing utilities for directive tests: Directive tests in this module consistently use plain TestBed and inject; the custom mount utilities target component specs only.

Likely an incorrect or invalid review comment.

packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts (3)

61-76: LGTM: MockService improves test reliability.

Using ng-mocks' MockService utility (imported on line 15) provides better type safety and Angular-aware service mocking compared to the custom mock() helper.


99-99: LGTM: Correct signal input initialization.

Using fixture.componentRef.setInput() is the proper way to initialize signal-based inputs before the component lifecycle runs.


113-113: LGTM: Correct signal accessor pattern.

Calling windowId() as a function is the correct pattern for accessing signal-based inputs after migration.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (2)

108-115: Critical: Signal not invoked on line 112.

Line 108 correctly calls selectedEnvironmentId() to get the signal value, but line 112 omits the parentheses, passing the signal object itself instead of its value to the event emitter.

Apply this diff:

       } else {
         this.subEnvironmentJsonChange.next({
-          id: this.selectedEnvironmentId,
+          id: this.selectedEnvironmentId(),
           value: content,
         });
       }

127-132: Critical: Signal not invoked on line 129.

The selectedEnvironmentId signal is referenced without calling it, passing the signal object instead of its value.

Apply this diff:

   onTitleChange(content: string) {
     this.subEnvironmentTitleChange.next({
-      id: this.selectedEnvironmentId,
+      id: this.selectedEnvironmentId(),
       value: content,
     });
   }
packages/altair-app/src/app/modules/altair/containers/altair/altair.component.ts (1)

779-779: Use string for collectionId in exportCollection
Update the method signature in packages/altair-app/src/app/modules/altair/containers/altair/altair.component.ts (line 779) to

exportCollection({ collectionId }: { collectionId: string })

and change the payload type in packages/altair-app/src/app/modules/altair/store/collection/collection.action.ts (line 99) to

constructor(public payload: { collectionId: string }) {}

to align with the globally string-based collection IDs.

♻️ Duplicate comments (11)
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.html (1)

55-60: Selection highlight mismatch for undefined ids

onSelectEnvironment(item.id) still normalizes undefined ids to '', yet ngClass compares against the raw item.id. When an item lacks an id, the stored value becomes '', so the highlight never matches and the newly selected row is not marked. Compare against the normalized value (or stop coalescing on set) to keep selection styling in sync.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html (1)

7-7: Restore explicit signal reads/writes for ngModel.

[(ngModel)]="data" assigns to the signal variable, replacing the ModelSignal instance and breaking subsequent updates. Read via data() and write via data.set() so the signal survives.

-          <nz-input-number [(ngModel)]="data" [name]="item.key" />
+          <nz-input-number
+            [ngModel]="data()"
+            [name]="item.key"
+            (ngModelChange)="data.set($event)"
+          />
@@
-          <nz-switch [(ngModel)]="data" [name]="item.key" />
+          <nz-switch
+            [ngModel]="data()"
+            [name]="item.key"
+            (ngModelChange)="data.set($event)"
+          />
@@
-                <nz-select [(ngModel)]="data" name="item.key" nzPlaceHolder="Choose">
+                <nz-select
+                  [ngModel]="data()"
+                  [name]="item.key"
+                  nzPlaceHolder="Choose"
+                  (ngModelChange)="data.set($event)"
+                >

Also applies to: 13-13, 40-40

packages/altair-app/package.json (1)

110-114: Bump ESLint to v9 to satisfy angular-eslint 20.3.0.

@angular-eslint/*@20.3.0 requires eslint@^9 (and @typescript-eslint@^8). We only bumped the TypeScript‑ESLint packages; keeping eslint at ^8.57.0 causes pnpm/yarn to throw peer dependency errors and breaks linting/installs. Please upgrade eslint (and any dependent configs/plugins) to a compatible v9 release in the same change.

-    "eslint": "^8.57.0",
+    "eslint": "^9.11.0",

Also verify any local eslint-* configs/plugins still align after the bump.

packages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts (1)

20-25: Modernize DI pattern and add behavioral tests.

The test still uses the deprecated inject() function from @angular/core/testing and only verifies instantiation. Per coding guidelines, tests should focus on business logic and behavior.

Apply this diff to modernize the test and add behavioral coverage:

-  it('should create an instance', inject(
-    [SetCssVariablesDirective],
-    (directive: SetCssVariablesDirective) => {
-      expect(directive).toBeTruthy();
-    }
-  ));
+  it('should create an instance', () => {
+    const directive = TestBed.inject(SetCssVariablesDirective);
+    expect(directive).toBeTruthy();
+  });
+
+  // Add behavioral tests:
+  // - Test CSS variable setting when input changes
+  // - Test lifecycle hooks (e.g., OnInit, OnChanges)
+  // - Test the directive's interaction with ElementRef
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

74-83: Race condition and missing error handling in async effect.

This effect has two issues:

  1. Race condition (previously flagged): Multiple concurrent requests can lead to stale data if selectedTeamId changes rapidly. The async effect doesn't cancel previous requests.

  2. Missing error handling: The getTeamMembers call has no try-catch block, so unhandled promise rejections could crash the effect.

Consider the RxJS-based solution suggested in the previous review, and add error handling:

constructor(...) {
  toObservable(this.selectedTeamId)
    .pipe(
      switchMap(selectedTeamId => {
        if (!selectedTeamId) {
          return of([]);
        }
        return from(this.accountService.getTeamMembers(selectedTeamId)).pipe(
          catchError(err => {
            this.notifyService.error('Failed to load team members');
            return of([]);
          })
        );
      }),
      takeUntilDestroyed()
    )
    .subscribe(members => this.membersOfSelectedTeam.set(members || []));
}
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)

25-29: Critical: Signal inputs not available during construction.

The constructor initializes value$ by calling getSettingKey(), which reads this.featureKey(). However, signal inputs are set after construction, so featureKey() returns the default value (empty string) instead of the actual input value. This results in an incorrect selector key like 'beta.disable.' instead of 'beta.disable.newEditor', breaking the component's functionality.

Move the value$ initialization to ngOnInit or use a computed signal:

+import { Component, OnInit, input, inject } from '@angular/core';
...
-export class BetaIndicatorComponent {
+export class BetaIndicatorComponent implements OnInit {
...
   value$: Observable<boolean>;

-  constructor() {
+  constructor() {}
+
+  ngOnInit() {
     this.value$ = this.store.select(
       (state) => !state.settings[this.getSettingKey()]
     );
   }

Alternatively, use a computed signal pattern:

+import { computed } from '@angular/core';
+import { toObservable } from '@angular/core/rxjs-interop';
...
-  value$: Observable<boolean>;
+  readonly value$ = toObservable(
+    computed(() => !this.store.selectSignal(
+      (state) => state.settings[this.getSettingKey()]
+    )())
+  );

-  constructor() {
-    this.value$ = this.store.select(
-      (state) => !state.settings[this.getSettingKey()]
-    );
-  }
+  constructor() {}
packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)

62-80: LGTM! All inputs successfully migrated to signal-based input().

All component inputs have been consistently migrated to signal wrappers, including showVariableDialog (line 71). This addresses the migration goals and maintains a clean, type-safe API.

Note: A previous review comment flagged showVariableDialog as not migrated, but it is correctly migrated on line 71.

packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts (1)

218-222: Remove no-op store selection.

Re-introduced the bare self.store.select(...) call without subscribe/assignmentβ€”it does nothing, but still instantiates the observable. Drop it and rely on the subscribed one right below.

         constructor(view: EditorView) {
           const windowId = self.windowId();
-          self.store.select(selectActiveEnvironmentsList(windowId));
           this.unsubscribe = self.store
             .select(selectActiveEnvironmentsList(windowId))
packages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts (1)

163-168: Avoid mutating the signal array in-place before calling set().

this.docHistory() returns the live array reference; popping it mutates the signal value before set(). Because the reference is unchanged, Angular skips notifying dependents, and history/navigation glitches. Copy the array first, and only set() after cloning.

-    if (this.docHistory().length) {
-      const history = this.docHistory();
-      const lastItem = history.pop();
-      this.docHistory.set(history);
-      // Set the doc view to the last item in history
-      this.setDocView(lastItem);
+    const history = [...this.docHistory()];
+    const lastItem = history.pop();
+    if (lastItem) {
+      this.docHistory.set(history);
+      this.setDocView(lastItem);
     }
packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

98-100: Replace the as [] assertion with a real array guard.

The old as [] cast is still here; it narrows the type to a zero-length tuple and undermines type safety. Guard the value with Array.isArray instead (and reuse the already derived fileVariable.data).

-    this.showWarning = Boolean(
-      !fileVariable?.isMultiple && (fileVariable.data as [])?.length > 1
-    );
+    this.showWarning = Boolean(
+      !fileVariable?.isMultiple &&
+        Array.isArray(fileVariable.data) &&
+        fileVariable.data.length > 1
+    );
packages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.ts (1)

50-53: Verify production usage: is collection always provided?

The error message was improved from "this should never happen" to "Collection is required to update", but collection remains an optional signal. If this component is always invoked with a collection in production, consider making the signal required:

-  readonly collection = input<IQueryCollection>();
+  readonly collection = input.required<IQueryCollection>();

This prevents the runtime error by enforcing the requirement at compile time.

Run this script to verify all usages provide a collection:

#!/bin/bash
# Search for component usage in templates
rg -nP --type html '<app-edit-collection-dialog' packages/altair-app/src/app/ -A 5 | \
  rg '\[collection\]'
🧹 Nitpick comments (17)
packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts (1)

12-12: Remove unused OnInit import.

The OnInit interface is imported but never implemented by QueryResultComponent (line 38 implements only AfterViewInit).

Apply this diff to remove the unused import:

   input,
-  OnInit,
   computed,
packages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.ts (1)

17-18: Add explicit type parameters to signal inputs

-  readonly showVariableDialog = input(false);
-  readonly variables = input('');
+  readonly showVariableDialog = input<boolean>(false);
+  readonly variables = input<string>('');
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

33-33: Provide a default empty array for the teams input.

The teams input doesn't have a default value, which means it could be undefined. While the code handles this at line 47 with a check, it would be more defensive and clearer to provide a default empty array.

Apply this diff:

-  readonly teams = input<Team[]>();
+  readonly teams = input<Team[]>([]);
packages/altair-app/src/app/modules/altair/components/upgrade-dialog/upgrade-dialog.component.ts (1)

21-28: Excellent signals migration!

The migration from @Input() decorators to signal-based input() is implemented correctly:

  • Default values preserved (showDialog, planInfos)
  • Types properly specified with input<IPlan>() and input<IPlanInfo[]>([])
  • readonly modifiers correctly applied
  • proPlanInfo computed signal appropriately replaces the logic previously in ngOnChanges

Optional: Minor type annotation cleanup.

Line 27: The explicit type annotation (planInfo: IPlanInfo) is redundant since TypeScript infers it from IPlanInfo[]. You can simplify to:

-    return this.planInfos()?.find((planInfo: IPlanInfo) => planInfo.role === 'pro');
+    return this.planInfos()?.find((planInfo) => planInfo.role === 'pro');

Similarly, the optional chaining ?. is defensive but unnecessary since planInfos has a default value of []. However, keeping it doesn't hurt and adds safety if defaults change.

packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts (1)

30-40: Consider guarding against race conditions.

If queryId changes rapidly, multiple API requests could be in flight simultaneously. The last-resolved request (not necessarily from the most recent queryId) could overwrite revisions, causing stale data to appear.

Consider one of these approaches:

Option 1: Use RxJS with switchMap to cancel stale requests:

import { toSignal } from '@angular/core/rxjs-interop';
import { switchMap, of } from 'rxjs';

readonly revisions = toSignal(
  toObservable(this.queryId).pipe(
    switchMap(queryId => 
      queryId ? from(this.api.getQueryRevisions(queryId)) : of([])
    )
  ),
  { initialValue: [] }
);

Option 2: Track the latest request with a counter:

private fetchCounter = 0;

constructor() {
  effect(() => {
    const queryId = this.queryId();
    const currentFetch = ++this.fetchCounter;
    if (queryId) {
      this.api.getQueryRevisions(queryId)
        .then((res) => {
          if (currentFetch === this.fetchCounter) {
            this.revisions.set(res);
          }
        })
        .catch((error) => {
          console.error('Failed to fetch query revisions:', error);
        });
    }
  });
}
packages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts (1)

125-187: Consider using computed() for reactive sorting.

While the current @memoize() decorator works, the sortedCollectionQueries method could be converted to a computed() signal for better integration with Angular's signals reactivity system. This would provide automatic dependency tracking and more predictable memoization.

Example refactor:

readonly sortedCollectionQueries = computed(() => {
  const queries = this.collectionTree().queries;
  const sortBy = this.queriesSortBy();
  
  if (!queries) {
    return [];
  }

  switch (sortBy) {
    case 'a-z':
      return queries.sort((a, b) => {
        const aName = a.windowName.toLowerCase() || a.updated_at || '';
        const bName = b.windowName.toLowerCase() || b.updated_at || '';
        return aName > bName ? 1 : aName < bName ? -1 : 0;
      });
    // ... other cases
    default:
      return queries;
  }
});

Then in the template:

@for (query of sortedCollectionQueries(); track trackById($index, query))
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts (1)

71-77: Optional parameter type can be simplified.

The cspNonce?: string parameter is optional, but the cspNonce signal is defined as input<string>('') with a default empty string, meaning it will never return undefined. The optional marker is harmless but slightly misleading.

Consider removing the optional marker for consistency:

-private createEmotionInstance(cspNonce?: string) {
+private createEmotionInstance(cspNonce: string) {
   this.emotionInstance = createEmotion({
     key: 'altair-theme',
     nonce: cspNonce,
   });
   return this.emotionInstance;
 }
packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts (2)

44-44: Reconsider destroyAfterEach: false to prevent test pollution.

Setting destroyAfterEach to false prevents Angular from cleaning up the TestBed after each test, which can lead to test pollution and flaky tests. Unless there's a specific reason for this configuration, remove this line to use the default behavior (true).

Apply this diff:

-    teardown: { destroyAfterEach: false },
+    teardown: { destroyAfterEach: true },

Or simply remove the line entirely:

   TestBed.configureTestingModule({
-    teardown: { destroyAfterEach: false },
     imports: [],

91-121: Behavioral test restored successfully.

The test for convertToNamedQuery correctly verifies that the effect dispatches SetQueryAction when processing ConvertToNamedQueryAction. This addresses the concern raised in the previous review about missing behavioral coverage.

However, consider adding test cases for error scenarios (e.g., when nameQuery throws an error or returns invalid data) to improve coverage.

packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)

197-217: Consider consolidating initialization logic.

There's significant overlap between effects, ngOnInit, and ngAfterViewInit:

  • Effects in the constructor (lines 142-187) handle ongoing updates to schema, tabSize, lineNumbers, variables, windowId, and shortcuts
  • ngOnInit (lines 197-207) conditionally initializes these same properties, but only if gqlSchema exists
  • ngAfterViewInit (lines 209-217) unconditionally re-initializes all these properties

Since all update methods have guards checking editor?.view and effects run initially with current values, the explicit calls in lifecycle hooks may be redundant. Consider:

  • Removing the conditional from ngOnInit (line 199) that skips initialization when gqlSchema is absentβ€”properties like tabSize and disableLineNumbers should still be set
  • Optionally, rely solely on effects for updates after ensuring they run once the view is ready
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.ts (1)

26-54: Race condition resolved; minor optimization opportunity.

The previous race condition concern has been addressedβ€”hasView is now updated immediately after state changes (lines 35, 49). However, line 41 sets hasView.set(true) unconditionally, even when the view is already attached (when !hasView() is false). This is redundant but not harmful.

Consider this optimization to avoid the redundant set:

       } else {
         // Re-attach the cached view if not already attached
         if (!this.hasView()) {
           this.viewContainer.insert(this.cachedViewRef);
+          this.hasView.set(true);
         }
-        this.hasView.set(true);
       }
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts (1)

7-31: TestBed setup is correct; consider expanding test coverage.

The TestBed configuration properly provides mocked dependencies for the directive's inject-based DI. The test verifies instantiation works with the new setup. As per coding guidelines, consider expanding the test to cover the directive's business logic: view creation, caching, attachment/detachment behavior, and the effect's reactivity to appCachedIf() changes.

Based on learnings.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (1)

25-26: Consider explicit type guards or non-null defaults for signal inputs.

The schema input defaults to {} (empty object) and data defaults to null. While these may be valid defaults, consider:

  • Explicitly typing the default for schema as JSONSchema6 (e.g., { type: 'object', properties: {} }) if an empty object doesn't satisfy the schema structure.
  • Using undefined instead of null for data if nullable values have no special meaning, to align with TypeScript's optional semantics.

Example refinement:

-  readonly schema = input<JSONSchema6>({});
-  readonly data = input<unknown>(null);
+  readonly schema = input<JSONSchema6>({ type: 'object', properties: {} });
+  readonly data = input<unknown>(undefined);

Only apply this if the defaults need to be more explicit or if null vs. undefined has semantic significance in your codebase.

packages/altair-app/src/app/modules/altair/components/tips/tips.component.ts (1)

85-96: Add explicit return type annotation.

Please declare the setupTipInterval return type (e.g., : void) so we adhere to the project rule requiring explicit return annotations for functions and methods. As per coding guidelines

packages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts (1)

23-32: Type the debounce timer and reset it on cleanup.

timeout: any defeats TypeScript’s safety and makes ESLint unhappy. Typing it as the actual timer handle (and clearing + resetting it) keeps the debounce utility strongly typed and avoids stale handles lingering after cleanup.

-function debounce<T>(input: Signal<T>, delay = 300) {
+function debounce<T>(input: Signal<T>, delay = 300) {
   const out = signal(input());
-  let timeout: any;
+  let timeout: ReturnType<typeof setTimeout> | undefined;
 
   effect((onCleanup) => {
     const value = input();
     clearTimeout(timeout);
     timeout = setTimeout(() => out.set(value), delay);
-    onCleanup(() => clearTimeout(timeout));
+    onCleanup(() => {
+      if (timeout !== undefined) {
+        clearTimeout(timeout);
+        timeout = undefined;
+      }
+    });
   });
 
   return out.asReadonly();
 }
packages/altair-app/src/app/modules/altair/components/element-wrapper/element-wrapper.component.ts (1)

31-33: Initial render logic preserved.

Calling handleRender in ngAfterViewInit ensures the element is appended after the view is ready, regardless of when signals are first set. This complements the effect which handles subsequent updates.

Minor note: The effect in the constructor also attempts to call handleRender, but the elRef check ensures it's harmless. If you prefer to eliminate the redundant initial call, you could use afterNextRender() instead of ngAfterViewInit, but the current pattern is clear and works correctly.

packages/altair-app/src/app/modules/altair/components/codemirror/codemirror.component.ts (1)

109-124: Consider cleanup for the redrawLayout effect timeout.

The setTimeout in the effect could leak if the effect re-runs or the component is destroyed before the timeout completes.

Store the timeout handle and clean it up:

+  private redrawTimeout?: ReturnType<typeof setTimeout>;
+
   constructor() {
     // ... other effects
     
     effect(() => {
       if (this.redrawLayout()) {
+        // Clear any pending redraw
+        if (this.redrawTimeout) {
+          clearTimeout(this.redrawTimeout);
+        }
         // wait for animations to finish
-        setTimeout(() => {
+        this.redrawTimeout = setTimeout(() => {
           if (this.view) {
             this.view.dispatch({
               changes: {
                 from: 0,
                 to: this.view.state.doc.length,
                 insert: this.view.state.doc.sliceString(0),
               },
             });
           }
         }, 250);
       }
     });
   }
+
+  ngOnDestroy() {
+    if (this.redrawTimeout) {
+      clearTimeout(this.redrawTimeout);
+    }
     this.view?.destroy();
   }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

87-110: Inconsistent data access: mixing parameter and signal reads.

The method receives fileVariable as a parameter but inconsistently accesses data from both the parameter (lines 89, 97) and the signal this.fileVariable() (line 93). This creates confusion and potential bugs if the parameter value differs from the current signal value.

Choose one approach:

Option 1 (Recommended): Remove the parameter and read exclusively from the signal:

-  updateLocalState(fileVariable?: FileVariable) {
-    this.validFileData = Array.isArray(fileVariable?.data)
-      ? fileVariable.data.filter((data) => data instanceof File)
+  updateLocalState() {
+    const fileVariable = this.fileVariable();
+    this.validFileData = Array.isArray(fileVariable?.data)
+      ? fileVariable.data.filter((data) => data instanceof File)
       : [];

     const data = this.fileVariable()?.data;
     this.invalidFileData =
       (Array.isArray(data) ? data.length : 0) > this.validFileData.length;
     this.showWarning = Boolean(
-      !fileVariable?.isMultiple && (fileVariable?.data as [])?.length > 1
+      !fileVariable?.isMultiple && (data as unknown[])?.length > 1
     );

Option 2: Keep the parameter but use it consistently throughout:

   updateLocalState(fileVariable?: FileVariable) {
     this.validFileData = Array.isArray(fileVariable?.data)
       ? fileVariable.data.filter((data) => data instanceof File)
       : [];

-    const data = this.fileVariable()?.data;
+    const data = fileVariable?.data;
     this.invalidFileData =
       (Array.isArray(data) ? data.length : 0) > this.validFileData.length;
     this.showWarning = Boolean(
-      !fileVariable?.isMultiple && (fileVariable?.data as [])?.length > 1
+      !fileVariable?.isMultiple && (data as unknown[])?.length > 1
     );
♻️ Duplicate comments (2)
packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

97-97: Fix incorrect type assertion (duplicate issue).

The type cast as [] represents an empty tuple type, not a general array. This was flagged in a previous review and remains unfixed.

Apply this fix:

     this.showWarning = Boolean(
-      !fileVariable?.isMultiple && (fileVariable?.data as [])?.length > 1
+      !fileVariable?.isMultiple && (Array.isArray(fileVariable?.data) && fileVariable.data.length > 1)
     );

Or use proper array type casting:

-      !fileVariable?.isMultiple && (fileVariable?.data as [])?.length > 1
+      !fileVariable?.isMultiple && (fileVariable?.data as unknown[])?.length > 1
     );
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)

25-29: Critical: Signal inputs still accessed during construction.

This issue was previously flagged: the constructor initializes value$ by calling getSettingKey(), which reads this.featureKey(). Signal inputs are set after construction, so featureKey() returns an uninitialized value, resulting in an incorrect selector key (e.g., 'beta.disable.' instead of 'beta.disable.newEditor').

Please move the initialization to ngOnInit or use a computed signal as suggested in the previous review comment.

🧹 Nitpick comments (3)
packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts (1)

33-37: Readability improvement looks good.

The explicit if/else block is clearer than a ternary expression for this branching logic.

Optionally, consider improving type safety for the fn parameter:

-const createStoreSubscribeFn = (environments: any) => {
-  return (fn: any) => {
+type SubscribeCallback = ((state: { environments: any }) => void) | { next: (state: { environments: any }) => void };
+
+const createStoreSubscribeFn = (environments: any) => {
+  return (fn: SubscribeCallback) => {
     if (typeof fn === 'function') {
       fn({ environments });
     } else {
       fn.next({ environments });
     }
     return new Subscription();
   };
 };

This would align with the coding guideline to "use explicit type annotations for function parameters" and prevent potential runtime errors if fn.next is undefined.

packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

53-72: Consider refactoring to avoid redundant updateLocalState call.

Both the effect (line 48) and ngOnInit (line 56) call updateLocalState, which means the method executes twice during initialization. While the cache-loading logic (lines 57-70) needs to run after state initialization, the double invocation could be avoided by:

  1. Removing the updateLocalState call from ngOnInit and letting the effect handle it
  2. Moving the cache-loading logic into a separate method called after the effect has updated state
  3. Using a flag to skip the effect's update during initial setup

If the double call is intentional for safety, consider adding a comment explaining why.

packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)

23-23: Consider completing the signals migration for value$.

Since this PR migrates inputs to signals, you could also convert value$ to a computed signal for consistency:

-  value$: Observable<boolean>;
+  readonly value$ = toObservable(
+    computed(() => !this.store.selectSignal((state) => state.settings[this.getSettingKey()])())
+  );

-  constructor() {
-    this.value$ = this.store.select(
-      (state) => !state.settings[this.getSettingKey()]
-    );
-  }
+  constructor() {}

This would align the component fully with the new signals-based reactive model, though the current Observable approach remains valid.

Also applies to: 25-29

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between f885767 and bed7dfe.

πŸ“’ Files selected for processing (8)
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (4 hunks)
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (4 hunks)
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts (3 hunks)
  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts (1 hunks)
  • packages/altair-app/src/testing/utils.ts (7 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (12)
**/*.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

Follow project code style using ESLint and Prettier

**/*.ts: Use explicit type annotations for function parameters and return types
Prefer interfaces over type aliases for object shapes
Use union types and literal types for better type safety
Leverage generic types for reusable components
Group imports: external libraries first, then internal modules
Use absolute imports from package roots when possible
Prefer named exports over default exports
Use custom error classes that extend Error
Implement proper error boundaries and handling
Log errors with sufficient context for debugging
Use observables (RxJS) for reactive programming patterns where appropriate
Manage subscriptions to avoid memory leaks
Use appropriate RxJS operators for data transformation
Handle errors in observable streams
Use async/await for sequential operations
Handle promise rejections properly
Use Promise.all() for concurrent operations
Implement timeout handling for long-running operations
Dispose of resources properly (subscriptions, event listeners)
Use weak references where appropriate
Avoid creating unnecessary objects in hot paths
Profile memory usage for performance-critical code
Use tree-shaking-friendly imports
Lazy load heavy modules when possible
Monitor bundle size impacts of new dependencies
Use dynamic imports for code splitting
Validate and sanitize all user inputs
Implement proper XSS and injection prevention
Validate API responses before processing
Sanitize sensitive data in logs
Follow secure coding practices
Group related functionality in modules
Keep files focused and not too large
Use consistent naming conventions
Organize imports and exports clearly
Write JSDoc comments for public APIs
Keep documentation up to date with code changes (inline docs)
Use meaningful variable and function names
Handle environment-specific APIs properly
Use TypeScript features appropriate for the configured version

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/testing/utils.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.ts: Place Angular component classes under packages/altair-app/src/app/modules/altair/components/
Prefer ChangeDetectionStrategy.OnPush for components when possible
Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)
Use Angular dependency injection for services and dependencies
Favor reactive programming with RxJS Observables for component state
Manage subscriptions and clean them up in ngOnDestroy
Emit component events using EventEmitter and expose a clear component API
Use @input and @output decorators to define the component API
Use Angular reactive forms for complex forms
Implement proper form validation and error handling
Provide trackBy functions for ngFor loops to improve performance
Avoid memory leaks by unsubscribing from Observables

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.{html,ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Ensure keyboard navigation works (focus management and keyboard handlers)

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
**/*.{ts,tsx}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Use TypeScript for implementation across the codebase

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/testing/utils.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
packages/altair-app/**/*.{ts,html}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Implement and modify the main web app using Angular conventions within packages/altair-app

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
  • packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
  • packages/altair-app/src/testing/utils.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
{**/__tests__/**/*.ts,**/*.{spec,test}.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

{**/__tests__/**/*.ts,**/*.{spec,test}.ts}: Use Jest as the testing framework for all tests
Organize tests next to the code under test: use a tests folder or .test.ts/.spec.ts files alongside sources
Use clear, descriptive test names explaining what is being verified
Mock dependencies with Jest to isolate the unit under test
Leverage TypeScript types in tests; define interfaces/types for expected data shapes

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
packages/altair-app/src/**/*.service.spec.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-services.instructions.md)

packages/altair-app/src/**/*.service.spec.ts: Mock external dependencies using Jest in service tests
Test public methods and observable streams of services
Verify NgRx interactions (selectors and actions) in service tests
Test error handling scenarios in service tests

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
**/*.{spec,test}.{ts,tsx,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Write and maintain tests; Jest is used for most testing

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
**/*.{test,spec}.{ts,js}

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

**/*.{test,spec}.{ts,js}: Follow the Arrange-Act-Assert (AAA) pattern in tests
Write descriptive test names that explain expected behavior
Keep tests focused and independent
Use consistent naming conventions across all test files
Group related tests using describe blocks
Use nested describe blocks for different methods or scenarios
Place setup code in beforeEach or beforeAll hooks
Clean up resources in afterEach or afterAll hooks
Mock external dependencies to isolate units under test
Use Jest's mocking capabilities effectively
Create reusable mock factories for common dependencies
Verify interactions with mocked dependencies when necessary
Use async/await for testing promises
Test both success and error scenarios in async code
Handle timeouts appropriately in async tests
Test concurrent operations when relevant
For NestJS controllers, test HTTP handling, response formatting, auth, and error/status codes; mock service dependencies
For NestJS services, test business logic, data transformations, error handling/validation, and verify logging/monitoring calls
For API integration tests, test endpoints end-to-end, use test DB/transactions, test auth flows, and verify API contracts/responses
For browser extensions, mock browser APIs (chrome., browser.), test message passing, content scripts, and verify manifest configuration
Write performance tests for critical code paths and set performance budgets/thresholds
Monitor test execution times and profile memory usage in tests
Load test API endpoints, verify graceful degradation, check for resource cleanup/memory leaks, and monitor performance metrics
E2E tests should focus on critical user journeys, use realistic data, test cross-browser, and verify integrations
Use dedicated test environments, mock external services appropriately, ensure data consistency, and clean up test artifacts
Create reusable test data factories and use realistic but anonymized data; version fixtures with code and clean up after tests
Maintain high t...

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
packages/altair-app/**/*.{test,spec}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/testing.instructions.md)

packages/altair-app/**/*.{test,spec}.ts: Use the custom testing framework in packages/altair-app/src/testing for Angular component tests
Focus on component business logic rather than UI library behavior
Mock services and external dependencies in component tests
Test component lifecycle methods appropriately
In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services
Do NOT test UI library component properties, template rendering details, CSS, or third-party library behavior in component tests

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
**/*.{spec,test}.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.{spec,test}.ts: Write unit tests focusing on business logic and behavior
Use descriptive test names
Mock external dependencies appropriately in tests
Test edge cases and error conditions

Files:

  • packages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.ts
🧠 Learnings (15)
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Angular reactive forms for complex forms

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts
πŸ“š Learning: 2025-10-03T16:36:10.024Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-services.instructions.md:0-0
Timestamp: 2025-10-03T16:36:10.024Z
Learning: Applies to packages/altair-app/src/**/*.service.ts : Implement robust error handling and retry logic for HTTP calls

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Input and Output decorators to define the component API

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
  • packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
πŸ“š Learning: 2025-10-03T16:36:10.024Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-services.instructions.md:0-0
Timestamp: 2025-10-03T16:36:10.024Z
Learning: Applies to packages/altair-app/src/**/*.service.ts : NgRx-integrated services should inject Store<RootState>

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : In components, test methods, business logic, event emissions, state changes, lifecycle, and integration with injected services

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test state management and property changes of components

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:39:27.517Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/main.instructions.md:0-0
Timestamp: 2025-10-03T16:39:27.517Z
Learning: Applies to packages/altair-core/**/*.ts : Modify shared logic/types/utilities in packages/altair-core carefully, as changes impact multiple packages; ensure thorough testing

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Focus on component business logic rather than UI library behavior

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Test component lifecycle methods appropriately

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Use the custom testing utilities from packages/altair-app/src/testing in unit tests

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component interactions with services using mocks

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-09-24T19:40:17.905Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/app-testing.instructions.md:0-0
Timestamp: 2025-09-24T19:40:17.905Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.spec.ts : Test component lifecycle behavior

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.spec.ts : Avoid testing UI library components or template rendering details in unit tests

Applied to files:

  • packages/altair-app/src/testing/utils.ts
πŸ“š Learning: 2025-10-03T16:41:45.498Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/testing.instructions.md:0-0
Timestamp: 2025-10-03T16:41:45.498Z
Learning: Applies to packages/altair-app/**/*.{test,spec}.ts : Use the custom testing framework in packages/altair-app/src/testing for Angular component tests

Applied to files:

  • packages/altair-app/src/testing/utils.ts
🧬 Code graph analysis (6)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (1)
packages/altair-app/src/app/modules/altair/utils/settings_addons.ts (2)
  • SchemaFormProperty (5-9)
  • getSchemaFormProperty (19-34)
packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts (1)
packages/altair-api-utils/src/client.ts (1)
  • QueryItemRevisionWithUsername (39-41)
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts (1)
packages/altair-core/src/theme/theme.ts (1)
  • ICustomTheme (217-217)
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (2)
packages/altair-core/src/types/state/state.interfaces.ts (1)
  • RootState (12-23)
packages/altair-core/src/types/state/settings.interfaces.ts (1)
  • SettingsState (8-195)
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (2)
packages/altair-app/src/app/modules/altair/services/index.ts (1)
  • NotifyService (5-5)
packages/altair-core/src/types/state/environments.interfaces.ts (3)
  • EnvironmentsState (36-41)
  • EnvironmentState (25-30)
  • BaseEnvironmentState (20-24)
packages/altair-app/src/testing/utils.ts (2)
packages/altair-app/src/testing/wrapper/index.ts (1)
  • props (166-172)
packages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts (1)
  • Component (8-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: sites / Deploy Sandbox / Deploy Iframe Sandbox
  • GitHub Check: sites / Deploy Docs / Deploy Documentation
  • GitHub Check: sites / Deploy Web App / Deploy Web App
  • GitHub Check: sites / Deploy Login Redirect / Deploy Login Redirect
  • GitHub Check: tauri / tauri (windows-latest)
  • GitHub Check: tauri / tauri (ubuntu-22.04)
  • GitHub Check: tauri / tauri (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: electron / electron (ubuntu-latest)
  • GitHub Check: electron / electron (windows-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target x86_64-apple-darwin)
  • GitHub Check: electron / electron (macos-latest)
  • GitHub Check: docker / docker
  • GitHub Check: tests / e2e-test (ubuntu-latest)
  • GitHub Check: tests / e2e-test (macos-latest)
  • GitHub Check: tests / test (ubuntu-latest)
  • GitHub Check: tests / api-e2e-test
  • GitHub Check: tests / test (macos-latest)
  • GitHub Check: build_and_preview
πŸ”‡ Additional comments (22)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.ts (3)

24-39: LGTM! Signals migration correctly resolves duplicate initialization.

The migration to input() signals with effect-based initialization is correct. The constructor effect (lines 32-39) reactively handles schema updates and replaces the previous ngOnInit logic, resolving the duplicate initialization issue flagged in the earlier review.


46-46: Null handling correctly fixed.

The nullish coalescing operator (?? {}) ensures formData is always an object, resolving the previous null handling concern.


51-51: Simplified signature is correct.

Removing the unused event and item parameters is appropriate since the method only emits this.formData.

packages/altair-app/src/testing/utils.ts (10)

7-8: LGTM!

The new imports (Signal and inject) are appropriately added to support the signals migration and modern Angular dependency injection patterns used throughout the file.


125-126: LGTM!

The exported type definitions provide excellent type safety for signal inputs:

  • ComponentMeta exposes the component metadata structure
  • FilteredSignalKeys<T> correctly identifies signal properties using conditional types
  • AllowedPropsDataKeys<T> properly combines non-function and signal keys
  • AllowedPropsDataValue<T, K> correctly extracts the inner type from signals using infer U

These types enable consumers to work with signal inputs in a type-safe manner.

Also applies to: 139-146


74-95: LGTM!

The getComponentMeta function correctly implements signal detection:

  • Documentation comments clearly explain each array's purpose
  • Signal inputs are properly detected using member.isSignal
  • Normal and signal inputs are tracked separately
  • Return type includes both normalInputs and signalInputs for downstream processing

This maintains backward compatibility while enabling signal-aware testing.

Also applies to: 100-105, 117-122


129-129: LGTM!

Changing props from IDictionary to ComponentMeta improves type safety and provides better IntelliSense for consumers of this base class.


150-150: LGTM!

The refined propsData typing using AllowedPropsDataKeys and AllowedPropsDataValue ensures that:

  • Only valid input properties (including signals) can be set
  • Signal inputs receive the correct inner type (extracted via Signal<infer U>)
  • Compile-time type safety prevents invalid prop assignments

155-156: LGTM!

Explicit typing of propsData and props improves code clarity and ensures type safety throughout the mount function.


174-174: LGTM!

The migration from constructor injection to inject(ViewContainerRef) follows modern Angular patterns and aligns with the broader signals migration. This approach is more concise and pairs well with signal-based components.


181-209: LGTM!

The constructor correctly handles both normal and signal inputs:

  • Combines normalInputs and signalInputs for unified processing
  • For signal inputs, correctly calls them as functions to read values (line 194)
  • For normal inputs, accesses them directly as properties (line 196)
  • Default values are properly retrieved from a temporary component instance
  • Conditional logic ensures only defined values are included in the inputs object

This implementation correctly aligns with Angular's signal API where signals must be called to retrieve their values.


244-250: LGTM!

The refactored buildTestHostComponentTemplate function:

  • Accepts a single ComponentMeta parameter for cleaner signature
  • Combines both normalInputs and signalInputs for template generation
  • Correctly uses property binding syntax [input]="inputs.input" which Angular handles uniformly for both normal and signal inputs

This simplification maintains correctness while improving maintainability.


285-285: LGTM!

ESLint comment formatting updated to align with current linting configuration.

packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)

45-50: Effect implementation correctly handles all input changes.

The effect now calls updateLocalState unconditionally, which addresses the previous concern about stale UI when fileVariable becomes empty or undefined. This ensures the component state stays synchronized with the signal input.

packages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts (2)

1-9: LGTM! Imports updated correctly for signals migration.

The imports have been appropriately updated to include the signal primitives (input, inject, effect, signal) and remove the deprecated lifecycle/decorator imports (Input, OnChanges, SimpleChanges).


20-24: LGTM! Class signature and DI modernized correctly.

The removal of OnChanges and migration to inject() plus signal-based inputs (input()) align with Angular's modern signals API. The default values for inputs are appropriate.

packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts (5)

1-1: LGTM! Signal APIs imported correctly.

The imports include all necessary Angular signal APIs (input, effect, inject, untracked) for the migration from lifecycle hooks to reactive signals.


14-17: LGTM! Signal inputs properly declared.

The migration from @Input properties to readonly signal inputs is correct:

  • All inputs have appropriate default values
  • Type annotations are preserved
  • readonly modifier prevents accidental reassignment

12-12: LGTM! Dependency injection modernized correctly.

The migration from constructor parameter injection to the inject() function follows current Angular best practices for signal-based directives.


22-35: LGTM! Effect pattern correctly addresses previous review concerns.

The split-effects pattern properly separates concerns:

  • Effect 1 (lines 23-30): Recreates emotion instance only when cspNonce() changes, using untracked() to prevent theme inputs from triggering instance recreation
  • Effect 2 (lines 31-34): Re-applies theme when theme/color inputs change

This implementation resolves both previous review comments about unnecessary emotion instance recreation and stale nonce caching.


77-83: LGTM! Helper method encapsulates instance creation cleanly.

The createEmotionInstance helper properly encapsulates the Emotion instance creation logic:

  • Accepts cspNonce as a parameter for explicit control
  • Sets this.emotionInstance before returning
  • Uses correct Emotion configuration with the provided nonce
packages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts (1)

115-121: Signal value emitted correctly.

Good call invoking selectedEnvironmentId() before emittingβ€”it ensures subscribers receive the actual string rather than the signal wrapper.

@imolorhe imolorhe added this pull request to the merge queue Oct 11, 2025
@imolorhe imolorhe removed this pull request from the merge queue due to a manual request Oct 11, 2025
@imolorhe imolorhe enabled auto-merge October 11, 2025 22:11
@imolorhe imolorhe added this pull request to the merge queue Oct 11, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

74-83: Race condition in async effect.

The effect fetches team members asynchronously without handling rapid changes to selectedTeamId. If the user switches teams quickly, multiple requests could be in flight, and stale responses might overwrite newer data.

Consider using RxJS operators to handle cancellation:

constructor() {
  toObservable(this.selectedTeamId)
    .pipe(
      switchMap(selectedTeamId => {
        if (!selectedTeamId) {
          return of([]);
        }
        return from(this.accountService.getTeamMembers(selectedTeamId));
      }),
      takeUntilDestroyed()
    )
    .subscribe(members => this.membersOfSelectedTeam.set(members || []));

Alternatively, implement request cancellation or track a request ID to ignore stale responses.

Based on past review comments.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts (1)

29-33: Same question: clarify the commented-out effect.

This component has the same commented-out effect pattern as schema-form-item.component.ts. The effect would auto-emit dataChange when data() updates, but since the parent components and template explicitly handle emissions, this might be redundant.

Consider documenting the reasoning or removing the commented code entirely for maintainability.

Applies the same guidance as in schema-form-item.component.ts.

🧹 Nitpick comments (1)
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (1)

44-54: Make the undefined return explicit.

Line 51 uses return; without a value, which implicitly returns undefined. For clarity and consistency with line 48's explicit return undefined;, make this explicit.

Apply this diff:

     if (!selectedTeamId) {
-      return;
+      return undefined;
     }
πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between bed7dfe and e8c26bd.

πŸ“’ Files selected for processing (6)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.html (1 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.ts (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html (2 hunks)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts (3 hunks)
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.ts
🧰 Additional context used
πŸ““ Path-based instructions (7)
packages/altair-app/src/app/modules/altair/components/**/*.component.{ts,html,scss,spec.ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Use kebab-case for all component-related filenames (e.g., query-editor.component.ts/html/scss/spec.ts)

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.html

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.html: Use ng-zorro Ant Design components for UI in templates
Include proper ARIA attributes in templates for accessibility
Use semantic HTML elements in templates

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
packages/altair-app/src/app/modules/altair/components/**/*.component.{html,ts}

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

Ensure keyboard navigation works (focus management and keyboard handlers)

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
packages/altair-app/**/*.{ts,html}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Implement and modify the main web app using Angular conventions within packages/altair-app

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
**/*.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/app-testing.instructions.md)

Follow project code style using ESLint and Prettier

**/*.ts: Use explicit type annotations for function parameters and return types
Prefer interfaces over type aliases for object shapes
Use union types and literal types for better type safety
Leverage generic types for reusable components
Group imports: external libraries first, then internal modules
Use absolute imports from package roots when possible
Prefer named exports over default exports
Use custom error classes that extend Error
Implement proper error boundaries and handling
Log errors with sufficient context for debugging
Use observables (RxJS) for reactive programming patterns where appropriate
Manage subscriptions to avoid memory leaks
Use appropriate RxJS operators for data transformation
Handle errors in observable streams
Use async/await for sequential operations
Handle promise rejections properly
Use Promise.all() for concurrent operations
Implement timeout handling for long-running operations
Dispose of resources properly (subscriptions, event listeners)
Use weak references where appropriate
Avoid creating unnecessary objects in hot paths
Profile memory usage for performance-critical code
Use tree-shaking-friendly imports
Lazy load heavy modules when possible
Monitor bundle size impacts of new dependencies
Use dynamic imports for code splitting
Validate and sanitize all user inputs
Implement proper XSS and injection prevention
Validate API responses before processing
Sanitize sensitive data in logs
Follow secure coding practices
Group related functionality in modules
Keep files focused and not too large
Use consistent naming conventions
Organize imports and exports clearly
Write JSDoc comments for public APIs
Keep documentation up to date with code changes (inline docs)
Use meaningful variable and function names
Handle environment-specific APIs properly
Use TypeScript features appropriate for the configured version

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
packages/altair-app/src/app/modules/altair/components/**/*.component.ts

πŸ“„ CodeRabbit inference engine (.github/instructions/angular-components.instructions.md)

packages/altair-app/src/app/modules/altair/components/**/*.component.ts: Place Angular component classes under packages/altair-app/src/app/modules/altair/components/
Prefer ChangeDetectionStrategy.OnPush for components when possible
Implement appropriate Angular lifecycle hooks (e.g., OnInit, OnDestroy)
Use Angular dependency injection for services and dependencies
Favor reactive programming with RxJS Observables for component state
Manage subscriptions and clean them up in ngOnDestroy
Emit component events using EventEmitter and expose a clear component API
Use @input and @output decorators to define the component API
Use Angular reactive forms for complex forms
Implement proper form validation and error handling
Provide trackBy functions for ngFor loops to improve performance
Avoid memory leaks by unsubscribing from Observables

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
**/*.{ts,tsx}

πŸ“„ CodeRabbit inference engine (.github/instructions/main.instructions.md)

Use TypeScript for implementation across the codebase

Files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
  • packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts
🧠 Learnings (3)
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Input and Output decorators to define the component API

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Use Angular reactive forms for complex forms

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts
πŸ“š Learning: 2025-10-03T16:35:29.117Z
Learnt from: CR
PR: altair-graphql/altair#0
File: .github/instructions/angular-components.instructions.md:0-0
Timestamp: 2025-10-03T16:35:29.117Z
Learning: Applies to packages/altair-app/src/app/modules/altair/components/**/*.component.ts : Emit component events using EventEmitter and expose a clear component API

Applied to files:

  • packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts
🧬 Code graph analysis (3)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts (2)
packages/altair-core/src/config/index.ts (1)
  • AltairConfig (24-221)
packages/altair-app/src/app/modules/altair/utils/settings_addons.ts (1)
  • SchemaFormProperty (5-9)
packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts (1)
packages/altair-app/src/app/modules/altair/utils/settings_addons.ts (2)
  • SchemaFormProperty (5-9)
  • getSchemaFormProperty (19-34)
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (4)
packages/altair-core/src/types/state/state.interfaces.ts (1)
  • RootState (12-23)
packages/altair-core/src/types/state/account.interfaces.ts (1)
  • Team (2-6)
packages/altair-api-utils/src/client.ts (1)
  • ReturnedTeamMembership (36-38)
packages/altair-api-utils/src/team.ts (1)
  • ICreateTeamDto (3-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: sites / Deploy Login Redirect / Deploy Login Redirect
  • GitHub Check: sites / Deploy Web App / Deploy Web App
  • GitHub Check: sites / Deploy Sandbox / Deploy Iframe Sandbox
  • GitHub Check: sites / Deploy Docs / Deploy Documentation
  • GitHub Check: tauri / tauri (macos-latest, --target x86_64-apple-darwin)
  • GitHub Check: tauri / tauri (windows-latest)
  • GitHub Check: tauri / tauri (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: tauri / tauri (ubuntu-22.04)
  • GitHub Check: electron / electron (macos-latest)
  • GitHub Check: electron / electron (windows-latest)
  • GitHub Check: docker / docker
  • GitHub Check: electron / electron (ubuntu-latest)
  • GitHub Check: tests / api-e2e-test
  • GitHub Check: tests / test (ubuntu-latest)
  • GitHub Check: tests / e2e-test (ubuntu-latest)
  • GitHub Check: tests / test (macos-latest)
  • GitHub Check: tests / e2e-test (macos-latest)
  • GitHub Check: build_and_preview
πŸ”‡ Additional comments (14)
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.ts (5)

2-11: LGTM! Correct imports for signals migration.

The imports properly include all necessary Angular signal APIs (input, signal, computed, effect, inject) required for the migration from @Input/constructor DI to the signals pattern.


28-34: LGTM! Proper DI and input migration.

The migration from constructor-based DI to inline inject() calls and from @Input() decorators to input() signals follows Angular best practices for the signals API.


85-93: LGTM! Proper form synchronization.

The effect correctly synchronizes the team form values when editTeamId changes, handling the case where the team is found in the teams array.


109-109: LGTM! Type inconsistency resolved.

The method now correctly uses this.editTeamId.set(undefined) instead of an empty string, resolving the type inconsistency flagged in the previous review. This is consistent with the signal type signal<string | undefined> and with other code using undefined.

Based on past review comments.


103-211: LGTM! Correct signal usage throughout methods.

All methods correctly use signal getters (calling with ()) to read values and signal setters (.set()) to update values. The migration maintains the original logic while adapting to the signals pattern.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html (3)

1-1: LGTM! Signal guard pattern correctly implemented.

The @if (item(); as item) guard correctly calls the signal as a function and assigns the result to a local variable for use in the template block.


8-11: LGTM! Signal bindings correctly implemented.

The template now uses the correct pattern for signal-based two-way binding:

  • [ngModel]="data()" reads the current signal value
  • (ngModelChange)="dataChange.emit($event)" explicitly emits changes through the output

This avoids the previous critical issue of attempting to assign directly to the signal with [(ngModel)]="data".

Also applies to: 18-21, 49-50


25-30: LGTM! Type guards and data binding for nested components.

The type guards correctly call data() to read the signal value, and the converter functions (asStringOrUndefined, asArrayOrUndefined) properly narrow types for passing to child components. The explicit (dataChange) bindings maintain the event flow.

Also applies to: 34-39

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.ts (3)

6-9: LGTM! Signal-based inputs and inject() migration.

The component correctly migrates to Angular's modern patterns:

  • input<SchemaFormProperty>() and model<unknown>() replace @Input() decorators
  • inject(AltairConfig) replaces constructor-based DI

These changes align with the broader signals migration across the codebase.

Also applies to: 22-25


29-33: Clarify the commented-out effect.

The constructor contains a commented-out effect() that would emit dataChange whenever data() updates. Since the template now explicitly emits via (ngModelChange)="dataChange.emit($event)", this effect might be redundant.

However, consider:

  • If the effect is intentionally disabled to avoid double-emitting, document why with a comment
  • If it's a work-in-progress, add a TODO or FIXME
  • If it's no longer needed, remove it entirely

Which approach is correct for this migration?


85-90: LGTM! Type converter helper for template usage.

The asStringOrUndefined method complements the isStringOrUndefined type guard. While the guard is used for conditional checks in the template, the converter provides the correctly typed value for passing to child components.

packages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.ts (3)

24-25: LGTM! Consistent signal-based inputs.

The component correctly adopts input<SchemaFormProperty>() and model<unknown[]>() for its public API, aligning with the signals migration pattern used throughout the PR.


36-42: LGTM! Array mutation pattern correctly implemented for signals.

The methods correctly follow the signal update pattern:

  1. Read current value via this.data()
  2. Mutate the array in place
  3. Call this.data.set(data) to trigger change detection

Angular signals will properly detect the change even though the array reference is reused, because set() is explicitly called. This is the standard pattern for updating array signals.

Also applies to: 46-50, 57-63


54-55: LGTM! Signal function call in key generation.

The method correctly calls this.item() as a function to read the current signal value when generating the schema form property key.

Merged via the queue into master with commit 0c228e8 Oct 11, 2025
25 checks passed
@imolorhe imolorhe deleted the imolorhe/signals-migration branch October 11, 2025 22:28
This was referenced Oct 12, 2025
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.

1 participant