Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,10 @@ export class ApplicationMenuManager {
click() {
WindowManager.createPopupWindowWithRouting({
title: 'Variables',
url: "#/headless/variable-pane",
url: '#/headless/variable-pane',
width: 400,
height: 450,
minWidth: 350,
alwaysOnTop: true,
modal: false,
});
Expand Down
2 changes: 2 additions & 0 deletions gui-js/apps/minsky-web/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico" />

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;">

<style>
.loader {
border: 8px solid #f3f3f3;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class Connector {
type: string;
position: (x: number, y: number, width: number, height: number) => [number,number];
}
22 changes: 22 additions & 0 deletions gui-js/libs/ui-components/src/lib/svg-canvas/classes/datapoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ElementType } from './elementtype';
import { Connector } from './connector';
import { Dimensions } from './dimensions';

export class DataPoint {
label: string;
x?: number;
y?: number;
fx?: number;
fy?: number;
value: number;
exponent: number;
rotation: number;
anchorx?: number;
anchory?: number;
type: ElementType;
connectors: Connector[];
canvasPosition;
symbol;
dimensions: Dimensions;
hidden = false;
}
Comment on lines +5 to +22
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.

🛠️ Refactor suggestion | 🟠 Major

Align this model with the field name the rest of the PR uses.

VariablePaneComponent creates these objects with name (gui-js/libs/ui-components/src/lib/variable-pane/variable-pane.component.ts Line 118), and SvgCanvasComponent later edits d.name (gui-js/libs/ui-components/src/lib/svg-canvas/svg-canvas.component.ts Lines 469-482). Keeping only label here means the declared type no longer matches the runtime shape, which is an easy way to end up with stale/broken name bindings.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gui-js/libs/ui-components/src/lib/svg-canvas/classes/datapoint.ts` around
lines 5 - 22, The DataPoint model currently declares "label" but the rest of the
codebase constructs/uses a "name" property (see VariablePaneComponent and
SvgCanvasComponent referencing d.name), causing a type/runtime mismatch; update
DataPoint (the class exported as DataPoint in datapoint.ts) to include a "name:
string" property (and optionally remove or alias "label" if you want a single
canonical field) so the declared type matches objects created/edited elsewhere
(ensure usages that expect d.name keep working).

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export class Dimensions {
length: number;
boundingbox: number[];
labelbox: number[];
valuebox: number[];
exponentbox: number[];
valueline?: number[][];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Connector } from './connector';
import { Dimensions } from './dimensions';

export class ElementType {
name: string;
points: (x: number, y: number, width: number, height: number) => string;
size: number[];
connectors: Connector[];
getDimensions: (length: number) => Dimensions;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<svg:path #linepath [style.display]="invisibleLine ? 'none' : 'inherit'"></svg:path>

<svg:circle #startpoint [attr.cx]="start[0]" [attr.cy]="start[1]" r="0.00001"></svg:circle>
<svg:circle #endpoint [attr.cx]="end[0]" [attr.cy]="end[1]" r="0.00001"></svg:circle>

<svg:circle #midpoint dragdrop *ngFor="let p of dotPositions; let i = index"
[dragfunctions]="dragfunctions(p, i)" [attr.cx]="p.x" [attr.cy]="p.y" r="7"></svg:circle>
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { CommonModule } from '@angular/common';
import { ElementRef, Input, OnChanges, ViewChild, Component, SimpleChanges, Output, EventEmitter, ViewChildren } from '@angular/core';
import * as d3 from 'd3';

@Component({
selector: '[d3line]',
templateUrl: './d3line.component.html',
styleUrls: ['./d3line.component.css'],
imports: [CommonModule]
})
Comment on lines +5 to +10
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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

In Angular, is the importsmetadata field valid on a component withoutstandalone: true, and can such a component be imported directly into another standalone component's imports array?

💡 Result:

No, the imports metadata field is not valid on a component without standalone: true. It is only available for standalone components. Additionally, a non-standalone component cannot be imported directly into another standalone component's imports array. Non-standalone components must be declared and exported from an NgModule, and that NgModule must be imported into the standalone component's imports array instead.

Citations:


🏁 Script executed:

# Find the SvgCanvasComponent file
fd -e ts SvgCanvas

Repository: highperformancecoder/minsky

Length of output: 53


🏁 Script executed:

# Search for D3LineComponent imports in the codebase
rg "D3LineComponent" --type ts -B 2 -A 2

Repository: highperformancecoder/minsky

Length of output: 1957


🏁 Script executed:

# Check the SvgCanvasComponent definition to see its imports
rg "selector.*svg-canvas" --type ts -B 5 -A 15

Repository: highperformancecoder/minsky

Length of output: 5169


Mark this component as standalone before importing it directly.

SvgCanvasComponent imports D3LineComponent in its standalone imports array, but D3LineComponent omits standalone: true. Angular only allows this wiring when the child component is declared as standalone. Currently, D3LineComponent has the imports metadata field (used only for standalone components) without the standalone: true flag, making it a non-standalone component that cannot be directly imported into another component's imports array.

Suggested fix
 `@Component`({
   selector: '[d3line]',
+  standalone: true,
   templateUrl: './d3line.component.html',
   styleUrls: ['./d3line.component.css'],
   imports: [CommonModule]
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Component({
selector: '[d3line]',
templateUrl: './d3line.component.html',
styleUrls: ['./d3line.component.css'],
imports: [CommonModule]
})
`@Component`({
selector: '[d3line]',
standalone: true,
templateUrl: './d3line.component.html',
styleUrls: ['./d3line.component.css'],
imports: [CommonModule]
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gui-js/libs/ui-components/src/lib/svg-canvas/components/d3line.component.ts`
around lines 5 - 10, D3LineComponent is missing the standalone flag but already
uses the imports metadata, so add standalone: true to the `@Component` metadata
for D3LineComponent to make it a standalone component that can be referenced
from SvgCanvasComponent's imports array; update the `@Component` decorator for
D3LineComponent (the class named D3LineComponent) to include standalone: true
while keeping its existing imports, selector, templateUrl, and styleUrls intact.

export class D3LineComponent implements OnChanges {
@ViewChild('linepath', {static: true})
linepath: ElementRef;

@ViewChild('startpoint', {static: true})
startpoint: ElementRef;

@ViewChild('endpoint', {static: true})
endpoint: ElementRef;

@ViewChildren('midpoint')
midpoints;

@Input()
start: [number,number,number];

@Input()
end: [number,number,number];

@Input()
dotsAt: number[];

dotPositions: any[] = [];

@Input()
invisibleLine = false;

@Input()
draggable = true;

@Output()
pointMoved = new EventEmitter<any>();

constructor() {

}

ngOnChanges(changes: SimpleChanges) {
if(this.start && this.end && (changes.start || changes.end)) {
const points: any = [this.start];

const pointDistance = Math.sqrt(Math.pow(this.end[0] - this.start[0], 2) + Math.pow(this.end[1] - this.start[1], 2)) / 4;
if(this.start[2] !== undefined) {
points.push([this.start[0] + Math.cos(this.start[2]) * pointDistance, this.start[1] + Math.sin(this.start[2]) * pointDistance]);
}
if(this.end[2] !== undefined) {
points.push([this.end[0] + Math.cos(this.end[2]) * pointDistance, this.end[1] + Math.sin(this.end[2]) * pointDistance]);
}
points.push(this.end);

this.linepath.nativeElement.setAttribute('d', d3.line().curve(d3.curveBasis)(points));
}

if(changes.dotsAt) {
this.handleDotsChange();
}
}

handleDotsChange() {
const path = this.linepath.nativeElement;
const length = path.getTotalLength();
this.dotPositions = this.dotsAt.map(percentage => {
return path.getPointAtLength(percentage * length);
});
}

dragfunctions(p, i) {
const startBox = this.startpoint.nativeElement.getBBox();
const endBox = this.endpoint.nativeElement.getBBox();
const start = [startBox.x + startBox.width / 2, startBox.y + startBox.height / 2];
const end = [endBox.x + endBox.width / 2, endBox.y + endBox.height / 2];

return {
dragstarted: () => {
},
dragged: () => {
if(this.draggable) {
const x = d3.event.x;
const y = d3.event.y;

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable y.
const point = [x,1000];

const a1 = Math.max(0, Math.PI / 2 - this.getAngle(end, start, point));
const a2 = Math.max(0, Math.PI / 2 - this.getAngle(start, end, point));

this.dotsAt[i] = a1 / (a1 + a2);
this.pointMoved.emit(this.dotsAt[i]);
Comment on lines +86 to +96
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the repo's D3 version and locate legacy global-event usage.
fd -i 'package.json' . -x rg -n '"d3"\s*:' {}
fd -i 'package-lock.json' . -x rg -n '"d3"\s*:' {}
rg -n -C2 "d3\.event|dragstarted:|dragged:|dragended:" gui-js/libs/ui-components/src/lib/svg-canvas

Repository: highperformancecoder/minsky

Length of output: 6980


Replace hardcoded Y coordinate with live drag position.

Line 89 captures y from the drag event, but line 90 hardcodes the probe point to [x, 1000], discarding the captured Y coordinate. This causes dotsAt[i] to only respond to horizontal drag movements instead of using the full 2D drag position.

The codebase uses D3 v5.16.0, where d3.event is correctly available during drag callbacks, so the current implementation works as-is. However, the hardcoded Y value appears unintentional given the pattern elsewhere in the component.

Fix
-                const point = [x,1000];
+                const point = [x, y];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
dragged: () => {
if(this.draggable) {
const x = d3.event.x;
const y = d3.event.y;
const point = [x,1000];
const a1 = Math.max(0, Math.PI / 2 - this.getAngle(end, start, point));
const a2 = Math.max(0, Math.PI / 2 - this.getAngle(start, end, point));
this.dotsAt[i] = a1 / (a1 + a2);
this.pointMoved.emit(this.dotsAt[i]);
dragged: () => {
if(this.draggable) {
const x = d3.event.x;
const y = d3.event.y;
const point = [x, y];
const a1 = Math.max(0, Math.PI / 2 - this.getAngle(end, start, point));
const a2 = Math.max(0, Math.PI / 2 - this.getAngle(start, end, point));
this.dotsAt[i] = a1 / (a1 + a2);
this.pointMoved.emit(this.dotsAt[i]);
🧰 Tools
🪛 GitHub Check: CodeQL

[notice] 89-89: Unused variable, import, function or class
Unused variable y.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@gui-js/libs/ui-components/src/lib/svg-canvas/components/d3line.component.ts`
around lines 86 - 96, The drag handler is ignoring vertical movement by using a
hardcoded point [x, 1000]; update the probe point to use the live drag Y from
d3.event (replace [x, 1000] with [x, y]) so getAngle(...) computes using the
actual drag position; change the point construction in the dragged lambda (where
draggable, x, y, point, getAngle, dotsAt[i], and pointMoved are referenced) to
use the captured y variable.

}
},
dragended: () => {

}
};
}

getAngle(x, y, z) {
const a = [z[0] - y[0], z[1] - y[1]];
const b = [x[0] - y[0], x[1] - y[1]];
const al = Math.sqrt(Math.pow(a[0],2)+Math.pow(a[1],2));
const bl = Math.sqrt(Math.pow(b[0],2)+Math.pow(b[1],2));
const dotproduct = a[0] * b[0] + a[1] * b[1];
return Math.acos(dotproduct / (al * bl));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:host {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
overflow: visible;
}

.namelabel, .descriptionlabel, .valuelabel {
display: flex;
justify-content: center;
align-items: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
}

.descriptionlabel {
flex-grow: 6;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="latex" latex [equation]="data.symbol" [style.fontSize]="fontSize">
</div>

<div *ngIf="lines > 1" class="valuelabel" [style.fontSize]="fontSize">
{{data.value.toFixed(4)}}
</div>
Comment on lines +4 to +6
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.

⚠️ Potential issue | 🟡 Minor

Guard against undefined data.value before calling .toFixed(4).

The data input is untyped (@Input() data;), and DataPoint.value may not always be initialized. Calling .toFixed(4) on undefined or null will throw a TypeError at runtime.

🛡️ Proposed fix: add null guard
 <div *ngIf="lines > 1" class="valuelabel" [style.fontSize]="fontSize">
-    {{data.value.toFixed(4)}}
+    {{data.value != null ? data.value.toFixed(4) : ''}}
 </div>

Alternatively, consider using the optional chaining operator if the Angular compiler version supports it:

{{data.value?.toFixed(4) ?? ''}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div *ngIf="lines > 1" class="valuelabel" [style.fontSize]="fontSize">
{{data.value.toFixed(4)}}
</div>
<div *ngIf="lines > 1" class="valuelabel" [style.fontSize]="fontSize">
{{data.value != null ? data.value.toFixed(4) : ''}}
</div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@gui-js/libs/ui-components/src/lib/svg-canvas/components/elementlabel.component.html`
around lines 4 - 6, The template calls data.value.toFixed(4) without guarding
for null/undefined; update the elementlabel.component.html expression (the line
rendering {{data.value.toFixed(4)}}) to guard against missing values—either use
Angular safe navigation/optional chaining and a default (e.g.,
{{data?.value?.toFixed(4) ?? ''}} or {{data.value?.toFixed(4) ?? ''}} if
allowed) or wrap the display in an *ngIf that checks data && data.value !==
undefined; also ensure the component's `@Input`() data is appropriately typed
(e.g., DataPoint | undefined) in the ElementLabelComponent so the template and
type system reflect the possible absence of value.


<div *ngIf="lines > 2" class="namelabel" [style.fontSize]="fontSize">
{{data.name}}
</div>

<div *ngIf="lines > 3" class="descriptionlabel" [style.fontSize]="fontSize">
{{data.description}}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Component, Input } from '@angular/core';
import { LatexDirective } from '../../directives/latex.directive';
import { CommonModule } from '@angular/common';

@Component({
selector: 'elementlabel',
templateUrl: './elementlabel.component.html',
styleUrls: ['./elementlabel.component.css'],
standalone: true,
imports: [LatexDirective, CommonModule]
})
export class ElementLabelComponent {
@Input()
data;

@Input()
lines: number;

get fontSize() {
return `${20 / this.lines}px`;
}
Comment on lines +19 to +21
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.

⚠️ Potential issue | 🟠 Major

Division by zero when lines is 0 produces invalid CSS.

The template passes lines=0 for non-operator types (d.type.name === 'operator' ? getLines(yFactor) : 0). When lines is 0, fontSize returns "Infinitypx", which is invalid CSS.

🐛 Proposed fix
     get fontSize() {
+        if (!this.lines || this.lines <= 0) {
+            return '20px'; // Default font size
+        }
         return `${20 / this.lines}px`;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
get fontSize() {
return `${20 / this.lines}px`;
}
get fontSize() {
if (!this.lines || this.lines <= 0) {
return '20px'; // Default font size
}
return `${20 / this.lines}px`;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@gui-js/libs/ui-components/src/lib/svg-canvas/components/elementlabel.component.ts`
around lines 19 - 21, The fontSize getter can divide by zero when this.lines ===
0; modify the fontSize logic in the elementlabel.component (the fontSize getter)
to guard against zero/negative values (e.g. use Math.max(this.lines, 1) or
return a sensible default like '20px' when this.lines is falsy) so it never
returns "Infinitypx" and always produces valid CSS.

}
Loading
Loading