-
-
Notifications
You must be signed in to change notification settings - Fork 372
signals migration #2905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
signals migration #2905
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughMigrates 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
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
Estimated code review effortπ― 5 (Critical) | β±οΈ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touchesβ Passed checks (3 passed)
β¨ Finishing touches
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @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 Highlights
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.
Using Gemini Code AssistThe 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
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 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
|
|
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 |
There was a problem hiding this 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:
- 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. - Lifecycle Hook Usage: A number of components use
ngOnInitorngOnChangesto react to changes in input values. With signal-based inputs, it is more idiomatic and robust to useeffect()orcomputed()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.
...dules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.ts
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-apikey/authorization-apikey.component.ts
Show resolved
Hide resolved
...modules/altair/components/authorization/authorization-basic/authorization-basic.component.ts
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-bearer/authorization-bearer.component.ts
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-editor/authorization-editor.component.ts
Show resolved
Hide resolved
...p/src/app/modules/altair/components/query-collection-item/query-collection-item.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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 triggerngOnChanges.The component still implements
OnChangesand relies onngOnChangesto detect changes to theschemainput. With signal-based inputs, thengOnChangeslifecycle 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
ngOnChangeswith Angular'seffect()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
showEnvironmentManagerto a signal-based input usinginput()is correctly implemented. However, the component now has mixed input patterns:
- Line 35:
showEnvironmentManagerusesinput()(signal-based)- Line 34:
environmentsstill uses@Input()(decorator-based)For consistency and maintainability, consider migrating the remaining
@Input()decorator toinput()as well.Note: This signals migration represents an intentional architectural shift in the PR. While previous learnings indicated using
@Inputdecorators, 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
showEnvironmentManagerproperty has been migrated to a signal input, but theenvironmentsproperty on line 34 still uses the@Inputdecorator. This creates an inconsistency within the same component.For a more uniform API and to fully benefit from the signal migration, consider migrating
environmentsas well:-@Input() environments?: EnvironmentsState; +readonly environments = input<EnvironmentsState>();If migrated, you'd also need to update all internal references from
this.environmentstothis.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
readonlyand 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 guidelinesAll components (e.g., doc-viewer-search-results) still use
@Output()/EventEmitter and nooutput()signals were detected. For consistency, either replace these withreadonly 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. Useas 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().contentcorrectly retrieves the signal's value. The logic properly hydrates the resolved value using the environment service.Optional enhancement: While
ngOnChangesworks 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
OnChangeslifecycle hook.packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.ts (1)
26-34: Template binding is correctβno directsizeusage
- The template applies
[ngStyle]="styles"computed inngOnInit; it doesnβt referencesizeorsize(), so no changes needed.- Optional: replace the
ngOnInitstyle assignment with acomputed()signal forstylesto 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, butcollectionsandworkspaces(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 theBehaviorSubjects: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 migratecollectionTreeinput for consistencyThe
collectionTreeproperty remains a classic@Input(), whileloggedIn,queriesSortBy, andexpandedhave been migrated to signals. Either migratecollectionTreeto a signal input (e.g.readonly collectionTree = input<IQueryCollectionTree|undefined>(undefined);and update usages tothis.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 usingeffect()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
ngOnChangesto react to input changes. With signal-based inputs, using Angular'seffect()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:
ngOnChangesstill 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: MigraterequestScriptLogstoinput(...)
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.tsline 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 selectionThis
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
OnInitimport.- 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(), andplanInfos().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.
ConvertapiUrl,selectedOperation, andstreamStateto usereadonly β¦ = 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 clearEventEmitters 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: Preferemit()overnext()for EventEmitter; type outputsFor 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 aneffectto react tocollectionssignal changes
While signal-based inputs still firengOnChanges, aneffectensuressetTreeNodes()runs whenevercollections()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.
...ages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.ts
Outdated
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-apikey/authorization-apikey.component.ts
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-editor/authorization-editor.component.ts
Outdated
Show resolved
Hide resolved
...dules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.ts
Show resolved
Hide resolved
...src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/query-result/query-result.component.ts
Outdated
Show resolved
Hide resolved
...p/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
Show resolved
Hide resolved
...es/altair-app/src/app/modules/altair/components/settings-dialog/settings-dialog.component.ts
Show resolved
Hide resolved
...air-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.ts
Show resolved
Hide resolved
There was a problem hiding this 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
activeEnvironmentis now a signal; comparing the signal function itself toundefinedalways 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.selectedEnvironmentIddirectly, 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.showVariableDialogis now anInputSignal<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 triggerngOnChanges. The logic that reconfigures extensions (line 117) and redraws the layout (line 125) will never execute becausechanges.extensionsandchanges.redrawLayoutwill 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
OnChangesandSimpleChangesimports: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, OnDestroypackages/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.showDialogdirectly 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
newCollectionParentCollectionIdis now a writable signal. Leaving[(ngModel)]="newCollectionParentCollectionId"expands tothis.newCollectionParentCollectionId = $event, so the first change will overwrite the signal with a string/null and the later callnewCollectionParentCollectionId()(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
OnChangesand checkschanges?.schema?.currentValue, but signal-based inputs created withinput()don't trigger Angular's change detection lifecycle hooks likeOnChanges. This code path will never execute.Replace
OnChangeswith 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.
hasSearchIndexis now a signal and should be accessed viahasSearchIndex()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: UnifycollectionIdto 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 usestringand 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 acomputed(() => β¦)so it readstabSize()lazily.packages/altair-app/src/app/modules/altair/components/query-editor/query-editor.component.ts (1)
164-227: ReplacengOnChangeslogic with signal effectsAll the properties referenced here are now
input()signals. Angular does not invokengOnChangesfor 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 intoeffect(() => β¦)blocks (or convert the inputs back to@Input) so they run whenever the corresponding signal changes, and drop theSimpleChangesplumbing altogether. ThebetaDisableNewEditorbranch 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
@Inputproperties have been successfully migrated to signal-basedinput()functions with appropriate defaults and types.Note: The past review comment about an unmigrated
@Inputdecorator 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
expandedinput was migrated to a signal at line 29, butngOnChangesat lines 53-57 attempts to react to changes inexpanded. Signal-based inputs created withinput()do not trigger theOnChangeslifecycle hook, so the logic updatingshowContentwill never execute whenexpandedchanges externally.This issue was previously flagged. Apply the suggested fix from the earlier review: replace
ngOnChangeswith aneffect()that watches theexpandedsignal and updatesshowContentaccordingly.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
Inputdecorator is no longer used after migrating to the signal-basedinput()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); - // });
...s/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts
Outdated
Show resolved
Hide resolved
...s/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts
Outdated
Show resolved
Hide resolved
...ltair-app/src/app/modules/altair/components/query-collections/query-collections.component.ts
Outdated
Show resolved
Hide resolved
...c/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.html
Outdated
Show resolved
Hide resolved
...app/src/app/modules/altair/components/window-switcher-item/window-switcher-item.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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: callselectedEnvironmentId()before emitting
linkedSignalreturns a callable signal, so emittingthis.selectedEnvironmentIdpasses the function itself instead of the selected id string. This breaks every consumer ofsubEnvironmentJsonChange,subEnvironmentTitleChange, anddeleteSubEnvironmentChange(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: InvokewindowIdsignal in test
Inwindow.component.spec.tsat 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: GuardwindowIds()against nullish values before mutating.
input<string[]>([])still deliversnull/undefinedwhen the async-bound parent emits those, sothis.windowIds()can be null during initial renders. Spreading, reading.length, or chaining.filteron a null value will throw and break drag/drop and context-menu flows. Please coerce to an array (or bail early) before callingmoveItemInArray,.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 whenwindowIdchanges.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 newwindowIdvalue 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
windowIdsignal (e.g. use the existingwindowState$derived fromthis.windowId$, orcombineLatestwiththis.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 instantiatingStorageServicewithnew.
StorageServicenow relies on Angular'sinject(); callingnew 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.
editorExtensionsis constructed in a class field, sothis.tabSize()is read before Angular delivers input updates and never re-evaluates. After the migration, any runtimetabSizechanges silently stop updating the editor configuration. Move this setup into acomputed(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
computedfrom@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 trackcspNonce()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()toinput()signals breaks thengOnChangeslifecycle hook. Signal-based inputs don't populate theSimpleChangesobject, sochanges.queryId?.currentValue(line 23) will always be undefined, preventing revisions from being fetched whenqueryIdchanges.This issue was already flagged in the previous review but remains unaddressed.
Replace the
OnChangesapproach with aneffect()that watches thequeryIdsignal: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: Useeffect()instead ofngOnInitto react to signal input changes.With signal-based inputs,
ngOnInitonly executes once during component initialization. IfauthDatachanges after initialization, the form will not be updated, leading to stale data.As noted in the previous review, replace
ngOnInitwith aneffect()in the constructor to ensure the form updates whenever theauthDatasignal 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 forauthDatabeforepatchValue.
authDatais typed asunknown, butFormGroup.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:ngOnChangesdoes not work with signal inputs.Signal inputs declared with
input()do not participate inngOnChangesor provideSimpleChangeswhen updated. The current implementation will not respond to input changes as expected.Additionally, the
betaDisableNewEditorblock (lines 214-226) references a non-existent input and should be removed.Recommended fix:
Remove the
ngOnChangeshook entirely and replace with targetedeffect()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?.viewwill 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
selectedTeamIdchanges rapidly. The previous review comment suggestingswitchMapor request cancellation is still valid.
108-111: The type inconsistency flagged in the previous review is still present.Line 109 still sets
editTeamIdto an empty string instead ofundefined, which is inconsistent with the signal's type and with line 167 whereeditUserId.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 callinggetWindowCollection.This repeats the regression flagged earlier:
collections$ | asyncfeedsnullinitially, sothis.collections()can be nullish andgetWindowCollectionwill blow up when it forwards that togetCollection(...). 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, thethis.docView()existence check is unnecessary sincedocViewis 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.
OnChangesandSimpleChangesare no longer needed since signal inputs don't triggerngOnChanges. 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: RemoveOnChangesinterface implementation.The
OnChangesinterface 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
expandedinput was migrated to a signal, but the component still implementsOnChangesand has anngOnChangesmethod that attempts to react to changes inexpanded. Signal-based inputs created withinput()do not trigger theOnChangeslifecycle hook, so the logic updatingshowContentwill never execute whenexpandedchanges externally.Replace
ngOnChangeswith aneffect()to react to theexpandedsignal: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 toauthData.With the new signal-based
authData, patching the form only inngOnInitmeans later input changes are ignored, so the form shows stale credentials. Wire the signal into aneffect(and bring in theeffectimport) so everyauthData()change refreshes the form, then drop the now-unusedngOnInitlogic.-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 signalYou still patch
typeFormonly inngOnInit, so later updates toauthorizationState()never reach the form. With signal inputs we need aneffectthat 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 inngOnInit, so later input updates never update the form. Hook aneffectto 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 triggerngOnChanges.With
input()signals, Angular never callsngOnChanges, soupdateLocalSettings()is never invoked when thesettingsinput updates. The dialog therefore shows stale data and fails to react to parent changes. Please remove theOnChangesimplementation and replace it with aneffect()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
debouncefunction's effect doesn't register a cleanup callback, which means:
- If the component is destroyed while a timeout is pending, the timeout won't be cleared, causing a memory leak
- 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.OnPushcan 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-standalonerule 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 itinject(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. TheresetEffect(lines 56-60) then updates it when the input changes. While this works correctly, initializing directly tosignal('')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 havestorageType: 'local'(rather than relying onundefined) or update the filter to only check for'local'. Confirm this aligns with howstorageTypeis assigned inquery-collection.service.
...ages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
Show resolved
Hide resolved
...air-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
Outdated
Show resolved
Hide resolved
.../altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/containers/window/window.component.spec.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.ts
Show resolved
Hide resolved
...ltair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.ts
Show resolved
Hide resolved
There was a problem hiding this 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: FixdocHistorysignal usage.
docHistorywas migrated to a signal (readonly docHistory = this.state.docHistory;), so in the template you must read it viadocHistory(). AccessingdocHistory.lengthwill throw at runtime because the signal function has nolengthproperty.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.or add role="button" tabindex="0" and handle Enter/Space.
- without href is not focusable and breaks keyboard nav.
- Either switch to
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 literalname="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
π 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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.htmlpackages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/dialog/dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/url-box/url-box.component.htmlpackages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.htmlpackages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.htmlpackages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.htmlpackages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.htmlpackages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.htmlpackages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.htmlpackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.htmlpackages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.htmlpackages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/tips/tips.component.htmlpackages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-result/query-result.component.htmlpackages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.htmlpackages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.htmlpackages/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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.htmlpackages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/dialog/dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/url-box/url-box.component.htmlpackages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.htmlpackages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.htmlpackages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.htmlpackages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.htmlpackages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.htmlpackages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.htmlpackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.htmlpackages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.htmlpackages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/tips/tips.component.htmlpackages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-result/query-result.component.htmlpackages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.htmlpackages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.htmlpackages/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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.htmlpackages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/dialog/dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/url-box/url-box.component.htmlpackages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.htmlpackages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.htmlpackages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.htmlpackages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.htmlpackages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.htmlpackages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.htmlpackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.htmlpackages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.htmlpackages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/tips/tips.component.htmlpackages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-result/query-result.component.htmlpackages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.htmlpackages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.htmlpackages/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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.htmlpackages/altair-app/src/app/modules/altair/components/import-curl-dialog/import-curl-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/dialog/dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.htmlpackages/altair-app/src/app/modules/altair/modules/icons/icon/icon.component.htmlpackages/altair-app/src/app/modules/altair/components/request-handler-dialog/request-handler-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/set-variable-dialog/set-variable-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/url-box/url-box.component.htmlpackages/altair-app/src/app/modules/altair/containers/altair/altair.component.htmlpackages/altair-app/src/app/modules/altair/components/query-collection-item/query-collection-item.component.htmlpackages/altair-app/src/app/modules/altair/components/authorization/authorization-oauth2/authorization-oauth2.component.htmlpackages/altair-app/src/app/modules/altair/components/teams-dialog/teams-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/window-switcher/window-switcher.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.htmlpackages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.htmlpackages/altair-app/src/app/modules/altair/components/add-collection-query-dialog/add-collection-query-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.htmlpackages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.htmlpackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form/schema-form.component.htmlpackages/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.htmlpackages/altair-app/src/app/modules/altair/components/variables-editor/variables-editor.component.htmlpackages/altair-app/src/app/modules/altair/components/request-extensions-dialog/request-extensions-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/tips/tips.component.htmlpackages/altair-app/src/app/modules/altair/components/edit-collection-dialog/edit-collection-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/query-result/query-result.component.htmlpackages/altair-app/src/app/modules/altair/components/account-dialog/account-dialog.component.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.htmlpackages/altair-app/src/app/modules/altair/components/pre-request-editor/pre-request-editor.component.htmlpackages/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.htmlpackages/altair-app/src/app/modules/altair/containers/altair/altair.component.htmlpackages/altair-app/src/app/modules/altair/components/banner-container/banner-container.component.htmlpackages/altair-app/src/app/modules/altair/components/tips/tips.component.htmlpackages/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.htmlpackages/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.htmlpackages/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
...ages/altair-app/src/app/modules/altair/components/confirm-toast/confirm-toast.component.html
Outdated
Show resolved
Hide resolved
.../src/app/modules/altair/components/doc-viewer/doc-viewer-type/doc-viewer-type.component.html
Show resolved
Hide resolved
...app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
Outdated
Show resolved
Hide resolved
...les/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.html
Show resolved
Hide resolved
...c/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.html
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/url-box/url-box.component.html
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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
β Files ignored due to path filters (9)
packages/altair-app/src/app/modules/altair/components/account-dialog/__snapshots__/account-dialog.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/action-bar/__snapshots__/action-bar.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/dialog/__snapshots__/dialog.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/edit-collection-dialog/__snapshots__/edit-collection-dialog.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/history-dialog/__snapshots__/history-dialog.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/import-curl-dialog/__snapshots__/import-curl-dialog.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/url-box/__snapshots__/url-box.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/app/modules/altair/components/variable-file-item/__snapshots__/variable-file-item.component.spec.ts.snapis excluded by!**/*.snappackages/altair-app/src/testing/__tests__/__snapshots__/utils.spec.ts.snapis 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.htmlpackages/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@ifblocks means we only render the βno environmentβ state whenactiveEnvironment()is strictlyundefined. If the signal ever yieldsnull(or any other falsy-but-not-undefinedplaceholder), the menu item becomes blank. Please confirm the signal never resolves tonull, or fold the logic into a single@if β¦ @elsewith an alias (e.g.@if (activeEnvironment() as env) { β¦ } @else { β¦ }) so every nullish case still shows the fallback.
packages/altair-app/src/app/modules/altair/effects/query.effect.spec.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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-baseddataproperty.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-baseddataproperty.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-baseddataproperty.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) andElementRef(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.OnPushfor optimal performance. This aligns with the coding guidelines and matches the pattern used in related components likeAddCollectionQueryDialogComponentandQueryCollectionItemComponent.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
searchTermsignal is derived fromsearchInputvia thedebounceutility and should be markedreadonlyto 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
propsDatavariable is typed asRecord<string, unknown>, which is less strict thanmountOptions.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
MockElementRefclass is unnecessary since it doesn't add any functionality. You can provideElementRefdirectly 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 useTestBed.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
π 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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/altair-app/src/app/modules/altair/components/query-collections/query-collections.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.spec.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.tspackages/altair-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/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.tspackages/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.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-input/schema-form-item-input.component.spec.tspackages/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
@Inputdecorators to Angular Signals usinginput()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
Signalandinjectimports appropriately supports the signals-based testing infrastructure updates.
71-123: Well-structured signal detection and input separation.The refactored
getComponentMetafunction correctly:
- Separates normal
@Inputproperties from signal inputs usingmember.isSignal- Provides clear JSDoc documentation for each input category
- Maintains backward compatibility with
availableInputstrackingThe 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
propsDataThis 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
BaseTestHostComponentandTestMountOptionscorrectly incorporateComponentMetaand 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
buildTestHostComponentTemplatecorrectly:
- Accepts
ComponentMetawith separated input categories- Combines
normalInputsandsignalInputsfor template generation (line 248)- Uses property binding syntax
[input]="inputs.input"which works uniformly for both signal and normal inputsThe 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'
MockServiceutility (imported on line 15) provides better type safety and Angular-aware service mocking compared to the custommock()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.
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
Show resolved
Hide resolved
...-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
Outdated
Show resolved
Hide resolved
...-app/src/app/modules/altair/directives/set-css-variables/set-css-variables.directive.spec.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
Outdated
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.spec.ts
Show resolved
Hide resolved
There was a problem hiding this 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
selectedEnvironmentIdsignal 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) toexportCollection({ 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 normalizesundefinedids to'', yetngClasscompares against the rawitem.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 forngModel.
[(ngModel)]="data"assigns to the signal variable, replacing theModelSignalinstance and breaking subsequent updates. Read viadata()and write viadata.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.0requireseslint@^9(and@typescript-eslint@^8). We only bumped the TypeScriptβESLint packages; keepingeslintat ^8.57.0 causes pnpm/yarn to throw peer dependency errors and breaks linting/installs. Please upgradeeslint(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/testingand 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 ElementRefpackages/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:
Race condition (previously flagged): Multiple concurrent requests can lead to stale data if
selectedTeamIdchanges rapidly. The async effect doesn't cancel previous requests.Missing error handling: The
getTeamMemberscall 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 callinggetSettingKey(), which readsthis.featureKey(). However, signal inputs are set after construction, sofeatureKey()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 tongOnInitor 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-basedinput().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
showVariableDialogas 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 callingset().
this.docHistory()returns the live array reference; popping it mutates the signal value beforeset(). Because the reference is unchanged, Angular skips notifying dependents, and history/navigation glitches. Copy the array first, and onlyset()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 theas []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 withArray.isArrayinstead (and reuse the already derivedfileVariable.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
collectionremains 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 unusedOnInitimport.The
OnInitinterface is imported but never implemented byQueryResultComponent(line 38 implements onlyAfterViewInit).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
teamsinput doesn't have a default value, which means it could beundefined. 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-basedinput()is implemented correctly:
- Default values preserved (
showDialog,planInfos)- Types properly specified with
input<IPlan>()andinput<IPlanInfo[]>([])readonlymodifiers correctly appliedproPlanInfocomputed signal appropriately replaces the logic previously inngOnChangesOptional: Minor type annotation cleanup.
Line 27: The explicit type annotation
(planInfo: IPlanInfo)is redundant since TypeScript infers it fromIPlanInfo[]. 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 sinceplanInfoshas 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
queryIdchanges rapidly, multiple API requests could be in flight simultaneously. The last-resolved request (not necessarily from the most recentqueryId) could overwriterevisions, causing stale data to appear.Consider one of these approaches:
Option 1: Use RxJS with
switchMapto 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 usingcomputed()for reactive sorting.While the current
@memoize()decorator works, thesortedCollectionQueriesmethod could be converted to acomputed()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?: stringparameter is optional, but thecspNoncesignal is defined asinput<string>('')with a default empty string, meaning it will never returnundefined. 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: ReconsiderdestroyAfterEach: falseto prevent test pollution.Setting
destroyAfterEachtofalseprevents 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
convertToNamedQuerycorrectly verifies that the effect dispatchesSetQueryActionwhen processingConvertToNamedQueryAction. This addresses the concern raised in the previous review about missing behavioral coverage.However, consider adding test cases for error scenarios (e.g., when
nameQuerythrows 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, andngAfterViewInit:
- 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 ifgqlSchemaexistsngAfterViewInit(lines 209-217) unconditionally re-initializes all these propertiesSince all update methods have guards checking
editor?.viewand 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 whengqlSchemais absentβproperties liketabSizeanddisableLineNumbersshould 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β
hasViewis now updated immediately after state changes (lines 35, 49). However, line 41 setshasView.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
schemainput defaults to{}(empty object) anddatadefaults tonull. While these may be valid defaults, consider:
- Explicitly typing the default for
schemaasJSONSchema6(e.g.,{ type: 'object', properties: {} }) if an empty object doesn't satisfy the schema structure.- Using
undefinedinstead ofnullfordataif 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
nullvs.undefinedhas 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
setupTipIntervalreturn type (e.g.,: void) so we adhere to the project rule requiring explicit return annotations for functions and methods. As per coding guidelinespackages/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: anydefeats 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
handleRenderinngAfterViewInitensures the element is appended after the view is ready, regardless of when signals are first set. This complements theeffectwhich handles subsequent updates.Minor note: The
effectin the constructor also attempts to callhandleRender, but theelRefcheck ensures it's harmless. If you prefer to eliminate the redundant initial call, you could useafterNextRender()instead ofngAfterViewInit, 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
setTimeoutin 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(); }
...ages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.ts
Outdated
Show resolved
Hide resolved
...s/altair-app/src/app/modules/altair/components/doc-viewer/doc-viewer/doc-viewer.component.ts
Show resolved
Hide resolved
...app/src/app/modules/altair/components/environment-manager/environment-manager.component.html
Show resolved
Hide resolved
...r-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
Show resolved
Hide resolved
...r-app/src/app/modules/altair/components/environment-manager/environment-manager.component.ts
Outdated
Show resolved
Hide resolved
...air-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/components/x-input/x-input.component.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/cached-if.directive.spec.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
Show resolved
Hide resolved
There was a problem hiding this 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
fileVariableas a parameter but inconsistently accesses data from both the parameter (lines 89, 97) and the signalthis.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 callinggetSettingKey(), which readsthis.featureKey(). Signal inputs are set after construction, sofeatureKey()returns an uninitialized value, resulting in an incorrect selector key (e.g.,'beta.disable.'instead of'beta.disable.newEditor').Please move the initialization to
ngOnInitor 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
fnparameter:-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.nextis undefined.packages/altair-app/src/app/modules/altair/components/variable-file-item/variable-file-item.component.ts (1)
53-72: Consider refactoring to avoid redundantupdateLocalStatecall.Both the effect (line 48) and
ngOnInit(line 56) callupdateLocalState, 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:
- Removing the
updateLocalStatecall fromngOnInitand letting the effect handle it- Moving the cache-loading logic into a separate method called after the effect has updated state
- 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 forvalue$.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
π 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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/altair-app/src/testing/utils.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/altair-app/src/testing/utils.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.tspackages/altair-app/src/app/modules/altair/services/environment/environment.service.spec.tspackages/altair-app/src/app/modules/altair/directives/theme/theme.directive.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/altair-app/src/app/modules/altair/components/environment-manager/environment-manager.component.tspackages/altair-app/src/testing/utils.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/beta-indicator/beta-indicator.component.tspackages/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 previousngOnInitlogic, resolving the duplicate initialization issue flagged in the earlier review.
46-46: Null handling correctly fixed.The nullish coalescing operator (
?? {}) ensuresformDatais always an object, resolving the previous null handling concern.
51-51: Simplified signature is correct.Removing the unused
eventanditemparameters is appropriate since the method only emitsthis.formData.packages/altair-app/src/testing/utils.ts (10)
7-8: LGTM!The new imports (
Signalandinject) 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:
ComponentMetaexposes the component metadata structureFilteredSignalKeys<T>correctly identifies signal properties using conditional typesAllowedPropsDataKeys<T>properly combines non-function and signal keysAllowedPropsDataValue<T, K>correctly extracts the inner type from signals usinginfer UThese types enable consumers to work with signal inputs in a type-safe manner.
Also applies to: 139-146
74-95: LGTM!The
getComponentMetafunction 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
normalInputsandsignalInputsfor downstream processingThis maintains backward compatibility while enabling signal-aware testing.
Also applies to: 100-105, 117-122
129-129: LGTM!Changing
propsfromIDictionarytoComponentMetaimproves type safety and provides better IntelliSense for consumers of this base class.
150-150: LGTM!The refined
propsDatatyping usingAllowedPropsDataKeysandAllowedPropsDataValueensures 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
propsDataandpropsimproves 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
normalInputsandsignalInputsfor 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
buildTestHostComponentTemplatefunction:
- Accepts a single
ComponentMetaparameter for cleaner signature- Combines both
normalInputsandsignalInputsfor template generation- Correctly uses property binding syntax
[input]="inputs.input"which Angular handles uniformly for both normal and signal inputsThis 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
updateLocalStateunconditionally, which addresses the previous concern about stale UI whenfileVariablebecomes 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
OnChangesand migration toinject()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
@Inputproperties to readonly signal inputs is correct:
- All inputs have appropriate default values
- Type annotations are preserved
readonlymodifier 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, usinguntracked()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
createEmotionInstancehelper properly encapsulates the Emotion instance creation logic:
- Accepts
cspNonceas a parameter for explicit control- Sets
this.emotionInstancebefore 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.
...p/src/app/modules/altair/components/query-revision-dialog/query-revision-dialog.component.ts
Show resolved
Hide resolved
packages/altair-app/src/app/modules/altair/directives/theme/theme.directive.ts
Show resolved
Hide resolved
There was a problem hiding this 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-emitdataChangewhendata()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 returnsundefined. For clarity and consistency with line 48's explicitreturn undefined;, make this explicit.Apply this diff:
if (!selectedTeamId) { - return; + return undefined; }
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π 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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.htmlpackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item/schema-form-item.component.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.tspackages/altair-app/src/app/modules/altair/components/schema-form/schema-form-item-list/schema-form-item-list.component.tspackages/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.tspackages/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.tspackages/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 toinput()signals follows Angular best practices for the signals API.
85-93: LGTM! Proper form synchronization.The effect correctly synchronizes the team form values when
editTeamIdchanges, 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 typesignal<string | undefined>and with other code usingundefined.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 outputThis 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>()andmodel<unknown>()replace@Input()decoratorsinject(AltairConfig)replaces constructor-based DIThese 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 emitdataChangewheneverdata()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
asStringOrUndefinedmethod complements theisStringOrUndefinedtype 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>()andmodel<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:
- Read current value via
this.data()- Mutate the array in place
- Call
this.data.set(data)to trigger change detectionAngular 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.
Fixes
Checks
yarn test-buildChanges proposed in this pull request:
Summary by CodeRabbit