Skip to content

✨Directly connect parameter inPort to its literal node #196

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

Merged
merged 5 commits into from
Sep 22, 2022
Merged
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
75 changes: 69 additions & 6 deletions src/components/xircuitBodyWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import 'rc-dialog/assets/bootstrap.css';
import { requestAPI } from '../server/handler';
import { XircuitsApplication } from './XircuitsApp';
import ComponentsPanel from '../context-menu/ComponentsPanel';
import { GeneralComponentLibrary } from '../tray_library/GeneralComponentLib';
import { cancelDialog, GeneralComponentLibrary } from '../tray_library/GeneralComponentLib';
import { NodeActionsPanel } from '../context-menu/NodeActionsPanel';
import { AdvancedComponentLibrary } from '../tray_library/AdvanceComponentLib';
import { AdvancedComponentLibrary, fetchNodeByName } from '../tray_library/AdvanceComponentLib';
import { inputDialog, getItsLiteralType } from '../dialog/LiteralInputDialog';

export interface BodyWidgetProps {
context: DocumentRegistry.Context;
Expand Down Expand Up @@ -744,6 +745,16 @@ export const BodyWidget: FC<BodyWidgetProps> = ({
return pythonCode;
}

const showErrorDialog = (title: string, errorMsg: string) => {
showDialog({
title,
body: (
<pre>{errorMsg}</pre>
),
buttons: [Dialog.warnButton({ label: 'OK' })]
});
}

const checkAllNodesConnected = (): boolean | null => {
let nodeModels = xircuitsApp.getDiagramEngine().getModel().getNodes();

Expand Down Expand Up @@ -1580,6 +1591,56 @@ export const BodyWidget: FC<BodyWidgetProps> = ({
}
}

const connectLinkToItsLiteral = async (linkName, event) => {
let portType = linkName.split("-")[1];
let nodeType: string = portType;
let varInput: string = '';
let errorMsg: string;
switch (portType) {
case 'int':
nodeType = 'Integer';
break;
case 'boolean':
let boolTitle = 'Enter boolean value: ';
const dialogOptions = inputDialog(boolTitle, "", 'Boolean');
const dialogResult = await showFormDialog(dialogOptions);
if (cancelDialog(dialogResult)) return;
let boolValue = dialogResult["value"][boolTitle];
if (boolValue == false) {
nodeType = 'False'
} else {
nodeType = 'True'
}
break;
case 'any':
// When inPort is 'any' type, get the correct literal type based on the first character inputed
let portAnyType = await getItsLiteralType();
if (portAnyType == undefined) return;
nodeType = portAnyType.nodeType;
varInput = portAnyType.varInput;
errorMsg = portAnyType.errorMsg;
break;
default:
nodeType = portType.charAt(0).toUpperCase() + portType.slice(1);
break;
}
if (errorMsg != undefined) {
if (nodeType == ('Float' || 'Integer')) {
showErrorDialog('Error : Input have non-numeric values', errorMsg);
} else {
showErrorDialog('Error : Type undefined', errorMsg);
}
return;
}
let current_node = await fetchNodeByName('Literal ' + nodeType);
let node = await GeneralComponentLibrary({ model: current_node, variableValue: varInput });
if (node == undefined) return;
let nodePosition = event.linkEvent;
let sourceLink = { link: event.link, sourcePort: event.sourcePort };
app.commands.execute(commandIDs.addNodeGivenPosition, { node, nodePosition });
app.commands.execute(commandIDs.connectNodeByLink, { targetNode: node, sourceLink, isParameterLink: true });
}

/**Component Panel & Node Action Panel Context Menu */
const [isComponentPanelShown, setIsComponentPanelShown] = useState(false);
const [actionPanelShown, setActionPanelShown] = useState(false);
Expand Down Expand Up @@ -1645,17 +1706,19 @@ export const BodyWidget: FC<BodyWidgetProps> = ({
};

// Show the component panel from dropped link
const showComponentPanelFromLink = (event) => {
const showComponentPanelFromLink = async (event) => {
setActionPanelShown(false);
setIsComponentPanelShown(false);
const linkName = event.link.sourcePort.options.name;
const linkName:string = event.link.sourcePort.options.name;

if (linkName.startsWith("parameter")) {
setIsParameterLink(true)
// Don't show panel when loose link from parameter outPort
// Don't show panel when loose link from parameter outPorts
if (linkName.includes("parameter-out")) {
return
}
// When loose link from type InPort, connect to its respective literal node
connectLinkToItsLiteral(linkName, event);
return;
}

setLooseLinkData({link: event.link, sourcePort: event.sourcePort});
Expand Down
88 changes: 85 additions & 3 deletions src/dialog/LiteralInputDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React, { useState } from 'react';
import { formDialogWidget } from "./formDialogwidget";
import { Dialog } from '@jupyterlab/apputils';
import Switch from "react-switch";
import { showFormDialog } from './FormDialog';
import { cancelDialog } from '../tray_library/GeneralComponentLib';

export function inputDialog(titleName: string, oldValue: any, type: string, isStoreDataType?: boolean, inputType?: string) {
let title = titleName;
Expand All @@ -23,6 +25,68 @@ export function inputDialog(titleName: string, oldValue: any, type: string, isSt
return dialogOptions;
}

export async function getItsLiteralType(){
// When inPort is 'any' type, get the correct literal type based on the first character inputed
let nodeType: string;
let varOfAnyTypeTitle = 'Enter your variable value';
const dialogOptions = inputDialog(varOfAnyTypeTitle, "", 'Variable');
const dialogResult = await showFormDialog(dialogOptions);
if (cancelDialog(dialogResult)) return;
const varValue = dialogResult["value"][varOfAnyTypeTitle];
const varType = varValue.charAt(0);
const varInput : string = varValue.slice(1);
let errorMsg : string;
switch (varType) {
case '"':
nodeType = 'String';
break;
case '#':
const isInputFloat = varInput.search('.');
let onlyNum = Number(varInput);
if (isNaN(onlyNum)){
errorMsg = `Variable's input (${varInput}) contain non-numeric value. Only allow '.' for Float` ;
break;
}
if (isInputFloat == 0) {
nodeType = 'Float';
} else {
nodeType = 'Integer';
}
break;
case '[':
nodeType = 'List';
break;
case '(':
nodeType = 'Tuple';
break;
case '{':
nodeType = 'Dict';
break;
case '!':
let boolValue = varValue.slice(1);
switch (boolValue) {
case 'true':
case 'True':
case '1':
case 't':
nodeType = 'True';
break;
case 'false':
case 'False':
case '0':
case 'nil':
nodeType = 'False';
break;
}
break;
default:
// When type is undefined, show error
errorMsg = `Type is undefined or not provided. Please insert the first chararacter as shown in example` ;
break;
}
return { nodeType, varInput, errorMsg}
}

export const LiteralInputDialog = ({ title, oldValue, type, isStoreDataType, inputType }): JSX.Element => {

const [checked, setChecked] = useState<boolean>(true);
Expand All @@ -44,6 +108,22 @@ export const LiteralInputDialog = ({ title, oldValue, type, isStoreDataType, inp
For Example: "a", "b", "c"
</h5>
);
} else if (type == 'Variable'){
let dictSymbol = '{';
return (
<h5 style={{ marginTop: 0, marginBottom: 5 }}>
<p>Determine your variable type by inserting the first char as below: </p>
<li> " : String</li>
<li> # : Integer</li>
<li> # with '.' : Float</li>
<li> [ : List</li>
<li> ( : Tuple</li>
<li> {dictSymbol} : Dict</li>
<li> !true / !True / !1 / !t : True</li>
<li> !false / !False / !0 / !nil : False</li>
<p>For Example: "Hello World or #15 or !true</p>
</h5>
);
}
return null;
}
Expand Down Expand Up @@ -72,11 +152,12 @@ export const LiteralInputDialog = ({ title, oldValue, type, isStoreDataType, inp
);
} else if (type == 'Boolean') {
return (
<div style={{ paddingLeft: 5 }}>
<div style={{ paddingLeft: 5, paddingTop: 5}}>
<Switch
checked={checked}
name={title}
onChange={() => handleChecked()}
boxShadow="0px 1px 5px rgba(0, 0, 0, 0.6)"
handleDiameter={25}
height={20}
width={48}
Expand All @@ -87,7 +168,8 @@ export const LiteralInputDialog = ({ title, oldValue, type, isStoreDataType, inp
(type == 'String' && inputType != 'textarea') ||
type == 'List' ||
type == 'Tuple' ||
type == 'Dict'
type == 'Dict' ||
type == 'Variable'
) {
return (
<input
Expand All @@ -101,7 +183,7 @@ export const LiteralInputDialog = ({ title, oldValue, type, isStoreDataType, inp

return (
<form>
{type != 'Boolean' ?
{type != 'Boolean' && type != 'Variable' ?
<h3 style={{ marginTop: 0, marginBottom: 5 }}>
Enter {title.includes('parameter') ? 'Hyperparameter Name' : `${type} Value`} ({isStoreDataType ? 'Without Brackets' : 'Without Quotes'}):
</h3>
Expand Down
Loading