Skip to content

Commit 977b166

Browse files
Copilotmikebarkmin
andcommitted
Add String as object mode with non-editable fields and make array length non-editable
Co-authored-by: mikebarkmin <2592379+mikebarkmin@users.noreply.github.com>
1 parent 8a08a36 commit 977b166

6 files changed

Lines changed: 299 additions & 1 deletion

File tree

src/ConfigView.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,28 @@ export const ConfigView = () => {
422422
/>
423423
Create New On Edge Drop
424424
</label>
425+
<label style={{
426+
display: "flex",
427+
alignItems: "center",
428+
gap: "8px",
429+
fontSize: "14px",
430+
color: "#374151",
431+
cursor: "pointer"
432+
}}>
433+
<input
434+
type="checkbox"
435+
checked={options.useStringAsObject || false}
436+
onChange={(e) =>
437+
handleOptionChange("useStringAsObject", e.target.checked)
438+
}
439+
style={{
440+
width: "16px",
441+
height: "16px",
442+
cursor: "pointer"
443+
}}
444+
/>
445+
Use String As Object
446+
</label>
425447
</div>
426448
</div>
427449

src/MemoryView.tsx

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import ReferenceEdge from "./ReferenceEdge";
4040
import { CustomEdgeType, CustomNodeType } from "./types";
4141
import { ArrayCreationDialog } from "./ArrayCreationDialog";
4242
import { SimpleInputDialog } from "./SimpleInputDialog";
43+
import { StringCreationDialog } from "./StringCreationDialog";
4344

4445
const selector = (state: RFState) => ({
4546
selectedNodeId: state.selectedNodeId,
@@ -130,6 +131,12 @@ export const MemoryView = () => {
130131
const [showLocalVarDialog, setShowLocalVarDialog] = useState(false);
131132
const [localVarDialogNodeId, setLocalVarDialogNodeId] = useState<string | null>(null);
132133

134+
// String creation dialog state
135+
const [showStringDialog, setShowStringDialog] = useState(false);
136+
const [stringDialogCallback, setStringDialogCallback] = useState<
137+
((name: string, value: string) => void) | null
138+
>(null);
139+
133140
const methodCalls = nodes.filter(isMethodCallNode);
134141
let previousMethodCall = methodCalls[0];
135142
let lastMethodCall = methodCalls[0];
@@ -200,6 +207,14 @@ export const MemoryView = () => {
200207
return [...primitveDataTypes, ...Object.keys(memory.klasses)];
201208
};
202209

210+
// Helper function to show string creation dialog
211+
const showStringCreationDialog = (
212+
callback: (name: string, value: string) => void
213+
) => {
214+
setStringDialogCallback(() => callback);
215+
setShowStringDialog(true);
216+
};
217+
203218
// Handler for declaring local variables
204219
const handleDeclareLocalVariable = (nodeId: string) => {
205220
setLocalVarDialogNodeId(nodeId);
@@ -498,6 +513,79 @@ export const MemoryView = () => {
498513
}
499514

500515
if (type != "variable") {
516+
if (type == "String" && memory.options.useStringAsObject) {
517+
// Show dialog for String creation
518+
showStringCreationDialog((name, value) => {
519+
const objAttributes: Record<string, Attribute> = {
520+
value: {
521+
dataType: "String",
522+
value: value,
523+
},
524+
};
525+
526+
const newNode: CustomNodeType = {
527+
id: getId(),
528+
type: "object",
529+
position,
530+
data: {
531+
klass: "String",
532+
attributes: objAttributes,
533+
position,
534+
},
535+
};
536+
537+
if (lastMethodCall === undefined) {
538+
const newVar: CustomNodeType = {
539+
id: getId(),
540+
type: "variable",
541+
position: {
542+
x: position.x - 100,
543+
y: position.y,
544+
},
545+
data: {
546+
name,
547+
value: newNode.id,
548+
position: {
549+
x: position.x - 100,
550+
y: position.y,
551+
},
552+
dataType: "String",
553+
},
554+
};
555+
setNodes((nds) => nds.concat(newNode, newVar));
556+
const newEdge: CustomEdgeType = {
557+
id: getId(),
558+
source: newVar.id,
559+
target: newNode.id,
560+
};
561+
setEdges((egs) => egs.concat(newEdge));
562+
} else {
563+
setNodes((nds) =>
564+
nds
565+
.map((n) => {
566+
if (n.id == lastMethodCall.id) {
567+
(n.data as any).localVariables[name] = {
568+
dataType: "String",
569+
value: newNode.id,
570+
};
571+
return n;
572+
}
573+
return n;
574+
})
575+
.concat(newNode)
576+
);
577+
const newEdge: CustomEdgeType = {
578+
id: getId(),
579+
source: lastMethodCall.id,
580+
sourceHandle: name,
581+
target: newNode.id,
582+
};
583+
setEdges((egs) => egs.concat(newEdge));
584+
}
585+
});
586+
return;
587+
}
588+
501589
if (type == "Array") {
502590
// Show dialog for array creation
503591
showArrayCreationDialog((name, length, elementType) => {
@@ -831,6 +919,19 @@ export const MemoryView = () => {
831919
}}
832920
/>
833921
)}
922+
{showStringDialog && stringDialogCallback && (
923+
<StringCreationDialog
924+
onConfirm={(name, value) => {
925+
stringDialogCallback(name, value);
926+
setShowStringDialog(false);
927+
setStringDialogCallback(null);
928+
}}
929+
onCancel={() => {
930+
setShowStringDialog(false);
931+
setStringDialogCallback(null);
932+
}}
933+
/>
934+
)}
834935
</div>
835936
);
836937
};

src/ObjectNode.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ function ObjectNode({ id, data }: NodeProps<ObjectNodeType>) {
145145
{Object.entries(data.attributes).map(([name, value]) => (
146146
<AttributeHandle
147147
key={`${id}+${name}`}
148-
isFinal={false}
148+
isFinal={
149+
(data.klass === "Array" && name === "length") ||
150+
(data.klass === "String" && name === "value")
151+
}
149152
isConnected={
150153
attributeEdges.find((e) => e.sourceHandle == name)?.target != null
151154
}

src/Sidebar.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ export const Sidebar = ({
8181
new Array
8282
</div>
8383
)}
84+
{memory.options.useStringAsObject && (
85+
<div
86+
className="dndnode sidebar-class"
87+
onPointerDown={(event) => {
88+
setType('String');
89+
onDragStart(event, makeOnDropAction('String'));
90+
}}
91+
>
92+
new String
93+
</div>
94+
)}
8495
{!memory.options.hideDeclareGlobalVariable && (
8596
<div
8697
className="sidebar-variable"

src/StringCreationDialog.tsx

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { useState } from "react";
2+
3+
interface StringCreationDialogProps {
4+
onConfirm: (name: string, value: string) => void;
5+
onCancel: () => void;
6+
}
7+
8+
export function StringCreationDialog({
9+
onConfirm,
10+
onCancel,
11+
}: StringCreationDialogProps) {
12+
const [name, setName] = useState("");
13+
const [value, setValue] = useState("");
14+
15+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
16+
e.preventDefault();
17+
if (name.trim()) {
18+
onConfirm(name.trim(), value);
19+
}
20+
};
21+
22+
return (
23+
<div
24+
style={{
25+
position: "fixed",
26+
top: 0,
27+
left: 0,
28+
right: 0,
29+
bottom: 0,
30+
backgroundColor: "rgba(0, 0, 0, 0.5)",
31+
display: "flex",
32+
alignItems: "center",
33+
justifyContent: "center",
34+
zIndex: 1000,
35+
}}
36+
onClick={onCancel}
37+
>
38+
<div
39+
style={{
40+
backgroundColor: "white",
41+
padding: "24px",
42+
borderRadius: "8px",
43+
minWidth: "400px",
44+
maxWidth: "90vw",
45+
border: "1px solid #e5e7eb",
46+
margin: "20px",
47+
}}
48+
onClick={(e) => e.stopPropagation()}
49+
>
50+
<h3
51+
style={{
52+
margin: "0 0 16px 0",
53+
fontSize: "18px",
54+
fontWeight: "600",
55+
color: "#111827",
56+
}}
57+
>
58+
Create New String
59+
</h3>
60+
<form onSubmit={handleSubmit}>
61+
<div style={{ marginBottom: "16px" }}>
62+
<label
63+
style={{
64+
display: "block",
65+
marginBottom: "6px",
66+
fontSize: "14px",
67+
fontWeight: "500",
68+
color: "#374151",
69+
}}
70+
>
71+
String Name
72+
</label>
73+
<input
74+
type="text"
75+
value={name}
76+
onChange={(e) => setName(e.target.value)}
77+
placeholder="Enter string name"
78+
autoFocus
79+
style={{
80+
width: "100%",
81+
padding: "8px 12px",
82+
borderRadius: "6px",
83+
border: "1px solid #d1d5db",
84+
fontSize: "14px",
85+
boxSizing: "border-box",
86+
}}
87+
/>
88+
</div>
89+
<div style={{ marginBottom: "16px" }}>
90+
<label
91+
style={{
92+
display: "block",
93+
marginBottom: "6px",
94+
fontSize: "14px",
95+
fontWeight: "500",
96+
color: "#374151",
97+
}}
98+
>
99+
String Value
100+
</label>
101+
<input
102+
type="text"
103+
value={value}
104+
onChange={(e) => setValue(e.target.value)}
105+
placeholder="Enter string value"
106+
style={{
107+
width: "100%",
108+
padding: "8px 12px",
109+
borderRadius: "6px",
110+
border: "1px solid #d1d5db",
111+
fontSize: "14px",
112+
boxSizing: "border-box",
113+
}}
114+
/>
115+
</div>
116+
<div
117+
style={{
118+
display: "flex",
119+
gap: "8px",
120+
justifyContent: "flex-end",
121+
}}
122+
>
123+
<button
124+
type="button"
125+
onClick={onCancel}
126+
style={{
127+
backgroundColor: "white",
128+
color: "#374151",
129+
padding: "8px 16px",
130+
fontSize: "14px",
131+
fontWeight: "500",
132+
border: "1px solid #d1d5db",
133+
borderRadius: "6px",
134+
cursor: "pointer",
135+
}}
136+
>
137+
Cancel
138+
</button>
139+
<button
140+
type="submit"
141+
disabled={!name.trim()}
142+
style={{
143+
backgroundColor: name.trim() ? "#111827" : "#9ca3af",
144+
color: "white",
145+
padding: "8px 16px",
146+
fontSize: "14px",
147+
fontWeight: "500",
148+
border: "none",
149+
borderRadius: "6px",
150+
cursor: name.trim() ? "pointer" : "not-allowed",
151+
}}
152+
>
153+
Create
154+
</button>
155+
</div>
156+
</form>
157+
</div>
158+
</div>
159+
);
160+
}

src/memory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export type Memory = {
9999
hideDeclareGlobalVariable?: boolean;
100100
hideNewArray?: boolean;
101101
createNewOnEdgeDrop?: boolean;
102+
useStringAsObject?: boolean;
102103
};
103104
klasses: Klasses;
104105
objects: Objs;

0 commit comments

Comments
 (0)