Skip to content

Commit 70f585f

Browse files
rarescodemartpopaula937
authored andcommitted
WID-100: add functionality to display the description of the component arguments
1 parent 8c14590 commit 70f585f

File tree

13 files changed

+468
-248
lines changed

13 files changed

+468
-248
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,8 @@ tsconfig.tsbuildinfo
143143

144144
# .py files compiled by Xircuits
145145
examples/*.py
146+
147+
# pycharm files
148+
/.idea/
149+
150+
xai_components/*/arguments

src/components/CustomNodeModel.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ export class CustomNodeModel extends DefaultNodeModel {
4141
this.extras=event.data.extras;
4242
}
4343

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

4646
//check if portID is passed, if not SR will generate a new port ID
4747
const p = (id) ? new CustomPortModel({in: false, name: name, label: label, id:id}) :
4848
new CustomPortModel({in: false, name: name, label: label});
49+
50+
p.description = description;
4951

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

57-
addInPortEnhance(label: string, name: string, after: boolean = true, id?: string): CustomPortModel {
59+
addInPortEnhance(label: string, name: string, after: boolean = true, id?: string, description: string = ""): CustomPortModel {
5860

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

65+
p.description = description;
66+
6367
if (!after) {
6468
this.portsOut.splice(0, 0, p);
6569
}

src/components/CustomNodeWidget.tsx

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ export interface DefaultNodeProps {
102102
*/
103103
export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
104104

105-
generatePort = (port) => {
106-
return <CustomPortLabel engine={this.props.engine} port={port} key={port.getID()} node={this.props.node} />;
107-
};
105+
portsNo = this.props.node.getInPorts().length + this.props.node.getOutPorts().length;
106+
107+
tooltipDescriptionRef = React.createRef<HTMLDivElement>();
108+
108109
element:Object;
109110
state = {
110111

@@ -127,7 +128,63 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
127128
original: 'https://picsum.photos/id/1019/1000/600/',
128129
thumbnail: 'https://picsum.photos/id/1019/250/150/'
129130
},
130-
]
131+
],
132+
showParamDescriptionList: new Array(this.portsNo).fill(false),
133+
paramName: ""
134+
};
135+
136+
/**
137+
* creates a particular function for each component so that it can set only it's state
138+
* @param id
139+
*/
140+
setShowParamDescription = (id : number) => {
141+
const _setShowParamDescription = (newShowDescription : boolean) => {
142+
this.setState({
143+
showParamDescriptionList: this.state.showParamDescriptionList.map((value, index) => (
144+
id === index ? newShowDescription : false
145+
)
146+
),
147+
showDescription: false
148+
})
149+
}
150+
return _setShowParamDescription;
151+
}
152+
153+
setDescriptionStr = (paramName: string) => {
154+
const _setDescriptionStr = async (descriptionStr : string) => {
155+
await this.setState({
156+
descriptionStr : descriptionStr,
157+
paramName: paramName
158+
});
159+
ReactTooltip.show(this.element as Element);
160+
}
161+
return _setDescriptionStr;
162+
}
163+
164+
generatePort = (port, index) => {
165+
const argumentDescriptions = this.props.node['extras']['argumentDescriptions'];
166+
167+
// remove the ☆ from the beginning of the label
168+
const name = port.getOptions().label[0] === "★" ? port.getOptions().label.slice(1) : port.getOptions().label;
169+
170+
const description = argumentDescriptions && (name in argumentDescriptions) ? argumentDescriptions[name] : "";
171+
172+
const isOutPort = port.getOptions().name.includes('parameter-out');
173+
174+
index = isOutPort ? index + this.props.node.getInPorts().length: index;
175+
176+
return (
177+
<CustomPortLabel
178+
engine={this.props.engine}
179+
port={port}
180+
key={port.getID()}
181+
node={this.props.node}
182+
showDescription={this.state.showParamDescriptionList[index]}
183+
setShowDescription={this.setShowParamDescription(index)}
184+
setDescriptionStr = {this.setDescriptionStr}
185+
description={description}
186+
/>
187+
);
131188
};
132189

