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
4 changes: 4 additions & 0 deletions e2e/creatingASimpleGraph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ test('Creating a Simple Graph', async ({ page }) => {

//click on the input port of the file to open the parameter table modal and highlight the port
await page.locator('#hello .inputPort').click();

// set 'changeable' on the port to true
await page.locator('.highlighted .column_Flags button.changeableFlag').click();

//rename the port
await page.locator('.highlighted .tableFieldDisplayName').fill('testInput');

Expand Down
9 changes: 5 additions & 4 deletions src/Daliuge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export namespace Daliuge {
EXECUTION_TIME = "execution_time",
GROUP_START = "group_start",
GROUP_END = "group_end",
FILE_PATH = "filepath",

INPUT_ERROR_RATE = "input_error_threshold",
NUM_OF_COPIES = "num_of_copies",
Expand Down Expand Up @@ -171,8 +172,8 @@ export namespace Daliuge {
export const groupStartField = new Field(null, FieldName.GROUP_START, "true", "true", "Is this node the start of a group?", false, DataType.Boolean, false, [], false, FieldType.Component, FieldUsage.NoPort);
export const groupEndField = new Field(null, FieldName.GROUP_END, "true", "true", "Is this node the end of a group?", false, DataType.Boolean, false, [], false, FieldType.Component, FieldUsage.NoPort);

export const branchYesField = new Field(null, FieldName.TRUE, "", "", "The affirmative output from a branch node", false, DataType.Object, false, [], false, FieldType.Component, FieldUsage.OutputPort);
export const branchNoField = new Field(null, FieldName.FALSE, "", "", "he negative output from a branch node", false, DataType.Object, false, [], false, FieldType.Component, FieldUsage.OutputPort);
export const branchTrueField = new Field(null, FieldName.TRUE, "", "", "The affirmative output from a branch node", false, DataType.Object, false, [], false, FieldType.Component, FieldUsage.OutputPort);
export const branchFalseField = new Field(null, FieldName.FALSE, "", "", "The negative output from a branch node", false, DataType.Object, false, [], false, FieldType.Component, FieldUsage.OutputPort);

export const dropClassField = new Field(null, FieldName.DROP_CLASS, "", "", "", false, DataType.String, false, [], false, FieldType.Component, FieldUsage.NoPort);

Expand Down Expand Up @@ -264,8 +265,8 @@ export namespace Daliuge {
Category.Branch
],
fields: [
Daliuge.branchYesField,
Daliuge.branchNoField,
Daliuge.branchTrueField,
Daliuge.branchFalseField,
Daliuge.dropClassField
]
},
Expand Down
50 changes: 35 additions & 15 deletions src/Eagle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3824,7 +3824,9 @@ export class Eagle {
const realSourceNode: Node = RightClick.edgeDropSrcNode;
const realSourcePort: Field = RightClick.edgeDropSrcPort;
const realDestNode: Node = nodes[0];
let realDestPort = realDestNode.findPortByMatchingType(realSourcePort.getType(), !RightClick.edgeDropSrcIsInput);

const usages: Daliuge.FieldUsage[] = [RightClick.edgeDropSrcIsInput ? Daliuge.FieldUsage.OutputPort : Daliuge.FieldUsage.InputPort, Daliuge.FieldUsage.InputOutput];
let realDestPort = realDestNode.findPortByMatchingType(realSourcePort.getType(), usages);

// if no dest port was found, just use first input port on dest node
if (realDestPort === null){
Expand Down Expand Up @@ -4571,7 +4573,8 @@ export class Eagle {
if (typeof intermediaryComponent === 'undefined'){
intermediaryComponent = new Node("Data", "Data Component", "", Category.Data);
} else {
intermediaryComponent = Utils.duplicateNode(intermediaryComponent);
//intermediaryComponent = Utils.duplicateNode(intermediaryComponent);
intermediaryComponent = intermediaryComponent.clone().setId(Utils.generateNodeId());
}

// if edge DOES NOT connect two applications, process normally
Expand All @@ -4588,14 +4591,20 @@ export class Eagle {
const newName = srcPort.getDisplayText();
const newDescription = srcPort.getDescription();
destNode.setName(newName);
destPort.setDisplayText(newName);
destPort.setDescription(newDescription);

if (destPort.isChangeable()){
destPort.setDisplayText(newName);
destPort.setDescription(newDescription);
}
} else {
const newName = destPort.getDisplayText();
const newDescription = destPort.getDescription();
srcNode.setName(newName);
srcPort.setDisplayText(newName);
srcPort.setDescription(newDescription);

if (srcPort.isChangeable()){
srcPort.setDisplayText(newName);
srcPort.setDescription(newDescription);
}
}
}

Expand Down Expand Up @@ -4629,18 +4638,29 @@ export class Eagle {
};

// Add the intermediary component to the graph
const newNode : Node = this.logicalGraph().addDataComponentToGraph(intermediaryComponent, dataComponentPosition);
//const newNode : Node = this.logicalGraph().addDataComponentToGraph(intermediaryComponent, dataComponentPosition); // DOESN't WORK!! io port is not rendered
const newNode = (await this.addNodeToLogicalGraph(intermediaryComponent, Utils.generateNodeId(), Eagle.AddNodeMode.Default))[0]; // WORKS!! (just location is not used)

newNode.setPosition(dataComponentPosition.x, dataComponentPosition.y);

// set name of new node (use user-facing name)
newNode.setName(srcPort.getDisplayText());

// remove existing ports from the memory node
newNode.removeAllInputPorts();
newNode.removeAllOutputPorts();

// add InputOutput port for dataType
const newInputOutputPort = new Field(Utils.generateFieldId(), srcPort.getDisplayText(), "", "", srcPort.getDescription(), false, srcPort.getType(), false, [], false, Daliuge.FieldType.Application, Daliuge.FieldUsage.InputOutput);
newNode.addField(newInputOutputPort);

// find InputOutput port on node, which matches the source port dataType
const inputOutputPort = newNode.findPortByMatchingType(srcPort.getType(), [Daliuge.FieldUsage.InputOutput]);
if (inputOutputPort === null){
Utils.showNotification("Add Edge Error", "Unable to find suitable port on intermediary component", "danger");
reject("Unable to find suitable port on intermediary component");
return;
}

// if the port is changeable, set its display text and description to match the source port
if (inputOutputPort.isChangeable()){
inputOutputPort.setDisplayText(srcPort.getDisplayText());
inputOutputPort.setDescription(srcPort.getDescription());
}

// set the parent of the new node
// by default, set parent to parent of dest node,
Expand All @@ -4657,8 +4677,8 @@ export class Eagle {
}

// create TWO edges, one from src to data component, one from data component to dest
const firstEdge : Edge = new Edge('', srcNode, srcPort, newNode, newInputOutputPort, loopAware, closesLoop, false);
const secondEdge : Edge = new Edge('', newNode, newInputOutputPort, destNode, destPort, loopAware, closesLoop, false);
const firstEdge : Edge = new Edge('', srcNode, srcPort, newNode, inputOutputPort, loopAware, closesLoop, false);
const secondEdge : Edge = new Edge('', newNode, inputOutputPort, destNode, destPort, loopAware, closesLoop, false);

this.logicalGraph().addEdgeComplete(firstEdge);
this.logicalGraph().addEdgeComplete(secondEdge);
Expand Down
28 changes: 25 additions & 3 deletions src/Field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export class Field {
private node : ko.Observable<Node>;
private edges: ko.Observable<Map<EdgeId, Edge>>;

// run-time only attributes
private changeable : ko.Observable<boolean>;

// graph related attributes
private inputX : ko.Observable<number>;
private inputY : ko.Observable<number>;
Expand Down Expand Up @@ -65,6 +68,9 @@ export class Field {
this.node = ko.observable(null);
this.edges = ko.observable(new Map<EdgeId, Edge>());

// run-time only attributes
this.changeable = ko.observable(true); // whether the field can be renamed or not

//graph related things
this.inputX = ko.observable(0);
this.inputY = ko.observable(0);
Expand Down Expand Up @@ -240,6 +246,15 @@ export class Field {
return this.precious();
}

isChangeable = () : boolean => {
return this.changeable();
}

toggleChangeable = () : Field => {
this.changeable(!this.changeable());
return this;
}

updateEdgeId(oldId: EdgeId, newId: EdgeId): void {
const edge = this.edges().get(oldId);

Expand Down Expand Up @@ -465,6 +480,7 @@ export class Field {
this.isEvent(false);
this.node(null);
this.edges().clear();
this.changeable(true);

return this;
}
Expand All @@ -478,6 +494,7 @@ export class Field {
const f = new Field(this.id(), this.displayText(), this.value(), this.defaultValue(), this.description(), this.readonly(), this.type(), this.precious(), options, this.positional(), this.parameterType(), this.usage());
f.encoding(this.encoding());
f.isEvent(this.isEvent());
f.changeable(this.changeable());
f.node(this.node());
f.edges(new Map<EdgeId, Edge>());
for (const edge of this.edges().values()) {
Expand Down Expand Up @@ -506,6 +523,7 @@ export class Field {
f.isEvent = this.isEvent;
f.node = this.node;
f.edges = this.edges;
f.changeable = this.changeable;

return f;
}
Expand Down Expand Up @@ -544,6 +562,7 @@ export class Field {
this.usage(src.usage());
this.encoding(src.encoding());
this.isEvent(src.isEvent());
this.changeable(src.changeable());

// NOTE: these two are not copied from the src, but come from the function's parameters
this.id(id);
Expand Down Expand Up @@ -791,7 +810,7 @@ export class Field {
};
}

static fromOJSJson(data : any) : Field {
static fromOJSJson(data : any, changeable: boolean) : Field {
let id: FieldId = Utils.generateFieldId();
let name: string = "";
let description: string = "";
Expand Down Expand Up @@ -879,10 +898,11 @@ export class Field {
const result = new Field(id, name, value, defaultValue, description, readonly, type, precious, options, positional, parameterType, usage);
result.isEvent(isEvent);
result.encoding(encoding);
result.changeable(changeable);
return result;
}

static fromOJSJsonPort(data : any) : Field {
static fromOJSJsonPort(data : any, changeable: boolean) : Field {
let name: string = "";
let event: boolean = false;
let type: Daliuge.DataType = Daliuge.DataType.Unknown;
Expand All @@ -908,10 +928,11 @@ export class Field {
const f = new Field(data.Id, name, "", "", description, false, type, false, [], false, Daliuge.FieldType.Unknown, Daliuge.FieldUsage.NoPort);
f.isEvent(event);
f.encoding(encoding);
f.changeable(changeable);
return f;
}

static fromV4Json(data: any): Field {
static fromV4Json(data: any, changeable: boolean): Field {
let id: FieldId;
let name: string;
let value: string;
Expand Down Expand Up @@ -961,6 +982,7 @@ export class Field {
const f = new Field(id, name, value, defaultValue, description, readonly, type, precious, options, positional, parameterType, usage);
f.isEvent(event);
f.encoding(encoding);
f.changeable(changeable);
return f;
}

Expand Down
37 changes: 13 additions & 24 deletions src/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -933,21 +933,10 @@ export class Node {
return null;
}


findPortByMatchingType = (type: string, input: boolean) : Field | null => {
if (input){
// check input ports
for (const inputPort of this.getInputPorts()){
if (Utils.typesMatch(inputPort.getType(), type)){
return inputPort;
}
}
} else {
// check output ports
for (const outputPort of this.getOutputPorts()){
if (Utils.typesMatch(outputPort.getType(), type)){
return outputPort;
}
findPortByMatchingType = (type: string, usages: Daliuge.FieldUsage[]) : Field | null => {
for (const port of this.getFields()){
if (usages.includes(port.getUsage()) && Utils.typesMatch(port.getType(), type)){
return port;
}
}
return null;
Expand Down Expand Up @@ -1596,7 +1585,7 @@ export class Node {
// add fields
if (typeof nodeData.fields !== 'undefined'){
for (const fieldData of nodeData.fields){
const field = Field.fromOJSJson(fieldData);
const field = Field.fromOJSJson(fieldData, !isPaletteNode);

// if the parameter type is not specified, assume it is a ComponentParameter
if (field.getParameterType() === Daliuge.FieldType.Unknown){
Expand All @@ -1610,7 +1599,7 @@ export class Node {
// add application params
if (typeof nodeData.applicationArgs !== 'undefined'){
for (const paramData of nodeData.applicationArgs){
const field = Field.fromOJSJson(paramData);
const field = Field.fromOJSJson(paramData, !isPaletteNode);
field.setParameterType(Daliuge.FieldType.Application);
node.addField(field);
}
Expand All @@ -1620,7 +1609,7 @@ export class Node {
if (typeof nodeData.inputAppFields !== 'undefined'){
for (const fieldData of nodeData.inputAppFields){
if (node.hasInputApplication()){
const field = Field.fromOJSJson(fieldData);
const field = Field.fromOJSJson(fieldData, !isPaletteNode);
node.inputApplication().addField(field);
} else {
errorsWarnings.errors.push(Errors.Message("Can't add input app field " + fieldData.text + " to node " + node.getName() + ". No input application."));
Expand All @@ -1632,7 +1621,7 @@ export class Node {
if (typeof nodeData.outputAppFields !== 'undefined'){
for (const fieldData of nodeData.outputAppFields){
if (node.hasOutputApplication()){
const field = Field.fromOJSJson(fieldData);
const field = Field.fromOJSJson(fieldData, !isPaletteNode);
node.outputApplication().addField(field);
} else {
errorsWarnings.errors.push(Errors.Message("Can't add output app field " + fieldData.text + " to node " + node.getName() + ". No output application."));
Expand All @@ -1643,7 +1632,7 @@ export class Node {
// add input ports
if (typeof nodeData.inputPorts !== 'undefined'){
for (const inputPort of nodeData.inputPorts){
const port = Field.fromOJSJsonPort(inputPort);
const port = Field.fromOJSJsonPort(inputPort, !isPaletteNode);
port.setParameterType(Daliuge.FieldType.Application);
port.setUsage(Daliuge.FieldUsage.InputPort);

Expand All @@ -1662,7 +1651,7 @@ export class Node {
// add output ports
if (typeof nodeData.outputPorts !== 'undefined'){
for (const outputPort of nodeData.outputPorts){
const port = Field.fromOJSJsonPort(outputPort);
const port = Field.fromOJSJsonPort(outputPort, !isPaletteNode);
port.setParameterType(Daliuge.FieldType.Application);
port.setUsage(Daliuge.FieldUsage.OutputPort);

Expand All @@ -1682,7 +1671,7 @@ export class Node {
if (typeof nodeData.inputLocalPorts !== 'undefined'){
for (const inputLocalPort of nodeData.inputLocalPorts){
if (node.hasInputApplication()){
const port = Field.fromOJSJsonPort(inputLocalPort);
const port = Field.fromOJSJsonPort(inputLocalPort, !isPaletteNode);
port.setParameterType(Daliuge.FieldType.Application);
port.setUsage(Daliuge.FieldUsage.OutputPort);

Expand All @@ -1696,7 +1685,7 @@ export class Node {
// add output local ports
if (typeof nodeData.outputLocalPorts !== 'undefined'){
for (const outputLocalPort of nodeData.outputLocalPorts){
const port = Field.fromOJSJsonPort(outputLocalPort);
const port = Field.fromOJSJsonPort(outputLocalPort, !isPaletteNode);
port.setParameterType(Daliuge.FieldType.Application);
port.setUsage(Daliuge.FieldUsage.InputPort);

Expand Down Expand Up @@ -1750,7 +1739,7 @@ export class Node {

// add fields
for (const [id, fieldData] of Object.entries(nodeData.fields)){
const field = Field.fromV4Json(fieldData);
const field = Field.fromV4Json(fieldData, !isPaletteNode);
node.addField(field);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class Palette {

// add nodes
for (const [nodeId, nodeData] of Object.entries(dataObject.nodes)){
const node = Node.fromV4Json(nodeData, errorsWarnings, false);
const node = Node.fromV4Json(nodeData, errorsWarnings, true);

result.nodes().set(nodeId as NodeId, node);
result.nodes.valueHasMutated();
Expand Down
2 changes: 1 addition & 1 deletion static/tables.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
}

.parameter_table_flags{
width: 101px;
width: 121px;
}

.parameter_table_actions{
Expand Down
Loading