diff --git a/pom.xml b/pom.xml index efbda15..228ffa4 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ com.axonivy.connector.uipath ui-path-connector ui-path-connector-modules - 10.0.2-SNAPSHOT + 10.0.1.0-SNAPSHOT pom @@ -38,6 +38,14 @@ + + + com.axonivy.ivy.ci + project-build-plugin + 10.0.16 + true + + diff --git a/ui-path-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs b/ui-path-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs index ddf76e4..3e17759 100644 --- a/ui-path-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs +++ b/ui-path-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,4 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=com.axonivy.connector.uipath.ui.path.connector.demo.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=com.axonivy.connector.uipath.ui.path.connector.demo +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 -eclipse.preferences.version=1 \ No newline at end of file +eclipse.preferences.version=1 diff --git a/ui-path-connector-demo/pom.xml b/ui-path-connector-demo/pom.xml index ed47c45..9c61663 100644 --- a/ui-path-connector-demo/pom.xml +++ b/ui-path-connector-demo/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.axonivy.connector.uipath ui-path-connector-demo - 10.0.2-SNAPSHOT + 10.0.1.0-SNAPSHOT iar @@ -18,7 +18,7 @@ com.axonivy.ivy.ci project-build-plugin - 10.0.6 + 10.0.16 true diff --git a/ui-path-connector-demo/processes/uiPathDemo.p.json b/ui-path-connector-demo/processes/uiPathDemo.p.json index 68f08de..d6c0f6e 100644 --- a/ui-path-connector-demo/processes/uiPathDemo.p.json +++ b/ui-path-connector-demo/processes/uiPathDemo.p.json @@ -14,7 +14,7 @@ "id" : "f9", "type" : "RequestStart", "name" : [ - " robot:", + "robot:", "GetOrders.ivp" ], "config" : { @@ -25,7 +25,7 @@ }, "visual" : { "at" : { "x" : 96, "y" : 64 }, - "labelOffset" : { "x" : -22, "y" : 39 } + "labelOffset" : { "x" : 17, "y" : 41 } }, "connect" : { "id" : "f2", "to" : "f0" } }, { @@ -44,7 +44,8 @@ } }, "visual" : { - "at" : { "x" : 224, "y" : 64 } + "at" : { "x" : 224, "y" : 64 }, + "icon" : "res:/webContent/icons/uipath.png" }, "connect" : { "id" : "f3", "to" : "f1" } }, { @@ -61,7 +62,7 @@ } }, "visual" : { - "at" : { "x" : 96, "y" : 256 }, + "at" : { "x" : 512, "y" : 64 }, "labelOffset" : { "x" : 11, "y" : 35 } } }, { @@ -77,9 +78,83 @@ "docs" : "https://docs.uipath.com/orchestrator/reference/consuming-cloud-api" }, "visual" : { - "at" : { "x" : 328, "y" : 256 }, + "at" : { "x" : 744, "y" : 64 }, "size" : { "width" : 336, "height" : 80 } }, "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f6", + "type" : "RequestStart", + "name" : "triggerAllActiveJobs.ivp", + "config" : { + "callSignature" : "triggerAllActiveJobs", + "outLink" : "triggerAllActiveJobs.ivp", + "startName" : "Trigger to start all active Jobs in Orcherstator" + }, + "visual" : { + "at" : { "x" : 96, "y" : 192 } + }, + "connect" : { "id" : "f11", "to" : "f10" } + }, { + "id" : "f7", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 352, "y" : 192 } + } + }, { + "id" : "f10", + "type" : "SubProcessCall", + "name" : "Start all active Jobs", + "config" : { + "processCall" : "uiPathJob:startAllActiveJobs()" + }, + "visual" : { + "at" : { "x" : 224, "y" : 192 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f8", "to" : "f7" } + }, { + "id" : "f13", + "type" : "RequestStart", + "name" : "startJobByName.ivp", + "config" : { + "callSignature" : "startJobByName", + "outLink" : "startJobByName.ivp", + "startName" : "Trigger to start job by name in Orcherstator" + }, + "visual" : { + "at" : { "x" : 96, "y" : 320 } + }, + "connect" : { "id" : "f16", "to" : "f15" } + }, { + "id" : "f14", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 352, "y" : 320 } + } + }, { + "id" : "f15", + "type" : "SubProcessCall", + "name" : [ + "Start active Jobs", + "By Name" + ], + "config" : { + "processCall" : "uiPathJob:startJobByName(String,String)", + "call" : { + "params" : [ + { "name" : "jobName", "type" : "String" }, + { "name" : "jobArguments", "type" : "String" } + ], + "map" : { + "param.jobName" : "\"SendEmailFromGmail\"" + } + } + }, + "visual" : { + "at" : { "x" : 224, "y" : 320 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f17", "to" : "f14" } } ] } \ No newline at end of file diff --git a/ui-path-connector-product/README.md b/ui-path-connector-product/README.md index 8d13da5..2137d0b 100644 --- a/ui-path-connector-product/README.md +++ b/ui-path-connector-product/README.md @@ -8,8 +8,6 @@ processes. This connector: - Enables you to steer robotic work from your workflow process. - Makes the UiPath RPA API features easy and attractive to use in business processes. -- Supports you with an easy-to-copy demo implementation to reduce your - integration effort. ## Demo diff --git a/ui-path-connector-product/images/copyAuth_idKeyTenant.png b/ui-path-connector-product/images/copyAuth_idKeyTenant.png index 64b622c..dd18d0b 100644 Binary files a/ui-path-connector-product/images/copyAuth_idKeyTenant.png and b/ui-path-connector-product/images/copyAuth_idKeyTenant.png differ diff --git a/ui-path-connector-product/pom.xml b/ui-path-connector-product/pom.xml index e968c37..acdd176 100644 --- a/ui-path-connector-product/pom.xml +++ b/ui-path-connector-product/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.axonivy.connector.uipath ui-path-connector-product - 10.0.2-SNAPSHOT + 10.0.1.0-SNAPSHOT pom diff --git a/ui-path-connector-test/.settings/ch.ivyteam.ivy.designer.prefs b/ui-path-connector-test/.settings/ch.ivyteam.ivy.designer.prefs index 2ef3d4d..1a932f0 100644 --- a/ui-path-connector-test/.settings/ch.ivyteam.ivy.designer.prefs +++ b/ui-path-connector-test/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,4 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=com.axonivy.connector.uipath.test.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=com.axonivy.connector.uipath.test +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 -eclipse.preferences.version=1 \ No newline at end of file +eclipse.preferences.version=1 diff --git a/ui-path-connector-test/pom.xml b/ui-path-connector-test/pom.xml index 6398260..1e71691 100644 --- a/ui-path-connector-test/pom.xml +++ b/ui-path-connector-test/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.axonivy.connector.uipath ui-path-connector-test - 10.0.2-SNAPSHOT + 10.0.1.0-SNAPSHOT iar @@ -15,7 +15,7 @@ com.axonivy.ivy.test unit-tester - 10.0.0 + 10.0.16 test @@ -36,7 +36,7 @@ com.axonivy.ivy.ci project-build-plugin - 10.0.6 + 10.0.16 true diff --git a/ui-path-connector-test/src/com/axonivy/connector/uipath/test/UiPathMock.java b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/UiPathMock.java index e6dc82b..4594515 100644 --- a/ui-path-connector-test/src/com/axonivy/connector/uipath/test/UiPathMock.java +++ b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/UiPathMock.java @@ -31,7 +31,7 @@ @Hidden public class UiPathMock { - static final String PATH_SUFFIX = "rpaMock"; + static final String PATH_SUFFIX = "rpaMock/orchestrator_/"; // URI where this mock can be reached: to be referenced in tests that use it! public static final String URI = "{ivy.app.baseurl}/api/" + PATH_SUFFIX; @@ -54,6 +54,20 @@ public String getJobs() { return json; } + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("odata/Folders") + public String getFolders() { + return load("json/folders.json"); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("odata/Machines") + public String getMachines() { + return load("json/machines.json"); + } + @GET @Produces(MediaType.APPLICATION_JSON) @Path("odata/Robots") diff --git a/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/folders.json b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/folders.json new file mode 100644 index 0000000..c67f003 --- /dev/null +++ b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/folders.json @@ -0,0 +1,22 @@ +{ + "@odata.context": "https://platform.uipath.com/odata/$metadata#Folders", + "@odata.count": 1, + "value": [ + { + "Key": "1a374a79-9bdd-4055-a0cc-95488ae006a0", + "DisplayName": "MyTest", + "FullyQualifiedName": "MyTest", + "FullyQualifiedNameOrderable": "MyTest", + "Description": null, + "FolderType": "Standard", + "ProvisionType": "Automatic", + "PermissionModel": "FineGrained", + "ParentId": null, + "ParentKey": null, + "IsActive": true, + "FeedType": "Processes", + "ReservedOptions": null, + "Id": 89973 + } + ] +} diff --git a/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/machines.json b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/machines.json new file mode 100644 index 0000000..a8a7cec --- /dev/null +++ b/ui-path-connector-test/src/com/axonivy/connector/uipath/test/json/machines.json @@ -0,0 +1,38 @@ +{ + "@odata.context": "https://cloud.uipath.com/orchestrator_/odata/$metadata#Machines/UiPath.Server.Configuration.OData.ExtendedMachineDto", + "@odata.count": 4, + "value": [ + { + "@odata.type": "#UiPath.Server.Configuration.OData.ExtendedMachineDto", + "ServerlessLicensingModel": null, + "LicenseKey": null, + "Name": "My workspace machine", + "Description": null, + "Type": "Template", + "Scope": "PersonalWorkspace", + "NonProductionSlots": 0, + "UnattendedSlots": 0, + "HeadlessSlots": 0, + "TestAutomationSlots": 0, + "AutomationCloudSlots": 0, + "AutomationCloudTestAutomationSlots": 0, + "Key": "480f27b8-09c8-4476-b01b-db2d1bd0f5d5", + "EndpointDetectionStatus": "NotAvailable", + "AutomationType": "Any", + "TargetFramework": "Any", + "ClientSecret": null, + "Id": 55490, + "RobotVersions": [ + { + "Count": 2, + "Version": "24.10.1" + } + ], + "RobotUsers": [], + "UpdatePolicy": null, + "Tags": [], + "MaintenanceWindow": null, + "VpnSettings": null + } + ] +} diff --git a/ui-path-connector-test/src_test/com/axonivy/connector/uipath/test/UiPathTest.java b/ui-path-connector-test/src_test/com/axonivy/connector/uipath/test/UiPathTest.java new file mode 100644 index 0000000..f5cb3d9 --- /dev/null +++ b/ui-path-connector-test/src_test/com/axonivy/connector/uipath/test/UiPathTest.java @@ -0,0 +1,81 @@ +package com.axonivy.connector.uipath.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.axonivy.connector.uipath.TenantHeaderFeature; +import com.axonivy.connector.uipath.ui.path.connector.UiPathJobData; +import com.axonivy.connector.uipath.ui.path.connector.UiPathRpa; + +import ch.ivyteam.ivy.application.IApplication; +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.AppFixture; +import ch.ivyteam.ivy.rest.client.RestClient; +import ch.ivyteam.ivy.rest.client.RestClients; +import ch.ivyteam.ivy.rest.client.mapper.JsonFeature; +import ch.ivyteam.ivy.rest.client.security.CsrfHeaderFeature; +import ch.ivyteam.ivy.security.ISession; + +/** + * Service functionality is mocked out here: {@link UiPathMock} + */ +@IvyProcessTest(enableWebServer = true) +public class UiPathTest { + + private static final String UI_PATH_REST_CLIENT = "UIPathRPA (UiPath.WebApi 18.0)"; + private static final BpmElement UI_PATH_JOB_ALL_ACTIVE_JOBS_END = BpmElement.pid("190E93ECBBC86C6F-f1"); + private static final BpmElement UI_PATH_JOB_START_JOB_END = BpmElement.pid("190E93ECBBC86C6F-f50"); + private static final BpmElement UI_PATH_RPA_END = BpmElement.pid("175F58F3612E10B1-f15"); + + + @BeforeAll + static void beforeAll(AppFixture fixture, IApplication app) { + fixture.config("RestClients." + UI_PATH_REST_CLIENT + ".Url", UiPathMock.URI); + fixture.config("RestClients." + UI_PATH_REST_CLIENT + ".Features", ""); + + RestClients clients = RestClients.of(app); + RestClient uiPathRpa = clients.find(UI_PATH_REST_CLIENT); + var testClient = uiPathRpa.toBuilder() + .features(List.of( // exclude oauth-feature + JsonFeature.class.getName(), + TenantHeaderFeature.class.getName(), + CsrfHeaderFeature.class.getName())) + .property("AUTH.clientId", "notMyId") + .property("AUTH.userKey", "notMyKey") + .property("AUTH.tenant", "notMyTenant") + .property("PATH.tenant", "tenant") + .property("PATH.organization", "organization") + .toRestClient(); + clients.set(testClient); + } + + @Test + public void rpaDemo(BpmClient bpmClient, ISession session) { + ExecutionResult result = bpmClient.start() + .process("uiPathDemo/robotGetOrders.ivp") + .as().session(session) + .execute(); + UiPathRpa data = result.data().lastOnElement(UI_PATH_RPA_END); + assertThat(data.getLicense()).isNotNull(); + assertThat(data.getReleases()).isNotEmpty(); + assertThat(data.getRobots()).isNotEmpty(); + } + + @Test + public void jobDemo(BpmClient bpmClient, ISession session) { + ExecutionResult result = bpmClient.start().process("uiPathDemo/triggerAllActiveJobs.ivp").as().session(session) + .execute(); + UiPathJobData data = result.data().lastOnElement(UI_PATH_JOB_ALL_ACTIVE_JOBS_END); + assertThat(data.getOrganizationunitId()).isNotNull(); + data = result.data().lastOnElement(UI_PATH_JOB_START_JOB_END); + assertThat(data.getMachines()).isNotEmpty(); + assertThat(data.getStartInfo()).isNotNull(); + } +} diff --git a/ui-path-connector/.settings/ch.ivyteam.ivy.designer.prefs b/ui-path-connector/.settings/ch.ivyteam.ivy.designer.prefs index 383cf87..8b64db3 100644 --- a/ui-path-connector/.settings/ch.ivyteam.ivy.designer.prefs +++ b/ui-path-connector/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,4 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=com.axonivy.connector.uipath.ui.path.connector.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=com.axonivy.connector.uipath.ui.path.connector +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 -eclipse.preferences.version=1 \ No newline at end of file +eclipse.preferences.version=1 diff --git a/ui-path-connector/config/rest-clients.yaml b/ui-path-connector/config/rest-clients.yaml index 3678cb2..010094c 100644 --- a/ui-path-connector/config/rest-clients.yaml +++ b/ui-path-connector/config/rest-clients.yaml @@ -1,8 +1,8 @@ RestClients: #Orchestrator API - UIPathRPA: + UIPathRPA (UiPath.WebApi 18.0): UUID: c700c640-4f76-4cbe-8724-dbc663d8bc0a - Url: https://cloud.uipath.com/ + Url: https://cloud.uipath.com/{organization}/{tenant}/orchestrator_/ Icon: res:/webContent/icons/uipath.png Features: - ch.ivyteam.ivy.rest.client.mapper.JsonFeature @@ -12,6 +12,8 @@ RestClients: AUTH.tenant: ${ivy.var.uiPath-connector.tenant} AUTH.clientId: ${ivy.var.uiPath-connector.clientId} AUTH.userKey: ${decrypt:\u00AC\u0078\u004A\u00A5\u000B\u0039\u0050\u0072\u0026\u0091\u000E\u0012\u00D2\u0048\u00F6\u009F\u0012\u00CB\u0048\u00B2\u00B2\u0098\u001A\u00BE\u0098\u0070\u0063\u0067\u0010\u00A4\u00A9\u00F5\u002E\u0097\u0021\u0041\u00D7\u001E\u00A5\u0049\u003B\u0065\u0001\u006C\u00EF\u0024\u00D4\u0008\u0031\u0036\u0081\u00DD\u0096\u0013\u00CE\u0016\u00B5\u00FD\u0049\u00D0\u00BE\u004F\u0031\u0032\u00C5\u0004\u00E0\u0015\u0068\u00BF\u001E\u00E7\u0080\u00BD\u004C\u0090\u0017\u003E\u00EE\u001A\u005B\u0052\u0040\u005E\u0086\u0034\u0088\u00E5\u00C8\u001C\u0014\u0097\u0019\u00E5\u004D\u00BB\u0067\u00E9\u0038\u00EA\u0078\u00AB\u0026\u00AA\u006A\u004A\u0048\u007D\u00B3\u0081\u0090\u00D7\u00B6\u0038\u00C9\u0017\u0072\u008B\u0023\u004C\u00B6\u0029\u00C6\u0028\u0024\u00A1\u006C\u00CD\u00D0\u0005\u007D\u00F8\u00FE\u00C0\u00E5\u0074\u0016\u00DB\u00F5\u00C9\u00BB\u0079\u00E4\u00DE\u00FF\u0004\u0071\u00B2\u00D4\u0000\u00EA\u007D\u0025\u006A\u00E4\u0037\u00B8\u0053\u00F9\u005A\u009E\u0076\u0000\u0086\u00F7\u0051\u0064\u00F2\u002E\u0074\u004C\u0003\u00DF\u007C\u00A2\u00EB\u0061\u001C\u00CE\u001F\u006E\u00B9\u00CB\u0014\u0039\u0026\u000C\u0096\u0004\u00CD\u0061\u0044\u00AC\u00A2\u0098\u00FC\u008C\u0007\u00EA\u00E1\u002A\u005A\u0061\u0021\u00C6\u0053\u00E2\u002D\u00F8\u006B\u00A6\u0019\u001C\u00BD\u0008\u009F\u009A\u00EA\u00B3\u000D\u003F\u00DA\u0069\u0011} + PATH.tenant: ${ivy.var.uiPath-connector.tenant} + PATH.organization: ${ivy.var.uiPath-connector.organization} jersey.config.client.followRedirects: 'false' JSON.Serialization.PROPERTY_INCLUSION: NON_NULL JSON.Mapper.ACCEPT_CASE_INSENSITIVE_PROPERTIES: 'true' diff --git a/ui-path-connector/config/variables.yaml b/ui-path-connector/config/variables.yaml index 35417d8..caccd2a 100644 --- a/ui-path-connector/config/variables.yaml +++ b/ui-path-connector/config/variables.yaml @@ -7,8 +7,9 @@ # Variables: uiPath-connector: + organization: '' tenant: 'AXONPRESALES' clientId: '' + # The key of service user, access to Admin > Tenant > Services > API Access > User Key # [password] userKey: '' - diff --git a/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathJobData.ivyClass b/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathJobData.ivyClass new file mode 100644 index 0000000..dfb5c64 --- /dev/null +++ b/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathJobData.ivyClass @@ -0,0 +1,9 @@ +UiPathJobData #class +com.axonivy.connector.uipath.ui.path.connector #namespace +organizationunitId Long #field +releases java.util.List #field +machines java.util.List #field +startInfo com.uipath.orchestrator.StartProcessDto #field +jobName String #field +jobArguments String #field +filter String #field diff --git a/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathRpa.ivyClass b/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathRpa.ivyClass index 7c2335d..965241e 100644 --- a/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathRpa.ivyClass +++ b/ui-path-connector/dataclasses/com/axonivy/connector/uipath/ui/path/connector/UiPathRpa.ivyClass @@ -5,3 +5,4 @@ license com.uipath.orchestrator.LicenseDto #field jobs List #field robots List #field releases List #field +organizationunitId Long #field diff --git a/ui-path-connector/lib/generated/rest/jaxRsClient_c700c640-4f76-4cbe-8724-dbc663d8bc0a.jar b/ui-path-connector/lib/generated/rest/jaxRsClient_c700c640-4f76-4cbe-8724-dbc663d8bc0a.jar index d26f17f..ba40c09 100644 Binary files a/ui-path-connector/lib/generated/rest/jaxRsClient_c700c640-4f76-4cbe-8724-dbc663d8bc0a.jar and b/ui-path-connector/lib/generated/rest/jaxRsClient_c700c640-4f76-4cbe-8724-dbc663d8bc0a.jar differ diff --git a/ui-path-connector/pom.xml b/ui-path-connector/pom.xml index 791b344..054c3f4 100644 --- a/ui-path-connector/pom.xml +++ b/ui-path-connector/pom.xml @@ -3,14 +3,14 @@ 4.0.0 com.axonivy.connector.uipath ui-path-connector - 10.0.2-SNAPSHOT + 10.0.1.0-SNAPSHOT iar com.axonivy.ivy.ci project-build-plugin - 10.0.6 + 10.0.16 true diff --git a/ui-path-connector/processes/uiPathJob.p.json b/ui-path-connector/processes/uiPathJob.p.json new file mode 100644 index 0000000..8355b4e --- /dev/null +++ b/ui-path-connector/processes/uiPathJob.p.json @@ -0,0 +1,417 @@ +{ + "format" : "10.0.0", + "id" : "190E93ECBBC86C6F", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "com.axonivy.connector.uipath.ui.path.connector.UiPathJobData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "startAllActiveJobs()", + "config" : { + "callSignature" : "startAllActiveJobs" + }, + "visual" : { + "at" : { "x" : 128, "y" : 64 }, + "icon" : "res:/webContent/icons/uipath.png?small" + }, + "connect" : { "id" : "f21", "to" : "f12" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 720, "y" : 64 } + } + }, { + "id" : "f15", + "type" : "Script", + "name" : "Remove proceed Job", + "config" : { + "output" : { + "code" : "in.releases.removeAt(0);" + } + }, + "visual" : { + "at" : { "x" : 608, "y" : 176 } + }, + "connect" : { "id" : "f18", "to" : "f17", "via" : [ { "x" : 608, "y" : 112 } ] } + }, { + "id" : "f17", + "type" : "Alternative", + "name" : "hasRelease?", + "visual" : { + "at" : { "x" : 448, "y" : 64 }, + "labelOffset" : { "x" : 16, "y" : -24 } + }, + "connect" : [ + { "id" : "f20", "to" : "f1", "label" : { + "name" : "no" + }, "condition" : "in.releases.isEmpty()" }, + { "id" : "f6", "to" : "f4", "label" : { + "name" : "yes" + } } + ] + }, { + "id" : "f10", + "type" : "CallSubStart", + "name" : "startJobByName(String,String)", + "config" : { + "callSignature" : "startJobByName", + "input" : { + "params" : [ + { "name" : "jobName", "type" : "String" }, + { "name" : "jobArguments", "type" : "String" } + ], + "map" : { + "out.jobArguments" : "param.jobArguments", + "out.jobName" : "param.jobName" + } + } + }, + "visual" : { + "at" : { "x" : 128, "y" : 288 }, + "icon" : "res:/webContent/icons/uipath.png?small" + }, + "connect" : { "id" : "f44", "to" : "f43" } + }, { + "id" : "f11", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 720, "y" : 288 } + } + }, { + "id" : "f25", + "type" : "Script", + "name" : "Remove proceed Job", + "config" : { + "output" : { + "code" : "in.releases.removeAt(0);" + } + }, + "visual" : { + "at" : { "x" : 608, "y" : 408 } + }, + "connect" : { "id" : "f30", "to" : "f26", "via" : [ { "x" : 608, "y" : 328 } ] } + }, { + "id" : "f26", + "type" : "Alternative", + "name" : "hasRelease?", + "visual" : { + "at" : { "x" : 448, "y" : 288 }, + "labelOffset" : { "x" : 16, "y" : -16 } + }, + "connect" : [ + { "id" : "f35", "to" : "f11", "label" : { + "name" : "no" + }, "condition" : "in.releases.isEmpty()" }, + { "id" : "f27", "to" : "f22", "label" : { + "name" : "yes" + } } + ] + }, { + "id" : "f14", + "type" : "CallSubStart", + "name" : "getReleases(String)", + "config" : { + "callSignature" : "getReleases", + "input" : { + "params" : [ + { "name" : "name", "type" : "String", "desc" : "Optional field" } + ], + "map" : { + "out.jobName" : "param.name" + } + }, + "result" : { + "params" : [ + { "name" : "releases", "type" : "java.util.List" }, + { "name" : "orgId", "type" : "Long" } + ], + "map" : { + "result.releases" : "in.releases", + "result.orgId" : "in.organizationunitId" + } + } + }, + "visual" : { + "at" : { "x" : 128, "y" : 528 }, + "icon" : "res:/webContent/icons/uipath.png?small" + }, + "connect" : { "id" : "f39", "to" : "f37" } + }, { + "id" : "f37", + "type" : "RestClientCall", + "name" : [ + "**RPA**: UI Path", + "Folders" + ], + "config" : { + "path" : "/odata/Folders", + "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", + "clientErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : "ivy:error:rest:client", + "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfFolderDto", + "responseCode" : [ + "// Should throw exception if no organizationunitId found", + "out.organizationunitId = result.value.get(0).id;" + ] + }, + "visual" : { + "at" : { "x" : 280, "y" : 528 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f9", "to" : "f7" } + }, { + "id" : "f38", + "type" : "RestClientCall", + "name" : [ + "**RPA**: UI Path", + "Releases" + ], + "config" : { + "path" : "/odata/Releases", + "headers" : { + "Accept" : "*/*", + "X-Uipath-Organizationunitid" : "in.organizationunitId" + }, + "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", + "clientErrorCode" : "ivy:error:rest:client", + "queryParams" : { + "mandatoryPermissions" : "", + "atLeastOnePermissions" : "", + "$expand" : "", + "$filter" : "in.#filter is initialized ? in.#filter : null", + "$select" : "", + "$orderby" : "", + "$top" : "", + "$skip" : "", + "$count" : "" + }, + "statusErrorCode" : "ivy:error:rest:client", + "responseMapping" : { + "out.releases" : "result.value" + }, + "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfReleaseDto", + "responseCode" : "ivy.log.warn(\"Found release {0}\", result.value.size());" + }, + "visual" : { + "at" : { "x" : 608, "y" : 528 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f42", "to" : "f41" } + }, { + "id" : "f41", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 760, "y" : 528 } + } + }, { + "id" : "f43", + "type" : "SubProcessCall", + "name" : "Get Releases", + "config" : { + "processCall" : "uiPathJob:getReleases(String)", + "output" : { + "map" : { + "out" : "in", + "out.organizationunitId" : "result.orgId", + "out.releases" : "result.releases" + } + }, + "call" : { + "params" : [ + { "name" : "name", "type" : "String" } + ], + "map" : { + "param.name" : "in.jobName" + } + } + }, + "visual" : { + "at" : { "x" : 280, "y" : 288 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f5", "to" : "f26" } + }, { + "id" : "f12", + "type" : "SubProcessCall", + "name" : "Get Releases", + "config" : { + "processCall" : "uiPathJob:getReleases(String)", + "output" : { + "map" : { + "out" : "in", + "out.organizationunitId" : "result.orgId", + "out.releases" : "result.releases" + } + }, + "call" : { + "params" : [ + { "name" : "name", "type" : "String" } + ] + } + }, + "visual" : { + "at" : { "x" : 280, "y" : 64 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f23", "to" : "f17" } + }, { + "id" : "f2", + "type" : "RestClientCall", + "name" : [ + "**RPA**: UI Path", + "Machines" + ], + "config" : { + "path" : "/odata/Machines", + "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", + "clientErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : "ivy:error:rest:client", + "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfExtendedMachineDto", + "responseCode" : [ + "import com.uipath.orchestrator.MachineRobotDto;", + "import com.uipath.orchestrator.ExtendedMachineDto;", + "for (ExtendedMachineDto exMachineDto : result.value) {", + " MachineRobotDto robot = new MachineRobotDto();", + " robot.machineId = exMachineDto.id;", + " robot.machineName = exMachineDto.name;", + " in.machines.add(robot);", + "}", + "in.startInfo.machineRobots = in.machines;" + ] + }, + "visual" : { + "at" : { "x" : 280, "y" : 680 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f8", "to" : "f3" } + }, { + "id" : "f3", + "type" : "RestClientCall", + "name" : [ + "**RPA**: UI Path", + "StartJobs" + ], + "config" : { + "path" : "/odata/Jobs/UiPath.Server.Configuration.OData.StartJobs", + "headers" : { + "Accept" : "*/*", + "X-Uipath-Organizationunitid" : "in.organizationunitId" + }, + "bodyObjectMapping" : { + "param.startInfo" : "in.startInfo" + }, + "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", + "clientErrorCode" : "ivy:error:rest:client", + "method" : "POST", + "statusErrorCode" : "ivy:error:rest:client", + "bodyObjectType" : "com.uipath.orchestrator.StartJobsRequest", + "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfJobDto", + "bodyInputType" : "ENTITY" + }, + "visual" : { + "at" : { "x" : 448, "y" : 680 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f28", "to" : "f50" } + }, { + "id" : "f49", + "type" : "CallSubStart", + "name" : "startJob(Long,String,ReleaseDto)", + "config" : { + "callSignature" : "startJob", + "input" : { + "params" : [ + { "name" : "orgId", "type" : "Long", "desc" : "Required field" }, + { "name" : "argument", "type" : "String", "desc" : "Optional field" }, + { "name" : "release", "type" : "com.uipath.orchestrator.ReleaseDto", "desc" : "Required field" } + ], + "map" : { + "out.organizationunitId" : "param.orgId" + }, + "code" : [ + "import com.axonivy.connector.uipath.constant.Constant;", + "import org.apache.commons.lang3.StringUtils;", + "out.startInfo.inputArguments = StringUtils.isBlank(param.argument) ? Constant.DEFAULT_ARGUMENT : param.argument;", + "out.startInfo.jobsCount = 1;", + "out.startInfo.resumeOnSameContext = true;", + "out.startInfo.strategy = com.uipath.orchestrator.StartProcessDto.StrategyEnum.MODERNJOBSCOUNT;", + "out.startInfo.releaseKey = param.release.key;" + ] + } + }, + "visual" : { + "at" : { "x" : 128, "y" : 680 }, + "icon" : "res:/webContent/icons/uipath.png?small" + }, + "connect" : { "id" : "f51", "to" : "f2" } + }, { + "id" : "f50", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 608, "y" : 680 } + } + }, { + "id" : "f22", + "type" : "SubProcessCall", + "name" : "Start UIPath Job", + "config" : { + "processCall" : "uiPathJob:startJob(Long,String,com.uipath.orchestrator.ReleaseDto)", + "call" : { + "params" : [ + { "name" : "orgId", "type" : "Long" }, + { "name" : "argument", "type" : "String" }, + { "name" : "release", "type" : "com.uipath.orchestrator.ReleaseDto" } + ], + "map" : { + "param.orgId" : "in.organizationunitId", + "param.argument" : "in.jobArguments", + "param.release" : "in.releases.get(0)" + } + } + }, + "visual" : { + "at" : { "x" : 448, "y" : 408 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f33", "to" : "f25" } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "Start UIPath Job", + "config" : { + "processCall" : "uiPathJob:startJob(Long,String,com.uipath.orchestrator.ReleaseDto)", + "call" : { + "params" : [ + { "name" : "orgId", "type" : "Long" }, + { "name" : "argument", "type" : "String" }, + { "name" : "release", "type" : "com.uipath.orchestrator.ReleaseDto" } + ], + "map" : { + "param.orgId" : "in.organizationunitId", + "param.release" : "in.releases.get(0)" + } + } + }, + "visual" : { + "at" : { "x" : 448, "y" : 176 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f19", "to" : "f15" } + }, { + "id" : "f7", + "type" : "Script", + "name" : "Build filter", + "config" : { + "output" : { + "code" : "in.filter = com.axonivy.connector.uipath.builder.FilterBuilder.newInstance().name(in.jobName).build();" + } + }, + "visual" : { + "at" : { "x" : 448, "y" : 528 } + }, + "connect" : { "id" : "f13", "to" : "f38" } + } ] +} \ No newline at end of file diff --git a/ui-path-connector/processes/uiPathRpa.p.json b/ui-path-connector/processes/uiPathRpa.p.json index 60de63e..e5d9c96 100644 --- a/ui-path-connector/processes/uiPathRpa.p.json +++ b/ui-path-connector/processes/uiPathRpa.p.json @@ -34,7 +34,8 @@ "description" : [ "Simple request against RPA Orchestration Platform provided by UIPath", " (mainly to enforce an active OAUTH session)" - ] + ], + "icon" : "res:/webContent/icons/uipath.png" }, "connect" : { "id" : "f6", "to" : "f5" } }, { @@ -57,9 +58,10 @@ }, "visual" : { "at" : { "x" : 472, "y" : 64 }, - "size" : { "width" : 128, "height" : 60 } + "size" : { "width" : 128, "height" : 60 }, + "icon" : "res:/webContent/icons/uipath.png" }, - "connect" : { "id" : "f2", "to" : "f0" } + "connect" : { "id" : "f1", "to" : "f37" } }, { "id" : "f0", "type" : "RestClientCall", @@ -69,6 +71,10 @@ ], "config" : { "path" : "/odata/Robots", + "headers" : { + "Accept" : "*/*", + "X-Uipath-Organizationunitid" : "in.organizationunitId" + }, "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", "clientErrorCode" : "ivy:error:rest:client", "method" : "GET", @@ -92,8 +98,9 @@ "responseCode" : "ivy.log.info(\"found \"+result.value.size()+\" RPA robots\");" }, "visual" : { - "at" : { "x" : 472, "y" : 144 }, - "size" : { "width" : 128, "height" : 60 } + "at" : { "x" : 472, "y" : 224 }, + "size" : { "width" : 128, "height" : 60 }, + "icon" : "res:/webContent/icons/uipath.png" }, "connect" : { "id" : "f4", "to" : "f22" } }, { @@ -130,8 +137,9 @@ "responseCode" : "ivy.log.info(\"found \"+result.value.size()+\" Process releases\");" }, "visual" : { - "at" : { "x" : 472, "y" : 224 }, - "size" : { "width" : 128, "height" : 60 } + "at" : { "x" : 472, "y" : 304 }, + "size" : { "width" : 128, "height" : 60 }, + "icon" : "res:/webContent/icons/uipath.png" }, "connect" : { "id" : "f8", "to" : "f24" } }, { @@ -174,8 +182,9 @@ "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfJobDto" }, "visual" : { - "at" : { "x" : 472, "y" : 304 }, - "size" : { "width" : 128, "height" : 60 } + "at" : { "x" : 472, "y" : 384 }, + "size" : { "width" : 128, "height" : 60 }, + "icon" : "res:/webContent/icons/uipath.png" }, "connect" : { "id" : "f9", "to" : "f15" } }, { @@ -213,7 +222,30 @@ "id" : "f15", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 608, "y" : 304 } + "at" : { "x" : 608, "y" : 384 } } + }, { + "id" : "f37", + "type" : "RestClientCall", + "name" : [ + "**RPA**: UI Path", + "Folders" + ], + "config" : { + "path" : "/odata/Folders", + "clientId" : "c700c640-4f76-4cbe-8724-dbc663d8bc0a", + "clientErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : "ivy:error:rest:client", + "responseMapping" : { + "out.organizationunitId" : "result.value.get(0).id" + }, + "resultType" : "com.uipath.orchestrator.ODataValueOfIEnumerableOfFolderDto" + }, + "visual" : { + "at" : { "x" : 472, "y" : 144 }, + "size" : { "width" : 128, "height" : 60 }, + "icon" : "res:/webContent/icons/uipath.png" + }, + "connect" : { "id" : "f2", "to" : "f0" } } ] } \ No newline at end of file diff --git a/ui-path-connector/src/com/axonivy/connector/uipath/builder/FilterBuilder.java b/ui-path-connector/src/com/axonivy/connector/uipath/builder/FilterBuilder.java new file mode 100644 index 0000000..7752f98 --- /dev/null +++ b/ui-path-connector/src/com/axonivy/connector/uipath/builder/FilterBuilder.java @@ -0,0 +1,28 @@ +package com.axonivy.connector.uipath.builder; + +import org.apache.commons.lang3.StringUtils; +import static org.apache.commons.lang3.StringUtils.EMPTY; + +import com.axonivy.connector.uipath.enums.FilterProperty; + +public class FilterBuilder { + + public static final String EQUALS_PATTERN = "%s eq '%s'"; + private String filterQuery = EMPTY; + + public static FilterBuilder newInstance() { + return new FilterBuilder(); + } + + public FilterBuilder name(String name) { + if (StringUtils.isNotBlank(name)) { + var filterByName = EQUALS_PATTERN.formatted(FilterProperty.NAME.getKey(), name); + filterQuery = filterQuery.concat(filterByName); + } + return this; + } + + public String build() { + return StringUtils.isBlank(filterQuery) ? null : filterQuery; + } +} diff --git a/ui-path-connector/src/com/axonivy/connector/uipath/constant/Constant.java b/ui-path-connector/src/com/axonivy/connector/uipath/constant/Constant.java new file mode 100644 index 0000000..8c2a9dc --- /dev/null +++ b/ui-path-connector/src/com/axonivy/connector/uipath/constant/Constant.java @@ -0,0 +1,6 @@ +package com.axonivy.connector.uipath.constant; + +public class Constant { + public static final String DEFAULT_ARGUMENT = "{}"; + +} diff --git a/ui-path-connector/src/com/axonivy/connector/uipath/enums/FilterProperty.java b/ui-path-connector/src/com/axonivy/connector/uipath/enums/FilterProperty.java new file mode 100644 index 0000000..6e7d6b2 --- /dev/null +++ b/ui-path-connector/src/com/axonivy/connector/uipath/enums/FilterProperty.java @@ -0,0 +1,20 @@ +package com.axonivy.connector.uipath.enums; + +public enum FilterProperty { + KEY("Key"), PROCESS_KEY("ProcessKey"), LATEST_VERSION("IsLatestVersion"), NAME("Name"), PROCESS_TYPE("ProcessType"), + ATTENDED("IsAttended"), COMPILED("IsCompiled"), JOB_PRIORITY("JobPriority"), ID("Id"), TAGS("Tags"); + + private String key; + + private FilterProperty(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +}