Skip to content

Commit

Permalink
Merge pull request #422 from nipunayf/improve-connection-search
Browse files Browse the repository at this point in the history
Enhance the connector search functionality
  • Loading branch information
nipunayf authored Oct 3, 2024
2 parents e7d03a1 + de095d7 commit 06c98c0
Show file tree
Hide file tree
Showing 147 changed files with 2,342 additions and 8,090 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@
import io.ballerina.compiler.syntax.tree.Node;
import io.ballerina.compiler.syntax.tree.NonTerminalNode;
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.flowmodelgenerator.core.central.ConnectorResponse;
import io.ballerina.flowmodelgenerator.core.central.LocalIndexCentral;
import io.ballerina.flowmodelgenerator.core.central.RemoteCentral;
import io.ballerina.flowmodelgenerator.core.model.AvailableNode;
import io.ballerina.flowmodelgenerator.core.model.Category;
import io.ballerina.flowmodelgenerator.core.model.Codedata;
import io.ballerina.flowmodelgenerator.core.model.Item;
import io.ballerina.flowmodelgenerator.core.model.Metadata;
import io.ballerina.flowmodelgenerator.core.model.NodeBuilder;
import io.ballerina.flowmodelgenerator.core.model.NodeKind;
import io.ballerina.flowmodelgenerator.core.model.node.NewConnection;
import io.ballerina.projects.Document;
import io.ballerina.tools.text.LinePosition;
import io.ballerina.tools.text.TextRange;
Expand Down Expand Up @@ -137,6 +141,7 @@ private void setDefaultNodes() {
.stepIn(Category.Name.STATEMENT)
.node(NodeKind.ASSIGN)
.node(function)
.node(NodeKind.DATA_MAPPER)
.stepOut()
.stepIn(Category.Name.CONTROL)
.node(NodeKind.IF)
Expand All @@ -149,18 +154,19 @@ private void setDefaultNodes() {
.node(NodeKind.JSON_PAYLOAD)
.node(NodeKind.XML_PAYLOAD)
.node(NodeKind.BINARY_DATA)
.node(NodeKind.DATA_MAPPER)
.stepOut()
.stepIn(Category.Name.ERROR_HANDLING)
.node(NodeKind.ERROR_HANDLER)
// TODO: Uncomment when error handling is implemented
// .node(NodeKind.ERROR_HANDLER)
.node(NodeKind.FAIL)
.node(NodeKind.PANIC)
.stepOut()
.stepIn(Category.Name.CONCURRENCY)
.node(NodeKind.TRANSACTION)
.node(NodeKind.LOCK)
.node(NodeKind.START)
.stepOut();
// TODO: Uncomment when concurrency is implemented
// .stepIn(Category.Name.CONCURRENCY)
// .node(NodeKind.TRANSACTION)
// .node(NodeKind.LOCK)
// .node(NodeKind.START)
// .stepOut();
}

private void setStopNode(NonTerminalNode node) {
Expand Down Expand Up @@ -203,11 +209,16 @@ private Optional<Category> getConnection(Symbol symbol) {
.node(NodeKind.NEW_CONNECTION)
.org(moduleSymbol.id().orgName())
.module(moduleSymbol.getName().orElseThrow())
.version(moduleSymbol.id().version())
.object("Client")
.symbol("init")
.build();
List<Item> connections = LocalIndexCentral.getInstance().getConnectorActions(codedata);

if (connections == null) {
connections = fetchConnections(codedata);
}

Metadata metadata = new Metadata.Builder<>(null)
.label(symbol.getName().orElseThrow())
.build();
Expand All @@ -216,4 +227,32 @@ private Optional<Category> getConnection(Symbol symbol) {
return Optional.empty();
}
}

private static List<Item> fetchConnections(Codedata codedata) {
List<Item> connectorActions = new ArrayList<>();
ConnectorResponse connector = RemoteCentral.getInstance()
.connector(codedata.org(), codedata.module(), codedata.version(), codedata.object());
for (ConnectorResponse.Function function : connector.functions()) {
if (function.name().equals(NewConnection.INIT_SYMBOL)) {
continue;
}
NodeBuilder actionBuilder = NodeBuilder.getNodeFromKind(NodeKind.ACTION_CALL);
actionBuilder
.metadata()
.label(function.name())
.icon(connector.icon())
.description(function.documentation())
.stepOut()
.codedata()
.node(NodeKind.ACTION_CALL)
.org(codedata.org())
.module(codedata.module())
.object(codedata.object())
.id(String.valueOf(connector.id()))
.symbol(function.name());
connectorActions.add(actionBuilder.buildAvailableNode());
}
return connectorActions;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import io.ballerina.flowmodelgenerator.core.model.NodeBuilder;
import io.ballerina.flowmodelgenerator.core.model.NodeKind;
import io.ballerina.flowmodelgenerator.core.model.Property;
import io.ballerina.flowmodelgenerator.core.model.node.ActionCall;
import io.ballerina.flowmodelgenerator.core.model.node.Assign;
import io.ballerina.flowmodelgenerator.core.model.node.BinaryData;
import io.ballerina.flowmodelgenerator.core.model.node.DataMapper;
Expand Down Expand Up @@ -257,9 +258,10 @@ private void handleActionNode(ActionNode actionNode, String methodName, Expressi
.org(orgName)
.module(moduleName)
.object("Client")
.version(symbol.get().getModule().get().id().version())
.symbol(methodName)
.build();
FlowNode nodeTemplate = LocalIndexCentral.getInstance().getNodeTemplate(codedata);
FlowNode nodeTemplate = ActionCall.getNodeTemplate(codedata);
if (nodeTemplate == null) {
handleExpressionNode(actionNode);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.compiler.syntax.tree.SyntaxTree;
import io.ballerina.compiler.syntax.tree.TypedBindingPatternNode;
import io.ballerina.flowmodelgenerator.core.central.ConnectorResponse;
import io.ballerina.projects.Document;
import io.ballerina.tools.text.LinePosition;
import io.ballerina.tools.text.LineRange;
Expand Down Expand Up @@ -298,4 +299,11 @@ public static TypeSymbol getRawType(TypeSymbol typeDescriptor) {
}
return typeDescriptor;
}

public static Object getTypeConstraint(ConnectorResponse.Parameter param, String typeName) {
return switch (typeName) {
case "inclusion" -> param.inclusionType();
default -> typeName;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ public JsonElement getFlowModel() {
semanticModel.visibleSymbols(document, canvasNode.lineRange().startLine()).stream()
.flatMap(symbol -> buildConnection(syntaxTree, symbol, textDocument).stream())
.sorted(Comparator.comparing(
node -> node.properties().get(Property.VARIABLE_KEY).value().toString()))
node -> Optional.ofNullable(node.properties().get(Property.VARIABLE_KEY))
.map(property -> property.value().toString())
.orElse("")))
.toList();

// Obtain the data mapping function names
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public ConnectorResponse connector(String id) {
}

public ConnectorResponse connector(String org, String module, String version, String connector) {
String path = String.format("connectors/%s/%s/%s/%s/%s", org, module, version, module, connector);
String path = String.format("%s/connectors/%s/%s/%s/%s/%s", BASE_URL, org, module, version, module, connector);
String response = query(path);
return gson.fromJson(response, ConnectorResponse.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ public <T> T valueAsType(TypeToken<T> typeToken) {
public static final String COLLECTION_KEY = "collection";
public static final String COLLECTION_DOC = "Collection to iterate";

public static final String DATA_VARIABLE_LABEL = "Data variable";
public static final String DATA_VARIABLE_LABEL = "Variable";
public static final String DATA_VARIABLE_KEY = "variable";
public static final String DATA_VARIABLE_DOC = "Name of the variable";

public static final String DATA_TYPE_LABEL = "Data type";
public static final String DATA_TYPE_LABEL = "Type";
public static final String DATA_TYPE_KEY = "type";
public static final String DATA_TYPE_DOC = "Type of the variable";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ public TokenBuilder expression(Property property) {
}

public TokenBuilder expressionWithType(Property type, Property variable) {
sb.append(type.toSourceCode()).append(WHITE_SPACE).append(variable.toSourceCode()).append(WHITE_SPACE);
String typeSourceCode = type.toSourceCode();
int lastDotIndex = typeSourceCode.lastIndexOf('.');
String typeName = lastDotIndex >= 0 ? typeSourceCode.substring(lastDotIndex + 1) : type.toSourceCode();
sb.append(typeName).append(WHITE_SPACE).append(variable.toSourceCode()).append(WHITE_SPACE);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
package io.ballerina.flowmodelgenerator.core.model.node;

import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.flowmodelgenerator.core.CommonUtils;
import io.ballerina.flowmodelgenerator.core.central.ConnectorResponse;
import io.ballerina.flowmodelgenerator.core.central.LocalIndexCentral;
import io.ballerina.flowmodelgenerator.core.central.RemoteCentral;
import io.ballerina.flowmodelgenerator.core.model.Codedata;
import io.ballerina.flowmodelgenerator.core.model.FlowNode;
import io.ballerina.flowmodelgenerator.core.model.NodeBuilder;
import io.ballerina.flowmodelgenerator.core.model.NodeKind;
Expand Down Expand Up @@ -60,6 +64,13 @@ public Map<Path, List<TextEdit>> toSource(SourceBuilder sourceBuilder) {
}

FlowNode nodeTemplate = LocalIndexCentral.getInstance().getNodeTemplate(sourceBuilder.flowNode.codedata());
if (nodeTemplate == null) {
nodeTemplate = fetchNodeTemplate(NodeBuilder.getNodeFromKind(NodeKind.ACTION_CALL),
sourceBuilder.flowNode.codedata());
}
if (nodeTemplate == null) {
throw new IllegalStateException("Action call node template not found");
}

Optional<Property> connection = sourceBuilder.flowNode.getProperty(Property.CONNECTION_KEY);
if (connection.isEmpty()) {
Expand All @@ -77,8 +88,72 @@ public Map<Path, List<TextEdit>> toSource(SourceBuilder sourceBuilder) {
.build();
}

private static FlowNode fetchNodeTemplate(NodeBuilder nodeBuilder, Codedata codedata) {
if (codedata.org().equals("$anon")) {
return null;
}

ConnectorResponse connector = codedata.id() != null ? RemoteCentral.getInstance().connector(codedata.id()) :
RemoteCentral.getInstance()
.connector(codedata.org(), codedata.module(), codedata.version(), codedata.object());

if (connector == null) {
return null;
}

Optional<ConnectorResponse.Function> optFunction = connector.functions().stream()
.filter(f -> f.name().equals(codedata.symbol()))
.findFirst();
if (optFunction.isEmpty()) {
return null;
}
nodeBuilder
.metadata()
.label(optFunction.get().name())
.icon(connector.icon())
.description(optFunction.get().documentation())
.stepOut()
.codedata()
.org(codedata.org())
.module(codedata.module())
.object(codedata.object())
.id(codedata.id())
.symbol(codedata.symbol());

for (ConnectorResponse.Parameter param : optFunction.get().parameters()) {
nodeBuilder.properties().custom(param.name(), param.name(), param.documentation(),
Property.valueTypeFrom(param.typeName()),
CommonUtils.getTypeConstraint(param, param.typeName()),
CommonUtils.getDefaultValueForType(param.typeName()), param.optional());
}

String returnType = optFunction.get().returnType().typeName();
if (returnType != null) {
nodeBuilder.properties().type(returnType).data(null);
}

nodeBuilder.properties().custom(Property.CONNECTION_KEY, connector.name(), connector.documentation(),
Property.ValueType.EXPRESSION, connector.moduleName() + ":" + connector.name(), connector.name(),
false);
return nodeBuilder.build();
}

public static FlowNode getNodeTemplate(Codedata codedata) {
FlowNode nodeTemplate = LocalIndexCentral.getInstance().getNodeTemplate(codedata);
if (nodeTemplate == null) {
return fetchNodeTemplate(NodeBuilder.getNodeFromKind(NodeKind.ACTION_CALL), codedata);
}
return nodeTemplate;
}

@Override
public void setConcreteTemplateData(TemplateContext context) {
this.cachedFlowNode = LocalIndexCentral.getInstance().getNodeTemplate(context.codedata());
Codedata codedata = context.codedata();
FlowNode nodeTemplate = LocalIndexCentral.getInstance().getNodeTemplate(codedata);
if (nodeTemplate != null) {
this.cachedFlowNode = nodeTemplate;
} else {
fetchNodeTemplate(this, codedata);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ public void setConcreteConstData() {
public Map<Path, List<TextEdit>> toSource(SourceBuilder sourceBuilder) {
FlowNode flowNode = sourceBuilder.flowNode;
Optional<Property> dataType = flowNode.getProperty(Property.DATA_TYPE_KEY);
dataType.ifPresent(value -> sourceBuilder.token().expression(value).whiteSpace());


if (dataType.isPresent() && !dataType.get().toSourceCode().isEmpty()) {
sourceBuilder.token().expression(dataType.get()).whiteSpace();
}

Optional<Property> variable = flowNode.getProperty(Property.VARIABLE_KEY);
if (variable.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*/
public class BinaryData extends NodeBuilder {

public static final String LABEL = "Binary Data";
public static final String LABEL = "Assign Binary";
public static final String DESCRIPTION = LABEL;
public static final String BINARY_DATA_DOC = "Create new Binary Data";
private static final String DUMMY_BINARY_DATA_EXPR = "base64 `abcd`";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*/
public class JsonPayload extends NodeBuilder {

public static final String LABEL = "JSON Payload";
public static final String LABEL = "Assign JSON";
public static final String DESCRIPTION = LABEL;
public static final String JSON_PAYLOAD_DOC = "Create new JSON payload";
private static final String DUMMY_JSON_PAYLOAD = "{\"value\": \"Dummy JSON value\"}";
Expand Down
Loading

0 comments on commit 06c98c0

Please sign in to comment.