133190
showTooltip() {
@@ -206,8 +263,12 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
206263
* Show/Hide Component's Description Tooltip
207264
*/
208265
async handleDescription() {
209-
await this.setState({ showDescription: !this.state.showDescription });
210-
this.getDescriptionStr();
266+
await this.setState({
267+
showDescription: !this.state.showDescription,
268+
showParamDescriptionList: new Array(this.portsNo).fill(false),
269+
paramName: ""
270+
});
271+
await this.getDescriptionStr();
211272
ReactTooltip.show(this.element as Element);
212273
}
213274

@@ -234,7 +295,7 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
234295
delete this.props.node.getOptions().extras["tip"];
235296
this.props.node.getOptions().extras["borderColor"]="rgb(0,192,255)";
236297
}
237-
298+
238299
render() {
239300
if (this.props.node['extras']['type'] == 'comment') {
240301
return (
@@ -301,39 +362,43 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
301362
</S.Ports>
302363
</S.Node>
303364
{/** Description Tooltip */}
304-
{this.state.showDescription && <ReactTooltip
365+
{(this.state.showDescription || this.state.showParamDescriptionList.reduce((prev, cur) => prev || cur, false)) && <ReactTooltip
305366
id={this.props.node.getOptions().id}
306367
className='description-tooltip'
307368
arrowColor='rgb(255, 255, 255)'
308369
clickable
309-
afterShow={() => { this.setState({ showDescription: true }) }}
310-
afterHide={() => { this.setState({ showDescription: false }) }}
311370
delayHide={60000}
312-
delayUpdate={5000}
371+
delayUpdate={0}
313372
getContent={() =>
314-
<div data-no-drag style={{ cursor: 'default' }}>
373+
<div data-no-drag style={{ cursor: 'default' }} ref={this.tooltipDescriptionRef}>
315374
<button
316375
type="button"
317376
className="close"
318377
data-dismiss="modal"
319378
aria-label="Close"
320-
onClick={() => { this.setState({ showDescription: false }); }}>
379+
onClick={() => { this.setState({
380+
showDescription: false,
381+
showParamDescriptionList: new Array(this.portsNo).fill(false)
382+
}); }}
383+
>
321384
<span aria-hidden="true">&times;</span>
322385
</button>
323-
<S.DescriptionName color={this.props.node.getOptions().color}>{this.props.node.getOptions()["name"]}</S.DescriptionName>
386+
<S.DescriptionName color={this.props.node.getOptions().color}>{this.props.node.getOptions()["name"] + " " + this.state.paramName}</S.DescriptionName>
324387
<p className='description-title'>Description:</p>
325-
<div
388+
<div
326389
onWheel={(e) => e.stopPropagation()}
327390
className='description-container'>
328-
<div className='markdown-body' dangerouslySetInnerHTML={this.renderText(this.state.descriptionStr)} />
391+
<div className='markdown-body' dangerouslySetInnerHTML = {{__html : this.state.descriptionStr}}/>
329392
</div>
330393
</div>}
331394
overridePosition={(
332395
{ left, top },
333396
currentEvent, currentTarget, node, refNode) => {
397+
334398
const currentNode = this.props.node;
335399
const nodeDimension = { x: currentNode.width, y: currentNode.height };
336400
const nodePosition = { x: currentNode.getX(), y: currentNode.getY() };
401+
337402
let newPositionX = nodePosition.x;
338403
let newPositionY = nodePosition.y;
339404
let offset = 0;
@@ -346,7 +411,7 @@ export class CustomNodeWidget extends React.Component<DefaultNodeProps> {
346411

347412
if (refNode == 'top') {
348413
newPositionX = newPositionX - 208 + offset + (nodeDimension.x / 2);
349-
newPositionY = newPositionY - 220;
414+
newPositionY = newPositionY + 66 - this.tooltipDescriptionRef.current.clientHeight;
350415
}
351416
else if (refNode == 'bottom') {
352417
newPositionX = newPositionX - 208 + offset + (nodeDimension.x / 2);

src/components/port/CustomPortLabel.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import * as React from 'react';
22
import { DiagramEngine, PortWidget } from '@projectstorm/react-diagrams-core';
33
import { DefaultNodeModel, DefaultPortModel } from "@projectstorm/react-diagrams";
44
import styled from '@emotion/styled';
5+
import WithToggle from "./WithToggle";
6+
57

68
export interface CustomPortLabelProps {
79
port: DefaultPortModel;
810
engine: DiagramEngine;
911
node: DefaultNodeModel;
12+
showDescription: boolean;
13+
setShowDescription: any;
14+
setDescriptionStr: (string: any) => any;
15+
description : string;
1016
}
1117

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

124130
const label = (
125131
<S.Label>
126-
{this.props.port.getOptions().label}
132+
<WithToggle
133+
renderToggleBeforeChildren={!this.props.port.getOptions().in}
134+
showDescription={this.props.showDescription}
135+
setShowDescription={this.props.setShowDescription}
136+
description={this.props.description}
137+
setDescriptionStr={this.props.setDescriptionStr(this.props.port.getOptions().label)}
138+
>
139+
{this.props.port.getOptions().label}
140+
</WithToggle>
127141
</S.Label>);
128142

129143
return (

src/components/port/CustomPortModel.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ import {PortModel} from "@projectstorm/react-diagrams-core";
88
*/
99
export class CustomPortModel extends DefaultPortModel {
1010

11+
private _description : string;
12+
13+
get description(): string {
14+
return this._description;
15+
}
16+
17+
set description(value: string) {
18+
this._description = value;
19+
}
20+
21+
1122

1223
canLinkToPort(port: PortModel): boolean {
1324
if (port instanceof DefaultPortModel) {

src/components/port/WithToggle.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from "react";
2+
import Toggle from 'react-toggle'
3+
import {useCallback, useRef} from "react";
4+
import {WithToggleProps} from "./types";
5+
6+
7+
export default function WithToggle(props: WithToggleProps){
8+
const ref = useRef(null);
9+
10+
const changeHandler = useCallback(async () => {
11+
await props.setShowDescription(!props.showDescription)
12+
await props.setDescriptionStr(props.description)
13+
}, [props.description, props.showDescription])
14+
15+
return (
16+
<div ref ={ref} className="alignToggle">
17+
{props.renderToggleBeforeChildren ?
18+
<>
19+
{
20+
props.description &&
21+
<Toggle
22+
className='description'
23+
name='Description'
24+
checked={props.showDescription}
25+
onChange={changeHandler}
26+
/>
27+
}
28+
<span style={{display: "inline-block", paddingLeft: "0.3rem"}}>
29+
{props.children}
30+
</span>
31+
</>
32+
:
33+
<>
34+
<span style={{display: "inline-block", paddingRight: "0.3rem"}}>
35+
{props.children}
36+
</span>
37+
{
38+
props.description &&
39+
<Toggle
40+
className='description'
41+
name='Description'
42+
checked={props.showDescription}
43+
onChange={changeHandler}
44+
/>
45+
}
46+
</>
47+
}
48+
</div>
49+
)
50+
}

src/components/port/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {ReactElement} from "react";
2+
3+
export type WithToggleProps = {
4+
renderToggleBeforeChildren : boolean;
5+
children: ReactElement[] | ReactElement | string;
6+
showDescription: boolean;
7+
setShowDescription: any;
8+
setDescriptionStr: (param: string) => void;
9+
description: string;
10+
}
11+
12+
export type WithToggleState = {
13+
showDescription : boolean
14+
}

src/tray_library/AdvanceComponentLib.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export function AdvancedComponentLibrary(props: AdvancedComponentLibraryProps) {
3131
extras: {
3232
"type": nodeData.type,
3333
"path": nodeData.file_path,
34-
"description": nodeData.docstring,
34+
"description": nodeData["json_description"]["description"] || nodeData.docstring,
35+
"argumentDescriptions" : nodeData["json_description"]["arguments"],
3536
"lineNo": nodeData.lineno
3637
}
3738
});
@@ -44,19 +45,24 @@ export function AdvancedComponentLibrary(props: AdvancedComponentLibraryProps) {
4445
"str": "string"
4546
}
4647

47-
nodeData["variables"].forEach(variable => {
48-
let name = variable["name"];
49-
let type = type_name_remappings[variable["type"]] || variable["type"];
48+
const argumentDescriptions = nodeData["json_description"]["arguments"];
49+
50+
51+
nodeData["variables"].forEach((variable, _) => {
52+
const name = variable["name"];
53+
const type = type_name_remappings[variable["type"]] || variable["type"];
54+
55+
const description = argumentDescriptions ? argumentDescriptions[name] || "" : "";
5056

5157
switch (variable["kind"]) {
5258
case "InCompArg":
53-
node.addInPortEnhance(`★${name}`, `parameter-${type}-${name}`);
59+
node.addInPortEnhance(`★${name}`, `parameter-${type}-${name}`, true, null, description);
5460
break;
5561
case "InArg":
56-
node.addInPortEnhance(name, `parameter-${type}-${name}`);
62+
node.addInPortEnhance(name, `parameter-${type}-${name}`, true, null, description);
5763
break;
5864
case "OutArg":
59-
node.addOutPortEnhance(name, `parameter-out-${type}-${name}`);
65+
node.addOutPortEnhance(name, `parameter-out-${type}-${name}`, true, null, description);
6066
break;
6167
case "BaseComponent":
6268
node.addOutPortEnhance(`${name} ▶`, `out-flow-${name}`);

style/ComponentInfo.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
}
88

99
.description-container{
10-
width: 450px;
11-
height: 250px;
10+
width: 600px;
11+
max-height: 250px;
1212
overflow: auto;
13+
display: inline-block;
1314
}
1415

1516
.description-title{

style/base.css

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,17 @@ input[type=number]::-webkit-inner-spin-button {
5454
/* Fix arrow position of HTMLSelect tag on run dialog */
5555
.jp-Dialog-content .f1ozlkqi {
5656
position: relative;
57+
}
58+
59+
.alignToggle {
60+
display: flex;
61+
flex-direction: row;
62+
align-items: center;
63+
justify-content: flex-start;
64+
}
65+
66+
.alignToggle span {
67+
display: inline-block;
68+
padding: 0;
69+
margin: 0;
5770
}

0 commit comments

Comments
 (0)