Skip to content

Commit

Permalink
WID-100: add functionality to display the description of the componen…
Browse files Browse the repository at this point in the history
…t arguments
  • Loading branch information
rarescodemart authored and popaula937 committed Mar 14, 2023
1 parent 8c14590 commit 70f585f
Show file tree
Hide file tree
Showing 13 changed files with 468 additions and 248 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,8 @@ tsconfig.tsbuildinfo

# .py files compiled by Xircuits
examples/*.py

# pycharm files
/.idea/

xai_components/*/arguments
8 changes: 6 additions & 2 deletions src/components/CustomNodeModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ export class CustomNodeModel extends DefaultNodeModel {
this.extras=event.data.extras;
}

addOutPortEnhance(label: string, name: string, after: boolean = true, id?: string): CustomPortModel {
addOutPortEnhance(label: string, name: string, after: boolean = true, id?: string, description: string = ""): CustomPortModel {

//check if portID is passed, if not SR will generate a new port ID
const p = (id) ? new CustomPortModel({in: false, name: name, label: label, id:id}) :
new CustomPortModel({in: false, name: name, label: label});

p.description = description;

if (!after) {
this.portsOut.splice(0, 0, p);
Expand All @@ -54,12 +56,14 @@ export class CustomNodeModel extends DefaultNodeModel {
return this.addPort(p);
}

addInPortEnhance(label: string, name: string, after: boolean = true, id?: string): CustomPortModel {
addInPortEnhance(label: string, name: string, after: boolean = true, id?: string, description: string = ""): CustomPortModel {

//check if portID is passed, if not SR will generate a new port ID
const p = (id) ? new CustomPortModel({in: true, name: name, label: label, id:id}) :
new CustomPortModel({in: true, name: name, label: label});

p.description = description;

if (!after) {
this.portsOut.splice(0, 0, p);
}
Expand Down
99 changes: 82 additions & 17 deletions src/components/CustomNodeWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ export interface DefaultNodeProps {
*/
export class CustomNodeWidget extends React.Component<DefaultNodeProps> {

generatePort = (port) => {
return <CustomPortLabel engine={this.props.engine} port={port} key={port.getID()} node={this.props.node} />;
};
portsNo = this.props.node.getInPorts().length + this.props.node.getOutPorts().length;

tooltipDescriptionRef = React.createRef<HTMLDivElement>();

element:Object;
state = {

Expand All @@ -127,7 +128,63 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
original: 'https://picsum.photos/id/1019/1000/600/',
thumbnail: 'https://picsum.photos/id/1019/250/150/'
},
]
],
showParamDescriptionList: new Array(this.portsNo).fill(false),
paramName: ""
};

/**
* creates a particular function for each component so that it can set only it's state
* @param id
*/
setShowParamDescription = (id : number) => {
const _setShowParamDescription = (newShowDescription : boolean) => {
this.setState({
showParamDescriptionList: this.state.showParamDescriptionList.map((value, index) => (
id === index ? newShowDescription : false
)
),
showDescription: false
})
}
return _setShowParamDescription;
}

setDescriptionStr = (paramName: string) => {
const _setDescriptionStr = async (descriptionStr : string) => {
await this.setState({
descriptionStr : descriptionStr,
paramName: paramName
});
ReactTooltip.show(this.element as Element);
}
return _setDescriptionStr;
}

generatePort = (port, index) => {
const argumentDescriptions = this.props.node['extras']['argumentDescriptions'];

// remove the ☆ from the beginning of the label
const name = port.getOptions().label[0] === "★" ? port.getOptions().label.slice(1) : port.getOptions().label;

const description = argumentDescriptions && (name in argumentDescriptions) ? argumentDescriptions[name] : "";

const isOutPort = port.getOptions().name.includes('parameter-out');

index = isOutPort ? index + this.props.node.getInPorts().length: index;

return (
<CustomPortLabel
engine={this.props.engine}
port={port}
key={port.getID()}
node={this.props.node}
showDescription={this.state.showParamDescriptionList[index]}
setShowDescription={this.setShowParamDescription(index)}
setDescriptionStr = {this.setDescriptionStr}
description={description}
/>
);
};

showTooltip() {
Expand Down Expand Up @@ -206,8 +263,12 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
* Show/Hide Component's Description Tooltip
*/
async handleDescription() {
await this.setState({ showDescription: !this.state.showDescription });
this.getDescriptionStr();
await this.setState({
showDescription: !this.state.showDescription,
showParamDescriptionList: new Array(this.portsNo).fill(false),
paramName: ""
});
await this.getDescriptionStr();
ReactTooltip.show(this.element as Element);
}

Expand All @@ -234,7 +295,7 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
delete this.props.node.getOptions().extras["tip"];
this.props.node.getOptions().extras["borderColor"]="rgb(0,192,255)";
}

render() {
if (this.props.node['extras']['type'] == 'comment') {
return (
Expand Down Expand Up @@ -301,39 +362,43 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
</S.Ports>
</S.Node>
{/** Description Tooltip */}
{this.state.showDescription && <ReactTooltip
{(this.state.showDescription || this.state.showParamDescriptionList.reduce((prev, cur) => prev || cur, false)) && <ReactTooltip
id={this.props.node.getOptions().id}
className='description-tooltip'
arrowColor='rgb(255, 255, 255)'
clickable
afterShow={() => { this.setState({ showDescription: true }) }}
afterHide={() => { this.setState({ showDescription: false }) }}
delayHide={60000}
delayUpdate={5000}
delayUpdate={0}
getContent={() =>
<div data-no-drag style={{ cursor: 'default' }}>
<div data-no-drag style={{ cursor: 'default' }} ref={this.tooltipDescriptionRef}>
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
onClick={() => { this.setState({ showDescription: false }); }}>
onClick={() => { this.setState({
showDescription: false,
showParamDescriptionList: new Array(this.portsNo).fill(false)
}); }}
>
<span aria-hidden="true">&times;</span>
</button>
<S.DescriptionName color={this.props.node.getOptions().color}>{this.props.node.getOptions()["name"]}</S.DescriptionName>
<S.DescriptionName color={this.props.node.getOptions().color}>{this.props.node.getOptions()["name"] + " " + this.state.paramName}</S.DescriptionName>
<p className='description-title'>Description:</p>
<div
<div
onWheel={(e) => e.stopPropagation()}
className='description-container'>
<div className='markdown-body' dangerouslySetInnerHTML={this.renderText(this.state.descriptionStr)} />
<div className='markdown-body' dangerouslySetInnerHTML = {{__html : this.state.descriptionStr}}/>
</div>
</div>}
overridePosition={(
{ left, top },
currentEvent, currentTarget, node, refNode) => {

const currentNode = this.props.node;
const nodeDimension = { x: currentNode.width, y: currentNode.height };
const nodePosition = { x: currentNode.getX(), y: currentNode.getY() };

let newPositionX = nodePosition.x;
let newPositionY = nodePosition.y;
let offset = 0;
Expand All @@ -346,7 +411,7 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {

if (refNode == 'top') {
newPositionX = newPositionX - 208 + offset + (nodeDimension.x / 2);
newPositionY = newPositionY - 220;
newPositionY = newPositionY + 66 - this.tooltipDescriptionRef.current.clientHeight;
}
else if (refNode == 'bottom') {
newPositionX = newPositionX - 208 + offset + (nodeDimension.x / 2);
Expand Down
16 changes: 15 additions & 1 deletion src/components/port/CustomPortLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import * as React from 'react';
import { DiagramEngine, PortWidget } from '@projectstorm/react-diagrams-core';
import { DefaultNodeModel, DefaultPortModel } from "@projectstorm/react-diagrams";
import styled from '@emotion/styled';
import WithToggle from "./WithToggle";


export interface CustomPortLabelProps {
port: DefaultPortModel;
engine: DiagramEngine;
node: DefaultNodeModel;
showDescription: boolean;
setShowDescription: any;
setDescriptionStr: (string: any) => any;
description : string;
}

namespace S {
Expand Down Expand Up @@ -123,7 +129,15 @@ export class CustomPortLabel extends React.Component<CustomPortLabelProps> {

const label = (
<S.Label>
{this.props.port.getOptions().label}
<WithToggle
renderToggleBeforeChildren={!this.props.port.getOptions().in}
showDescription={this.props.showDescription}
setShowDescription={this.props.setShowDescription}
description={this.props.description}
setDescriptionStr={this.props.setDescriptionStr(this.props.port.getOptions().label)}
>
{this.props.port.getOptions().label}
</WithToggle>
</S.Label>);

return (
Expand Down
11 changes: 11 additions & 0 deletions src/components/port/CustomPortModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ import {PortModel} from "@projectstorm/react-diagrams-core";
*/
export class CustomPortModel extends DefaultPortModel {

private _description : string;

get description(): string {
return this._description;
}

set description(value: string) {
this._description = value;
}



canLinkToPort(port: PortModel): boolean {
if (port instanceof DefaultPortModel) {
Expand Down
50 changes: 50 additions & 0 deletions src/components/port/WithToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as React from "react";
import Toggle from 'react-toggle'
import {useCallback, useRef} from "react";
import {WithToggleProps} from "./types";


export default function WithToggle(props: WithToggleProps){
const ref = useRef(null);

const changeHandler = useCallback(async () => {
await props.setShowDescription(!props.showDescription)
await props.setDescriptionStr(props.description)
}, [props.description, props.showDescription])

return (
<div ref ={ref} className="alignToggle">
{props.renderToggleBeforeChildren ?
<>
{
props.description &&
<Toggle
className='description'
name='Description'
checked={props.showDescription}
onChange={changeHandler}
/>
}
<span style={{display: "inline-block", paddingLeft: "0.3rem"}}>
{props.children}
</span>
</>
:
<>
<span style={{display: "inline-block", paddingRight: "0.3rem"}}>
{props.children}
</span>
{
props.description &&
<Toggle
className='description'
name='Description'
checked={props.showDescription}
onChange={changeHandler}
/>
}
</>
}
</div>
)
}
14 changes: 14 additions & 0 deletions src/components/port/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {ReactElement} from "react";

export type WithToggleProps = {
renderToggleBeforeChildren : boolean;
children: ReactElement[] | ReactElement | string;
showDescription: boolean;
setShowDescription: any;
setDescriptionStr: (param: string) => void;
description: string;
}

export type WithToggleState = {
showDescription : boolean
}
20 changes: 13 additions & 7 deletions src/tray_library/AdvanceComponentLib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export function AdvancedComponentLibrary(props: AdvancedComponentLibraryProps) {
extras: {
"type": nodeData.type,
"path": nodeData.file_path,
"description": nodeData.docstring,
"description": nodeData["json_description"]["description"] || nodeData.docstring,
"argumentDescriptions" : nodeData["json_description"]["arguments"],
"lineNo": nodeData.lineno
}
});
Expand All @@ -44,19 +45,24 @@ export function AdvancedComponentLibrary(props: AdvancedComponentLibraryProps) {
"str": "string"
}

nodeData["variables"].forEach(variable => {
let name = variable["name"];
let type = type_name_remappings[variable["type"]] || variable["type"];
const argumentDescriptions = nodeData["json_description"]["arguments"];


nodeData["variables"].forEach((variable, _) => {
const name = variable["name"];
const type = type_name_remappings[variable["type"]] || variable["type"];

const description = argumentDescriptions ? argumentDescriptions[name] || "" : "";

switch (variable["kind"]) {
case "InCompArg":
node.addInPortEnhance(`★${name}`, `parameter-${type}-${name}`);
node.addInPortEnhance(`★${name}`, `parameter-${type}-${name}`, true, null, description);
break;
case "InArg":
node.addInPortEnhance(name, `parameter-${type}-${name}`);
node.addInPortEnhance(name, `parameter-${type}-${name}`, true, null, description);
break;
case "OutArg":
node.addOutPortEnhance(name, `parameter-out-${type}-${name}`);
node.addOutPortEnhance(name, `parameter-out-${type}-${name}`, true, null, description);
break;
case "BaseComponent":
node.addOutPortEnhance(`${name} ▶`, `out-flow-${name}`);
Expand Down
5 changes: 3 additions & 2 deletions style/ComponentInfo.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
}

.description-container{
width: 450px;
height: 250px;
width: 600px;
max-height: 250px;
overflow: auto;
display: inline-block;
}

.description-title{
Expand Down
13 changes: 13 additions & 0 deletions style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,17 @@ input[type=number]::-webkit-inner-spin-button {
/* Fix arrow position of HTMLSelect tag on run dialog */
.jp-Dialog-content .f1ozlkqi {
position: relative;
}

.alignToggle {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}

.alignToggle span {
display: inline-block;
padding: 0;
margin: 0;
}
Loading

0 comments on commit 70f585f

Please sign in to comment.