diff --git a/connectors/asana/element-templates/asana-connector.json b/connectors/asana/element-templates/asana-connector.json index 68a9cff1cf..f35d6454bd 100644 --- a/connectors/asana/element-templates/asana-connector.json +++ b/connectors/asana/element-templates/asana-connector.json @@ -3,7 +3,14 @@ "name": "Asana Outbound Connector", "id": "io.camunda.connectors.Asana.v1", "version": 2, - "description": "Manage your Asana project with Camunda", + "description": "Create, update, and manage tasks and projects in Asana.", + "metadata": { + "keywords": [ + "get task or project by ID", + "get tasks from project", + "create project in workspace" + ] + }, "icon": { "contents": "data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='781.361 0 944.893 873.377'%3E%3CradialGradient id='a' cx='943.992' cy='1221.416' r='.663' gradientTransform='matrix(944.8934 0 0 -873.3772 -890717.875 1067234.75)' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23ffb900'/%3E%3Cstop offset='.6' stop-color='%23f95d8f'/%3E%3Cstop offset='.999' stop-color='%23f95353'/%3E%3C/radialGradient%3E%3Cpath fill='url(%23a)' d='M1520.766 462.371c-113.508 0-205.508 92-205.508 205.488 0 113.499 92 205.518 205.508 205.518 113.489 0 205.488-92.019 205.488-205.518 0-113.488-91.999-205.488-205.488-205.488zm-533.907.01c-113.489.01-205.498 91.99-205.498 205.488 0 113.489 92.009 205.498 205.498 205.498 113.498 0 205.508-92.009 205.508-205.498 0-113.499-92.01-205.488-205.518-205.488h.01zm472.447-256.883c0 113.489-91.999 205.518-205.488 205.518-113.508 0-205.508-92.029-205.508-205.518S1140.31 0 1253.817 0c113.489 0 205.479 92.009 205.479 205.498h.01z'/%3E%3C/svg%3E" }, diff --git a/connectors/automation-anywhere/src/main/java/io/camunda/connector/automationanywhere/AutomationAnywhereConnector.java b/connectors/automation-anywhere/src/main/java/io/camunda/connector/automationanywhere/AutomationAnywhereConnector.java index 1b70ad8283..5bf1a325b7 100644 --- a/connectors/automation-anywhere/src/main/java/io/camunda/connector/automationanywhere/AutomationAnywhereConnector.java +++ b/connectors/automation-anywhere/src/main/java/io/camunda/connector/automationanywhere/AutomationAnywhereConnector.java @@ -25,8 +25,14 @@ @ElementTemplate( id = "io.camunda.connectors.AutomationAnywhere", name = "Automation Anywhere Outbound Connector", - description = - "Orchestrate your Automation Anywhere bots with Camunda. You can create new queue items and get the result from it", + description = "Manage work items in Automation Anywhere queues.", + metadata = + @ElementTemplate.Metadata( + keywords = { + "add work item to queue", + "get work item from queue", + "get work item result from queue by ID" + }), inputDataClass = AutomationAnywhereRequest.class, version = 2, propertyGroups = { diff --git a/connectors/blue-prism/element-templates/blue-prism-connector.json b/connectors/blue-prism/element-templates/blue-prism-connector.json index afb64d4e7e..30898d83c6 100644 --- a/connectors/blue-prism/element-templates/blue-prism-connector.json +++ b/connectors/blue-prism/element-templates/blue-prism-connector.json @@ -3,7 +3,14 @@ "name": "Blue Prism Outbound Connector", "id": "io.camunda.connectors.BluePrism.v1", "version": 3, - "description": "Orchestrate your Blue Prism queue with Camunda. You can create new queue items and get the result from it", + "description": "Manage Blue Prism work queues and items.", + "metadata": { + "keywords": [ + "get item from queue by ID", + "create work queue item", + "work queue" + ] + }, "documentationRef": "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/blueprism/", "category": { "id": "connectors", diff --git a/connectors/easy-post/element-templates/easy-post-connector.json b/connectors/easy-post/element-templates/easy-post-connector.json index da4a6d7b64..5d803912ab 100644 --- a/connectors/easy-post/element-templates/easy-post-connector.json +++ b/connectors/easy-post/element-templates/easy-post-connector.json @@ -3,7 +3,17 @@ "name": "Easy Post Outbound Connector", "id": "io.camunda.connectors.EasyPost.v1", "version": 4, - "description": "Allows you to create addresses, parcels, and shipments, as well as purchase and verify shipments", + "description": "Manage addresses, parcels, and shipments with Easy Post.", + "metadata": { + "keywords": [ + "create address", + "create parcel", + "create shipment", + "buy shipment", + "verify address", + "retrieve tracker by ID" + ] + }, "documentationRef": "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/easy-post/", "category": { "id": "connectors", diff --git a/connectors/jdbc/element-templates/hybrid/jdbc-outbound-connector-hybrid.json b/connectors/jdbc/element-templates/hybrid/jdbc-outbound-connector-hybrid.json index cc1301e675..d832f2b884 100644 --- a/connectors/jdbc/element-templates/hybrid/jdbc-outbound-connector-hybrid.json +++ b/connectors/jdbc/element-templates/hybrid/jdbc-outbound-connector-hybrid.json @@ -2,7 +2,10 @@ "$schema" : "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", "name" : "Hybrid SQL Database Connector", "id" : "io.camunda.connectors.Jdbc.v1-hybrid", - "description" : "Read and write data from a Camunda process directly to a SQL database(Microsoft SQL Server, MySQL, PostgreSQL)", + "description" : "Read and write data from a Camunda process directly to a SQL database (e.g., Microsoft SQL Server, MySQL, PostgreSQL)", + "metadata" : { + "keywords" : [ "relational", "database" ] + }, "documentationRef" : "https://docs.camunda.io/docs/next/components/connectors/out-of-the-box-connectors/sql", "version" : 1, "category" : { diff --git a/connectors/jdbc/element-templates/jdbc-outbound-connector.json b/connectors/jdbc/element-templates/jdbc-outbound-connector.json index a87ed5bfec..132a3be9aa 100644 --- a/connectors/jdbc/element-templates/jdbc-outbound-connector.json +++ b/connectors/jdbc/element-templates/jdbc-outbound-connector.json @@ -2,7 +2,10 @@ "$schema" : "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", "name" : "SQL Database Connector", "id" : "io.camunda.connectors.Jdbc.v1", - "description" : "Read and write data from a Camunda process directly to a SQL database(Microsoft SQL Server, MySQL, PostgreSQL)", + "description" : "Read and write data from a Camunda process directly to a SQL database (e.g., Microsoft SQL Server, MySQL, PostgreSQL)", + "metadata" : { + "keywords" : [ "relational", "database" ] + }, "documentationRef" : "https://docs.camunda.io/docs/next/components/connectors/out-of-the-box-connectors/sql", "version" : 1, "category" : { diff --git a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/outbound/JdbcFunction.java b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/outbound/JdbcFunction.java index 4496f62640..7b9a0ec285 100644 --- a/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/outbound/JdbcFunction.java +++ b/connectors/jdbc/src/main/java/io/camunda/connector/jdbc/outbound/JdbcFunction.java @@ -24,7 +24,8 @@ name = "SQL Database Connector", version = 1, description = - "Read and write data from a Camunda process directly to a SQL database(Microsoft SQL Server, MySQL, PostgreSQL)", + "Read and write data from a Camunda process directly to a SQL database (e.g., Microsoft SQL Server, MySQL, PostgreSQL)", + metadata = @ElementTemplate.Metadata(keywords = {"relational", "database"}), icon = "icon.svg", documentationRef = "https://docs.camunda.io/docs/next/components/connectors/out-of-the-box-connectors/sql", diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplate.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplate.java index 38923f302c..54ad7bfefe 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplate.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplate.java @@ -31,6 +31,7 @@ "name", "id", "description", + "metadata", "documentationRef", "version", "category", @@ -46,20 +47,13 @@ public record ElementTemplate( int version, String documentationRef, String description, + Metadata metadata, Set appliesTo, ElementTypeWrapper elementType, List groups, List properties, ElementTemplateIcon icon) { - public static ElementTemplateBuilder builderForOutbound() { - return ElementTemplateBuilder.createOutbound(); - } - - public static ElementTemplateBuilder builderForInbound() { - return ElementTemplateBuilder.createInbound(); - } - static final String SCHEMA_FIELD_NAME = "$schema"; static final String SCHEMA_URL = "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json"; @@ -107,6 +101,14 @@ public static ElementTemplateBuilder builderForInbound() { } } + public static ElementTemplateBuilder builderForOutbound() { + return ElementTemplateBuilder.createOutbound(); + } + + public static ElementTemplateBuilder builderForInbound() { + return ElementTemplateBuilder.createInbound(); + } + @JsonProperty public ElementTemplateCategory category() { return ElementTemplateCategory.CONNECTORS; @@ -117,6 +119,8 @@ public String schema() { return SCHEMA_URL; } + public record Metadata(String[] keywords) {} + @JsonInclude(Include.NON_NULL) public record ElementTypeWrapper( String value, String eventDefinition, @JsonIgnore BpmnType originalType) { diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplateBuilder.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplateBuilder.java index 0c7867094c..e31e51a7d1 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplateBuilder.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/dsl/ElementTemplateBuilder.java @@ -17,6 +17,7 @@ package io.camunda.connector.generator.dsl; import io.camunda.connector.generator.dsl.ElementTemplate.ElementTypeWrapper; +import io.camunda.connector.generator.dsl.ElementTemplate.Metadata; import io.camunda.connector.generator.dsl.Property.FeelMode; import io.camunda.connector.generator.dsl.PropertyBinding.ZeebeProperty; import io.camunda.connector.generator.dsl.PropertyBinding.ZeebeTaskDefinition; @@ -47,6 +48,7 @@ private ElementTemplateBuilder(Mode mode) { protected ElementTemplateIcon icon; protected String documentationRef; protected String description; + protected Metadata metadata; protected Set appliesTo; protected BpmnType elementType; protected final List groups = new ArrayList<>(); @@ -149,6 +151,11 @@ public ElementTemplateBuilder description(String description) { return this; } + public ElementTemplateBuilder metadata(Metadata metadata) { + this.metadata = metadata; + return this; + } + public ElementTemplateBuilder appliesTo(Set appliesTo) { this.appliesTo = appliesTo.stream().map(BpmnType::getName).collect(Collectors.toSet()); return this; @@ -197,6 +204,7 @@ public ElementTemplate build() { version, documentationRef, description, + metadata, appliesTo, ElementTypeWrapper.from(elementType), groups, diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedDocsGenerator.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedDocsGenerator.java index 493d9685ad..bb06a4962c 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedDocsGenerator.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedDocsGenerator.java @@ -64,8 +64,6 @@ public class ClassBasedDocsGenerator implements DocsGenerator> { - private final ClassLoader classLoader; - private static final ObjectWriter OBJECT_WRITER = ConnectorsObjectMapperSupplier.DEFAULT_MAPPER .copy() @@ -73,8 +71,8 @@ public class ClassBasedDocsGenerator implements DocsGenerator> { .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) .setSerializationInclusion(JsonInclude.Include.NON_NULL) .writerWithDefaultPrettyPrinter(); - private static final FeelEngineWrapper feelEngineWrapper = new FeelEngineWrapper(); + private final ClassLoader classLoader; public ClassBasedDocsGenerator(ClassLoader classLoader) { this.classLoader = classLoader; @@ -84,6 +82,57 @@ public ClassBasedDocsGenerator() { this(Thread.currentThread().getContextClassLoader()); } + public static Map collectExampleData(Class type) { + var methods = findAllDataExampleMethods(type); + return methods.stream() + .map( + pair -> { + var method = pair.getLeft(); + var annotation = pair.getRight(); + Object result; + String json; + Object feelResult = null; + String feelResultJson = null; + try { + result = method.invoke(new Arrays[0]); + json = OBJECT_WRITER.writeValueAsString(result); + if (StringUtils.isNotBlank(annotation.feel())) { + feelResult = feelEngineWrapper.evaluate(annotation.feel(), result); + feelResultJson = OBJECT_WRITER.writeValueAsString(feelResult); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return new DataExampleModel( + annotation.id(), result, json, annotation.feel(), feelResult, feelResultJson); + }) + .collect(Collectors.toMap(DataExampleModel::id, v -> v)); + } + + public static List> findAllDataExampleMethods(Class type) { + return Arrays.stream(type.getDeclaredMethods()) + .filter(m -> Modifier.isStatic(m.getModifiers())) + .filter( + m -> + Arrays.stream(m.getAnnotations()) + .anyMatch(a -> DataExample.class.equals(a.annotationType()))) + .map(m -> Pair.of(m, m.getDeclaredAnnotation(DataExample.class))) + .toList(); + } + + public static String generateExampleData(Class type) { + DataProviderStrategy strategy = new DocsDataProviderStrategy(); + PodamFactory factory = new PodamFactoryImpl(strategy); + var exampleOutput = factory.manufacturePojo(type); + String exampleOutputJson; + try { + exampleOutputJson = OBJECT_WRITER.writeValueAsString(exampleOutput); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + return exampleOutputJson; + } + @Override public Doc generate(Class connectorDefinition, DocsGeneratorConfiguration configuration) { @@ -115,6 +164,7 @@ private Map buildTemplateModel( model.put("id", elementTemplate.id()); model.put("name", elementTemplate.name()); model.put("description", elementTemplate.description()); + model.put("keywords", elementTemplate.metadata().keywords()); model.put("version", elementTemplate.version()); model.put("type", templateGenerationContext.connectorType()); model.put( @@ -176,57 +226,6 @@ private DocsProperty mapToDocsProperty(Property property) { property); } - public static Map collectExampleData(Class type) { - var methods = findAllDataExampleMethods(type); - return methods.stream() - .map( - pair -> { - var method = pair.getLeft(); - var annotation = pair.getRight(); - Object result; - String json; - Object feelResult = null; - String feelResultJson = null; - try { - result = method.invoke(new Arrays[0]); - json = OBJECT_WRITER.writeValueAsString(result); - if (StringUtils.isNotBlank(annotation.feel())) { - feelResult = feelEngineWrapper.evaluate(annotation.feel(), result); - feelResultJson = OBJECT_WRITER.writeValueAsString(feelResult); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - return new DataExampleModel( - annotation.id(), result, json, annotation.feel(), feelResult, feelResultJson); - }) - .collect(Collectors.toMap(DataExampleModel::id, v -> v)); - } - - public static List> findAllDataExampleMethods(Class type) { - return Arrays.stream(type.getDeclaredMethods()) - .filter(m -> Modifier.isStatic(m.getModifiers())) - .filter( - m -> - Arrays.stream(m.getAnnotations()) - .anyMatch(a -> DataExample.class.equals(a.annotationType()))) - .map(m -> Pair.of(m, m.getDeclaredAnnotation(DataExample.class))) - .toList(); - } - - public static String generateExampleData(Class type) { - DataProviderStrategy strategy = new DocsDataProviderStrategy(); - PodamFactory factory = new PodamFactoryImpl(strategy); - var exampleOutput = factory.manufacturePojo(type); - String exampleOutputJson; - try { - exampleOutputJson = OBJECT_WRITER.writeValueAsString(exampleOutput); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - return exampleOutputJson; - } - private String renderTemplate(Map model, PebbleTemplate pebbleTemplate) { Writer writer = new StringWriter(); try { diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedTemplateGenerator.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedTemplateGenerator.java index 4cf3ae97d5..d936a7ed60 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedTemplateGenerator.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/ClassBasedTemplateGenerator.java @@ -52,6 +52,45 @@ public ClassBasedTemplateGenerator() { this(Thread.currentThread().getContextClassLoader()); } + private static String createId( + TemplateGenerationContext context, + String templateId, + ConnectorElementType elementType, + final boolean isHybridMode) { + String baseTemplateId = + Optional.ofNullable(elementType.templateIdOverride()) + .orElseGet( + () -> + context.elementTypes().size() > 1 + ? templateId + ":" + elementType.elementType().getId() + : templateId); + return isHybridMode + ? baseTemplateId + GeneratorConfiguration.HYBRID_TEMPLATE_ID_SUFFIX + : baseTemplateId; + } + + private static String createName( + TemplateGenerationContext context, + String templateName, + ConnectorElementType elementType, + boolean isHybridMode) { + String baseTemplateName = + Optional.ofNullable(elementType.templateNameOverride()) + .orElseGet( + () -> { + if (context.elementTypes().size() > 1) { + return templateName + + " (" + + camelCaseToSpaces(elementType.elementType().getId()) + + ")"; + } + return templateName; + }); + return isHybridMode + ? GeneratorConfiguration.HYBRID_TEMPLATE_NAME_PREFIX + baseTemplateName + : baseTemplateName; + } + @Override public List generate( Class connectorDefinition, GeneratorConfiguration configuration) { @@ -130,6 +169,9 @@ public List generate( .appliesTo(elementType.appliesTo()) .elementType(elementType.elementType()) .icon(icon) + .metadata( + new io.camunda.connector.generator.dsl.ElementTemplate.Metadata( + template.metadata().keywords())) .documentationRef( template.documentationRef().isEmpty() ? null : template.documentationRef()) .description(template.description().isEmpty() ? null : template.description()) @@ -141,45 +183,6 @@ public List generate( .toList(); } - private static String createId( - TemplateGenerationContext context, - String templateId, - ConnectorElementType elementType, - final boolean isHybridMode) { - String baseTemplateId = - Optional.ofNullable(elementType.templateIdOverride()) - .orElseGet( - () -> - context.elementTypes().size() > 1 - ? templateId + ":" + elementType.elementType().getId() - : templateId); - return isHybridMode - ? baseTemplateId + GeneratorConfiguration.HYBRID_TEMPLATE_ID_SUFFIX - : baseTemplateId; - } - - private static String createName( - TemplateGenerationContext context, - String templateName, - ConnectorElementType elementType, - boolean isHybridMode) { - String baseTemplateName = - Optional.ofNullable(elementType.templateNameOverride()) - .orElseGet( - () -> { - if (context.elementTypes().size() > 1) { - return templateName - + " (" - + camelCaseToSpaces(elementType.elementType().getId()) - + ")"; - } - return templateName; - }); - return isHybridMode - ? GeneratorConfiguration.HYBRID_TEMPLATE_NAME_PREFIX + baseTemplateName - : baseTemplateName; - } - private List addServiceProperties( List groups, TemplateGenerationContext context, diff --git a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/ElementTemplate.java b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/ElementTemplate.java index 38f25ce6c5..ed195c0fd6 100644 --- a/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/ElementTemplate.java +++ b/element-template-generator/core/src/main/java/io/camunda/connector/generator/java/annotation/ElementTemplate.java @@ -68,6 +68,8 @@ */ String description() default ""; + Metadata metadata() default @Metadata; + /** * Manual configuration for the connector property groups. * @@ -93,6 +95,12 @@ ConnectorElementType[] elementTypes() default {}; + /** Metadata tags for the connector. Will be used in Camunda Modeler. */ + @interface Metadata { + + String[] keywords() default {}; + } + @interface PropertyGroup { String id(); diff --git a/element-template-generator/core/src/test/java/io/camunda/connector/generator/dsl/ElementTemplateSerializationTest.java b/element-template-generator/core/src/test/java/io/camunda/connector/generator/dsl/ElementTemplateSerializationTest.java index fe3be8b8dd..9899e1fad7 100644 --- a/element-template-generator/core/src/test/java/io/camunda/connector/generator/dsl/ElementTemplateSerializationTest.java +++ b/element-template-generator/core/src/test/java/io/camunda/connector/generator/dsl/ElementTemplateSerializationTest.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.camunda.connector.generator.dsl.DropdownProperty.DropdownChoice; +import io.camunda.connector.generator.dsl.ElementTemplate.Metadata; import io.camunda.connector.generator.dsl.Property.FeelMode; import io.camunda.connector.generator.dsl.PropertyBinding.ZeebeInput; import io.camunda.connector.generator.dsl.PropertyBinding.ZeebeTaskHeader; @@ -48,6 +49,7 @@ void serializationTest() throws Exception { .documentationRef( "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/available-connectors-overview/") .description("Describe this connector") + .metadata(new Metadata(new String[] {"foo", "bar"})) .propertyGroups( PropertyGroup.builder() .id("authentication") diff --git a/element-template-generator/core/src/test/resources/test-element-template.json b/element-template-generator/core/src/test/resources/test-element-template.json index 201737b452..e38601b6d7 100644 --- a/element-template-generator/core/src/test/resources/test-element-template.json +++ b/element-template-generator/core/src/test/resources/test-element-template.json @@ -3,6 +3,12 @@ "name": "Template: Some Function", "id": "io.camunda.connector.Template.v1", "description": "Describe this connector", + "metadata": { + "keywords": [ + "foo", + "bar" + ] + }, "documentationRef": "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/available-connectors-overview/", "version": 1, "category": {