Skip to content

SED-4838 added IDE handling for plan referencing - #1443

Open
neogucky wants to merge 2 commits into
SED-4429-step-ap-idefrom
SED-4838-plan-editor-normalized-subplan-referencing
Open

SED-4838 added IDE handling for plan referencing#1443
neogucky wants to merge 2 commits into
SED-4429-step-ap-idefrom
SED-4838-plan-editor-normalized-subplan-referencing

Conversation

@neogucky

Copy link
Copy Markdown
Collaborator

No description provided.

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

Copy link
Copy Markdown
Contributor

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 introduces the PlanReferencePolicyService to handle plan reference modes and navigation permissions, particularly for IDE mode, and refactors several components to use Angular's signal-based inputs and view queries. Key feedback includes resolving a critical runtime error by allowing signal writes in the initialPlanContextEffect, replacing non-null assertions in ArtefactsFactoryService to prevent potential TypeErrors, restricting plan navigation checks to CallPlan artefacts, and using an optional viewChild in CallPlanComponent to avoid early-access runtime errors.

Comment on lines +186 to +190
private readonly initialPlanContextEffect = effect(() => {
const context = this.initialPlanContext();
this.initializeContext(context ?? undefined, true);
this.repositoryObjectRef = this._planEditorApi.createRepositoryObjectReference(context?.id);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Since this.initializeContext eventually calls this._planEditorService.init(), which writes to signals (such as planContextInternal or other state signals), running this inside an effect without { allowSignalWrites: true } will throw a runtime error (NG0600: Writing to signals is not allowed in a template or an effect by default). We should explicitly allow signal writes for this effect.

Suggested change
private readonly initialPlanContextEffect = effect(() => {
const context = this.initialPlanContext();
this.initializeContext(context ?? undefined, true);
this.repositoryObjectRef = this._planEditorApi.createRepositoryObjectReference(context?.id);
});
private readonly initialPlanContextEffect = effect(() => {
const context = this.initialPlanContext();
this.initializeContext(context ?? undefined, true);
this.repositoryObjectRef = this._planEditorApi.createRepositoryObjectReference(context?.id);
}, { allowSignalWrites: true });

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not relevant for Angular 19

Comment on lines +114 to +116
const callPlan = artefact as AbstractArtefact & CallPlan;
callPlan.attributes!['name'] = plan.attributes!['name'];
callPlan.dynamicName!.dynamic = callPlan.useDynamicName;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To prevent potential runtime TypeErrors, we should avoid using non-null assertions (!) on plan.attributes, callPlan.attributes, and callPlan.dynamicName. If any of these are undefined, the application will crash. Let's use defensive checks instead.

Suggested change
const callPlan = artefact as AbstractArtefact & CallPlan;
callPlan.attributes!['name'] = plan.attributes!['name'];
callPlan.dynamicName!.dynamic = callPlan.useDynamicName;
const callPlan = artefact as AbstractArtefact & CallPlan;
if (plan?.attributes) {
callPlan.attributes = callPlan.attributes ?? {};
callPlan.attributes['name'] = plan.attributes['name'];
}
if (callPlan.dynamicName) {
callPlan.dynamicName.dynamic = callPlan.useDynamicName;
}

Comment on lines +291 to +294
return (
['CallPlan', 'CallKeyword'].includes(artefact._class) &&
this._planReferencePolicy.canNavigateToReferencedPlan(artefact)
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Calling canNavigateToReferencedPlan on a CallKeyword artefact is semantically incorrect and potentially misleading, even though it currently returns true. We should only perform this check for CallPlan artefacts.

Suggested change
return (
['CallPlan', 'CallKeyword'].includes(artefact._class) &&
this._planReferencePolicy.canNavigateToReferencedPlan(artefact)
);
if (artefact._class === 'CallKeyword') {
return true;
}
return (
artefact._class === 'CallPlan' &&
this._planReferencePolicy.canNavigateToReferencedPlan(artefact)
);

Comment on lines +36 to +40
protected readonly formReference = viewChild.required<NgForm>('form');

protected get form(): NgForm {
return this.formReference();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using viewChild.required for a property that might be accessed by the parent class (BaseArtefactComponent) or during early lifecycle hooks (like contextChange or ngOnInit) can cause a runtime error if accessed before the view is initialized. Using an optional viewChild is safer and more robust.

Suggested change
protected readonly formReference = viewChild.required<NgForm>('form');
protected get form(): NgForm {
return this.formReference();
}
protected readonly formReference = viewChild<NgForm>('form');
protected get form(): NgForm | undefined {
return this.formReference();
}

@neogucky
neogucky requested a review from dvladir August 27, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants