diff --git a/docs/src/content/docs/reference/components/webflow.md b/docs/src/content/docs/reference/components/webflow.md new file mode 100644 index 00000000000..2588e5386f0 --- /dev/null +++ b/docs/src/content/docs/reference/components/webflow.md @@ -0,0 +1,111 @@ +--- +title: "Webflow" +description: "Webflow is a web design and development platform that allows users to build responsive websites visually without writing code." +--- +## Reference +
+ +Webflow is a web design and development platform that allows users to build responsive websites visually without writing code. + + +Categories: [developer-tools] + + +Version: 1 + +
+ + + +## Connections + +Version: 1 + + +### OAuth2 Authorization Code + +#### Properties + +| Name | Type | Control Type | Description | +|:--------------:|:------------:|:--------------------:|:-------------------:| +| Client Id | STRING | TEXT | | +| Client Secret | STRING | TEXT | | + + + + + +
+ + + +## Triggers + + + +
+ + + +## Actions + + +### Fulfill Order +Updates an order's status to fulfilled. + +#### Properties + +| Name | Type | Control Type | Description | +|:--------------:|:------------:|:--------------------:|:-------------------:| +| Site | STRING | SELECT | | +| Order | STRING | SELECT | | + + +### Output + + + +Type: OBJECT + + +#### Properties + +| Type | Control Type | +|:------------:|:--------------------:| +| {STRING\(orderId), STRING\(status)} | OBJECT_BUILDER | + + + + + + +### Get Collection Item +Get collection item in a collection. + +#### Properties + +| Name | Type | Control Type | Description | +|:--------------:|:------------:|:--------------------:|:-------------------:| +| Site | STRING | SELECT | | +| Collection | STRING | SELECT | | +| Item | STRING | SELECT | | + + +### Output + + + +Type: OBJECT + + +#### Properties + +| Type | Control Type | +|:------------:|:--------------------:| +| {STRING\(id), {STRING\(name), STRING\(slug)}\(fieldData)} | OBJECT_BUILDER | + + + + + + diff --git a/server/apps/server-app/build.gradle.kts b/server/apps/server-app/build.gradle.kts index 40a5366dfee..8d6b54ddec5 100644 --- a/server/apps/server-app/build.gradle.kts +++ b/server/apps/server-app/build.gradle.kts @@ -228,6 +228,7 @@ dependencies { implementation(project(":server:libs:modules:components:typeform")) implementation(project(":server:libs:modules:components:var")) implementation(project(":server:libs:modules:components:vtiger")) + implementation(project(":server:libs:modules:components:webflow")) implementation(project(":server:libs:modules:components:webhook")) implementation(project(":server:libs:modules:components:whatsapp")) implementation(project(":server:libs:modules:components:xero")) diff --git a/server/ee/apps/worker-app/build.gradle.kts b/server/ee/apps/worker-app/build.gradle.kts index 149a04de231..474601972f9 100644 --- a/server/ee/apps/worker-app/build.gradle.kts +++ b/server/ee/apps/worker-app/build.gradle.kts @@ -149,6 +149,7 @@ dependencies { implementation(project(":server:libs:modules:components:typeform")) implementation(project(":server:libs:modules:components:var")) implementation(project(":server:libs:modules:components:vtiger")) + implementation(project(":server:libs:modules:components:webflow")) implementation(project(":server:libs:modules:components:webhook")) implementation(project(":server:libs:modules:components:whatsapp")) implementation(project(":server:libs:modules:components:xero")) diff --git a/server/libs/modules/components/webflow/openapi.yaml b/server/libs/modules/components/webflow/openapi.yaml new file mode 100644 index 00000000000..1423e1b14c9 --- /dev/null +++ b/server/libs/modules/components/webflow/openapi.yaml @@ -0,0 +1,96 @@ +--- +openapi: "3.0.1" +info: + title: "Webflow" + description: "Webflow is a web design and development platform that allows users to build responsive websites visually without writing code." + version: "v1" +servers: + - url: "https://api.webflow.com" +paths: + /v2/sites/{siteId}/orders/{orderId}/fulfill: + post: + summary: "Fulfill Order" + description: "Updates an order's status to fulfilled." + operationId: "fulfillOrder" + parameters: + - name: "siteId" + in: "path" + required: true + schema: + type: "string" + title: "Site" + - name: "orderId" + in: "path" + required: true + schema: + type: "string" + title: "Order" + responses: + 200: + description: "Successful operation" + content: + application/json: + schema: + type: "object" + properties: + body: + type: "object" + properties: + orderId: + type: "string" + status: + type: "string" + /v2/collections/{collectionId}/item/{itemId}: + get: + summary: "Get Collection Item" + description: "Get collection item in a collection." + operationId: "getCollectionItem" + parameters: + - name: "collectionId" + in: "path" + description: "" + required: true + schema: + type: "string" + title: "Collection" + - name: "itemId" + in: "path" + description: "" + required: true + schema: + type: "string" + title: "Item" + responses: + 200: + description: "Successful operation" + content: + application/json: + schema: + type: "object" + properties: + body: + type: "object" + properties: + id: + type: "string" + fieldData: + type: "object" + properties: + name: + type: "string" + slug: + type: "string" +components: + securitySchemes: + oauth2: + type: "oauth2" + flows: + authorizationCode: + authorizationUrl: "https://webflow.com/oauth/authorize" + tokenUrl: "https://api.webflow.com/oauth/access_token" + refreshUrl: "https://api.webflow.com/oauth/access_token" + scopes: + cms:read: " " + ecommerce:read: " " + ecommerce:write: " " + sites:read: "" diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/AbstractWebflowComponentHandler.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/AbstractWebflowComponentHandler.java new file mode 100644 index 00000000000..0d4c7fe09a5 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/AbstractWebflowComponentHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow; + +import static com.bytechef.component.definition.ComponentDsl.component; + +import com.bytechef.component.OpenApiComponentHandler; +import com.bytechef.component.definition.ComponentDefinition; +import com.bytechef.component.webflow.action.WebflowFulfillOrderAction; +import com.bytechef.component.webflow.action.WebflowGetCollectionItemAction; +import com.bytechef.component.webflow.connection.WebflowConnection; + +/** + * Provides the base implementation for the REST based component. + * + * @generated + */ +public abstract class AbstractWebflowComponentHandler implements OpenApiComponentHandler { + private final ComponentDefinition componentDefinition = modifyComponent( + component("webflow") + .title("Webflow") + .description( + "Webflow is a web design and development platform that allows users to build responsive websites visually without writing code.")) + .actions(modifyActions(WebflowFulfillOrderAction.ACTION_DEFINITION, + WebflowGetCollectionItemAction.ACTION_DEFINITION)) + .connection(modifyConnection(WebflowConnection.CONNECTION_DEFINITION)) + .triggers(getTriggers()); + + @Override + public ComponentDefinition getDefinition() { + return componentDefinition; + } +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/WebflowComponentHandler.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/WebflowComponentHandler.java new file mode 100644 index 00000000000..bc046cc7b53 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/WebflowComponentHandler.java @@ -0,0 +1,99 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow; + +import static com.bytechef.component.definition.ComponentDsl.string; +import static com.bytechef.component.webflow.constant.WebflowConstants.COLLECTION_ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.ORDER_ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.SITE_ID; + +import com.bytechef.component.OpenApiComponentHandler; +import com.bytechef.component.definition.ActionDefinition; +import com.bytechef.component.definition.ComponentCategory; +import com.bytechef.component.definition.ComponentDsl.ModifiableActionDefinition; +import com.bytechef.component.definition.ComponentDsl.ModifiableComponentDefinition; +import com.bytechef.component.definition.ComponentDsl.ModifiableProperty; +import com.bytechef.component.definition.ComponentDsl.ModifiableStringProperty; +import com.bytechef.component.definition.OptionsDataSource.ActionOptionsFunction; +import com.bytechef.component.definition.Property; +import com.bytechef.component.webflow.util.WebflowUtils; +import com.google.auto.service.AutoService; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * @author Monika Kušter + */ +@AutoService(OpenApiComponentHandler.class) +public class WebflowComponentHandler extends AbstractWebflowComponentHandler { + + @Override + public List modifyActions(ModifiableActionDefinition... actionDefinitions) { + + for (ModifiableActionDefinition modifiableActionDefinition : actionDefinitions) { + if (Objects.equals(modifiableActionDefinition.getName(), "getCollectionItem")) { + Optional> propertiesOptional = modifiableActionDefinition.getProperties(); + + List properties = new ArrayList<>(propertiesOptional.get()); + + properties.addFirst( + string(SITE_ID) + .label("Site") + .options((ActionOptionsFunction) WebflowUtils::getSiteOptions) + .required(true)); + + modifiableActionDefinition.properties(properties); + } + } + + return super.modifyActions(actionDefinitions); + } + + @Override + public ModifiableComponentDefinition modifyComponent(ModifiableComponentDefinition modifiableComponentDefinition) { + return modifiableComponentDefinition + .customAction(true) + .icon("path:assets/webflow.svg") + .categories(ComponentCategory.DEVELOPER_TOOLS); + } + + @Override + public ModifiableProperty modifyProperty( + ActionDefinition actionDefinition, ModifiableProperty modifiableProperty) { + + if (Objects.equals(modifiableProperty.getName(), SITE_ID)) { + ((ModifiableStringProperty) modifiableProperty) + .options((ActionOptionsFunction) WebflowUtils::getSiteOptions); + } else if (Objects.equals(modifiableProperty.getName(), ORDER_ID)) { + ((ModifiableStringProperty) modifiableProperty) + .options((ActionOptionsFunction) WebflowUtils::getOrderOptions) + .optionsLookupDependsOn(SITE_ID); + } else if (Objects.equals(modifiableProperty.getName(), COLLECTION_ID)) { + ((ModifiableStringProperty) modifiableProperty) + .options((ActionOptionsFunction) WebflowUtils::getCollectionOptions) + .optionsLookupDependsOn(SITE_ID); + } else if (Objects.equals(modifiableProperty.getName(), "itemId")) { + ((ModifiableStringProperty) modifiableProperty) + .options((ActionOptionsFunction) WebflowUtils::getCollectionItemOptions) + .optionsLookupDependsOn(COLLECTION_ID, SITE_ID); + } + + return modifiableProperty; + } +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowFulfillOrderAction.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowFulfillOrderAction.java new file mode 100644 index 00000000000..8b58bbd5dd3 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowFulfillOrderAction.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.action; + +import static com.bytechef.component.OpenApiComponentHandler.PropertyType; +import static com.bytechef.component.definition.ComponentDsl.action; +import static com.bytechef.component.definition.ComponentDsl.object; +import static com.bytechef.component.definition.ComponentDsl.outputSchema; +import static com.bytechef.component.definition.ComponentDsl.string; +import static com.bytechef.component.definition.Context.Http.ResponseType; + +import com.bytechef.component.definition.ComponentDsl; +import java.util.Map; + +/** + * Provides a list of the component actions. + * + * @generated + */ +public class WebflowFulfillOrderAction { + public static final ComponentDsl.ModifiableActionDefinition ACTION_DEFINITION = action("fulfillOrder") + .title("Fulfill Order") + .description("Updates an order's status to fulfilled.") + .metadata( + Map.of( + "method", "POST", + "path", "/v2/sites/{siteId}/orders/{orderId}/fulfill" + + )) + .properties(string("siteId").label("Site") + .required(true) + .metadata( + Map.of( + "type", PropertyType.PATH)), + string("orderId").label("Order") + .required(true) + .metadata( + Map.of( + "type", PropertyType.PATH))) + .output(outputSchema(object() + .properties(object("body").properties(string("orderId").required(false), string("status").required(false)) + .required(false)) + .metadata( + Map.of( + "responseType", ResponseType.JSON)))); + + private WebflowFulfillOrderAction() { + } +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowGetCollectionItemAction.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowGetCollectionItemAction.java new file mode 100644 index 00000000000..6d01a44f819 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/action/WebflowGetCollectionItemAction.java @@ -0,0 +1,68 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.action; + +import static com.bytechef.component.OpenApiComponentHandler.PropertyType; +import static com.bytechef.component.definition.ComponentDsl.action; +import static com.bytechef.component.definition.ComponentDsl.object; +import static com.bytechef.component.definition.ComponentDsl.outputSchema; +import static com.bytechef.component.definition.ComponentDsl.string; +import static com.bytechef.component.definition.Context.Http.ResponseType; + +import com.bytechef.component.definition.ComponentDsl; +import java.util.Map; + +/** + * Provides a list of the component actions. + * + * @generated + */ +public class WebflowGetCollectionItemAction { + public static final ComponentDsl.ModifiableActionDefinition ACTION_DEFINITION = action("getCollectionItem") + .title("Get Collection Item") + .description("Get collection item in a collection.") + .metadata( + Map.of( + "method", "GET", + "path", "/v2/collections/{collectionId}/item/{itemId}" + + )) + .properties(string("collectionId").label("Collection") + .description("") + .required(true) + .metadata( + Map.of( + "type", PropertyType.PATH)), + string("itemId").label("Item") + .description("") + .required(true) + .metadata( + Map.of( + "type", PropertyType.PATH))) + .output(outputSchema(object() + .properties(object("body") + .properties(string("id").required(false), + object("fieldData").properties(string("name").required(false), string("slug").required(false)) + .required(false)) + .required(false)) + .metadata( + Map.of( + "responseType", ResponseType.JSON)))); + + private WebflowGetCollectionItemAction() { + } +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/connection/WebflowConnection.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/connection/WebflowConnection.java new file mode 100644 index 00000000000..a5d132834a9 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/connection/WebflowConnection.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.connection; + +import static com.bytechef.component.definition.Authorization.AuthorizationType; +import static com.bytechef.component.definition.Authorization.CLIENT_ID; +import static com.bytechef.component.definition.Authorization.CLIENT_SECRET; +import static com.bytechef.component.definition.ComponentDsl.authorization; +import static com.bytechef.component.definition.ComponentDsl.connection; +import static com.bytechef.component.definition.ComponentDsl.string; + +import com.bytechef.component.definition.ComponentDsl; +import java.util.List; + +/** + * Provides the component connection definition. + * + * @generated + */ +public class WebflowConnection { + public static final ComponentDsl.ModifiableConnectionDefinition CONNECTION_DEFINITION = connection() + .baseUri((connectionParameters, context) -> "https://api.webflow.com") + .authorizations(authorization(AuthorizationType.OAUTH2_AUTHORIZATION_CODE) + .title("OAuth2 Authorization Code") + .properties( + string(CLIENT_ID) + .label("Client Id") + .required(true), + string(CLIENT_SECRET) + .label("Client Secret") + .required(true)) + .authorizationUrl((connectionParameters, context) -> "https://webflow.com/oauth/authorize") + .scopes((connection, context) -> List.of("cms:read", "ecommerce:read", "ecommerce:write", "sites:read")) + .tokenUrl((connectionParameters, context) -> "https://api.webflow.com/oauth/access_token") + .refreshUrl((connectionParameters, context) -> "https://api.webflow.com/oauth/access_token")); + + private WebflowConnection() { + } +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/constant/WebflowConstants.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/constant/WebflowConstants.java new file mode 100644 index 00000000000..b691e5dc570 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/constant/WebflowConstants.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.constant; + +/** + * @author Monika Kušter + */ +public class WebflowConstants { + + private WebflowConstants() { + } + + public static final String COLLECTION_ID = "collectionId"; + public static final String DISPLAY_NAME = "displayName"; + public static final String ID = "id"; + public static final String ORDER_ID = "orderId"; + public static final String SITE_ID = "siteId"; +} diff --git a/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/util/WebflowUtils.java b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/util/WebflowUtils.java new file mode 100644 index 00000000000..38e5e5d9040 --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/java/com/bytechef/component/webflow/util/WebflowUtils.java @@ -0,0 +1,120 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.util; + +import static com.bytechef.component.definition.ComponentDsl.option; +import static com.bytechef.component.webflow.constant.WebflowConstants.COLLECTION_ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.DISPLAY_NAME; +import static com.bytechef.component.webflow.constant.WebflowConstants.ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.ORDER_ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.SITE_ID; + +import com.bytechef.component.definition.ActionContext; +import com.bytechef.component.definition.Context.Http; +import com.bytechef.component.definition.Option; +import com.bytechef.component.definition.Parameters; +import com.bytechef.component.definition.TypeReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Monika Kušter + */ +public class WebflowUtils { + + private WebflowUtils() { + } + + public static List> getCollectionItemOptions( + Parameters inputParameters, Parameters connectionParameters, Map dependencyPaths, + String searchText, ActionContext context) { + + Map>> body = context + .http(http -> http.get("/collections/" + inputParameters.getRequiredString(COLLECTION_ID) + "/items")) + .configuration(Http.responseType(Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() {}); + + List> options = new ArrayList<>(); + + for (Map map : body.get("items")) { + if (map.get("fieldData") instanceof Map fieldDataMap) { + options.add(option((String) fieldDataMap.get("name"), (String) map.get(ID))); + } + } + + return options; + } + + public static List> getCollectionOptions( + Parameters inputParameters, Parameters connectionParameters, Map dependencyPaths, + String searchText, ActionContext context) { + + Map>> body = context + .http(http -> http.get("/sites/" + inputParameters.getRequiredString(SITE_ID) + "/collections")) + .configuration(Http.responseType(Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() {}); + + List> options = new ArrayList<>(); + + for (Map map : body.get("collections")) { + options.add(option((String) map.get(DISPLAY_NAME), (String) map.get(ID))); + } + + return options; + } + + public static List> getOrderOptions( + Parameters inputParameters, Parameters connectionParameters, Map dependencyPaths, + String searchText, ActionContext context) { + + Map>> body = context + .http(http -> http.get("/sites/" + inputParameters.getRequiredString(SITE_ID) + "/orders")) + .configuration(Http.responseType(Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() {}); + + List> options = new ArrayList<>(); + + for (Map map : body.get("orders")) { + options.add(option((String) map.get(ORDER_ID), (String) map.get(ORDER_ID))); + } + + return options; + } + + public static List> getSiteOptions( + Parameters inputParameters, Parameters connectionParameters, Map dependencyPaths, + String searchText, ActionContext context) { + + Map>> body = context + .http(http -> http.get("/sites")) + .configuration(Http.responseType(Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() {}); + + List> options = new ArrayList<>(); + + for (Map map : body.get("sites")) { + options.add(option((String) map.get(DISPLAY_NAME), (String) map.get(ID))); + } + + return options; + } +} diff --git a/server/libs/modules/components/webflow/src/main/resources/assets/webflow.svg b/server/libs/modules/components/webflow/src/main/resources/assets/webflow.svg new file mode 100644 index 00000000000..5670e95759e --- /dev/null +++ b/server/libs/modules/components/webflow/src/main/resources/assets/webflow.svg @@ -0,0 +1 @@ + diff --git a/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/AbstractWebflowComponentHandlerTest.java b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/AbstractWebflowComponentHandlerTest.java new file mode 100644 index 00000000000..28119661c3e --- /dev/null +++ b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/AbstractWebflowComponentHandlerTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow; + +import com.bytechef.test.jsonasssert.JsonFileAssert; +import org.junit.jupiter.api.Test; + +/** + * Provides the base test implementation for the REST based component. + * + * @generated + */ +public abstract class AbstractWebflowComponentHandlerTest { + @Test + public void testGetDefinition() { + JsonFileAssert.assertEquals("definition/webflow_v1.json", new WebflowComponentHandler().getDefinition()); + } +} diff --git a/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/WebflowComponentHandlerTest.java b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/WebflowComponentHandlerTest.java new file mode 100644 index 00000000000..a4afc205e60 --- /dev/null +++ b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/WebflowComponentHandlerTest.java @@ -0,0 +1,23 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow; + +/** + * @generated + */ +public class WebflowComponentHandlerTest extends AbstractWebflowComponentHandlerTest { +} diff --git a/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/util/WebflowUtilsTest.java b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/util/WebflowUtilsTest.java new file mode 100644 index 00000000000..d5aa4b011a1 --- /dev/null +++ b/server/libs/modules/components/webflow/src/test/java/com/bytechef/component/webflow/util/WebflowUtilsTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2023-present ByteChef Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.webflow.util; + +import static com.bytechef.component.definition.ComponentDsl.option; +import static com.bytechef.component.webflow.constant.WebflowConstants.DISPLAY_NAME; +import static com.bytechef.component.webflow.constant.WebflowConstants.ID; +import static com.bytechef.component.webflow.constant.WebflowConstants.ORDER_ID; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.bytechef.component.definition.ActionContext; +import com.bytechef.component.definition.Context.Http; +import com.bytechef.component.definition.Option; +import com.bytechef.component.definition.Parameters; +import com.bytechef.component.definition.TypeReference; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * @author Monika Kušter + */ +class WebflowUtilsTest { + + private final List> expectedOptions = List.of(option("abc", "123")); + private final ActionContext mockedActionContext = mock(ActionContext.class); + private final Http.Executor mockedExecutor = mock(Http.Executor.class); + private final Parameters mockedParameters = mock(Parameters.class); + private final Http.Response mockedResponse = mock(Http.Response.class); + + @BeforeEach + void beforeEach() { + when(mockedActionContext.http(any())) + .thenReturn(mockedExecutor); + when(mockedExecutor.configuration(any())) + .thenReturn(mockedExecutor); + when(mockedExecutor.execute()) + .thenReturn(mockedResponse); + } + + @Test + void testGetCollectionItemOptions() { + when(mockedResponse.getBody(any(TypeReference.class))) + .thenReturn(Map.of("items", List.of(Map.of(ID, "123", "fieldData", Map.of("name", "abc"))))); + + assertEquals( + expectedOptions, + WebflowUtils.getCollectionItemOptions(mockedParameters, mockedParameters, Map.of(), "", + mockedActionContext)); + } + + @Test + void testGetCollectionOptions() { + when(mockedResponse.getBody(any(TypeReference.class))) + .thenReturn(Map.of("collections", List.of(Map.of(ID, "123", DISPLAY_NAME, "abc")))); + + assertEquals( + expectedOptions, + WebflowUtils.getCollectionOptions(mockedParameters, mockedParameters, Map.of(), "", mockedActionContext)); + } + + @Test + void testGetOrderOptions() { + when(mockedResponse.getBody(any(TypeReference.class))) + .thenReturn(Map.of("orders", List.of(Map.of(ORDER_ID, "123")))); + + assertEquals( + List.of(option("123", "123")), + WebflowUtils.getOrderOptions(mockedParameters, mockedParameters, Map.of(), "", mockedActionContext)); + } + + @Test + void testGetSiteOptions() { + when(mockedResponse.getBody(any(TypeReference.class))) + .thenReturn(Map.of("sites", List.of(Map.of(ID, "123", DISPLAY_NAME, "abc")))); + + assertEquals( + expectedOptions, + WebflowUtils.getSiteOptions(mockedParameters, mockedParameters, Map.of(), "", mockedActionContext)); + } +} diff --git a/server/libs/modules/components/webflow/src/test/resources/definition/webflow_v1.json b/server/libs/modules/components/webflow/src/test/resources/definition/webflow_v1.json new file mode 100644 index 00000000000..b8d680810d9 --- /dev/null +++ b/server/libs/modules/components/webflow/src/test/resources/definition/webflow_v1.json @@ -0,0 +1,668 @@ +{ + "categories" : [ { + "key" : "developer-tools", + "label" : "developer-tools" + } ], + "customAction" : true, + "customActionHelp" : null, + "description" : "Webflow is a web design and development platform that allows users to build responsive websites visually without writing code.", + "icon" : "path:assets/webflow.svg", + "tags" : null, + "metadata" : null, + "name" : "webflow", + "resources" : null, + "version" : 1, + "title" : "Webflow", + "actions" : [ { + "batch" : null, + "deprecated" : null, + "description" : "Updates an order's status to fulfilled.", + "help" : null, + "metadata" : { + "method" : "POST", + "path" : "/v2/sites/{siteId}/orders/{orderId}/fulfill" + }, + "name" : "fulfillOrder", + "outputDefinition" : { + "output" : null, + "outputResponse" : { + "outputSchema" : { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "responseType" : "JSON" + }, + "required" : null, + "name" : null, + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "body", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "orderId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "status", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + }, + "sampleOutput" : null + }, + "outputSchema" : { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "responseType" : "JSON" + }, + "required" : null, + "name" : null, + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "body", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "orderId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "status", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + }, + "sampleOutput" : null + }, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "type" : "PATH" + }, + "required" : true, + "name" : "siteId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Site", + "placeholder" : null, + "controlType" : "SELECT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : { + "optionsLookupDependsOn" : null, + "options" : { } + } + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "type" : "PATH" + }, + "required" : true, + "name" : "orderId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Order", + "placeholder" : null, + "controlType" : "SELECT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : { + "optionsLookupDependsOn" : [ "siteId" ], + "options" : { } + } + } ], + "title" : "Fulfill Order", + "perform" : null, + "workflowNodeDescription" : null, + "processErrorResponse" : null + }, { + "batch" : null, + "deprecated" : null, + "description" : "Get collection item in a collection.", + "help" : null, + "metadata" : { + "method" : "GET", + "path" : "/v2/collections/{collectionId}/item/{itemId}" + }, + "name" : "getCollectionItem", + "outputDefinition" : { + "output" : null, + "outputResponse" : { + "outputSchema" : { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "responseType" : "JSON" + }, + "required" : null, + "name" : null, + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "body", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "id", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "fieldData", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "name", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "slug", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + }, + "sampleOutput" : null + }, + "outputSchema" : { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "responseType" : "JSON" + }, + "required" : null, + "name" : null, + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "body", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "id", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "fieldData", + "type" : "OBJECT", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "additionalProperties" : null, + "multipleValues" : null, + "options" : null, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "name", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : false, + "name" : "slug", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : null, + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + } ], + "optionsDataSource" : null, + "controlType" : "OBJECT_BUILDER" + }, + "sampleOutput" : null + }, + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : true, + "name" : "siteId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Site", + "placeholder" : null, + "controlType" : "SELECT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : { + "optionsLookupDependsOn" : null, + "options" : { } + } + }, { + "advancedOption" : null, + "description" : "", + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "type" : "PATH" + }, + "required" : true, + "name" : "collectionId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Collection", + "placeholder" : null, + "controlType" : "SELECT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : { + "optionsLookupDependsOn" : [ "siteId" ], + "options" : { } + } + }, { + "advancedOption" : null, + "description" : "", + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { + "type" : "PATH" + }, + "required" : true, + "name" : "itemId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Item", + "placeholder" : null, + "controlType" : "SELECT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : { + "optionsLookupDependsOn" : [ "collectionId", "siteId" ], + "options" : { } + } + } ], + "title" : "Get Collection Item", + "perform" : null, + "workflowNodeDescription" : null, + "processErrorResponse" : null + } ], + "dataStream" : null, + "unifiedApi" : null, + "triggers" : [ ], + "connection" : { + "authorizations" : [ { + "detectOn" : null, + "description" : null, + "name" : "oauth2_authorization_code", + "properties" : [ { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : true, + "name" : "clientId", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Client Id", + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + }, { + "advancedOption" : null, + "description" : null, + "displayCondition" : null, + "expressionEnabled" : null, + "hidden" : null, + "metadata" : { }, + "required" : true, + "name" : "clientSecret", + "type" : "STRING", + "defaultValue" : null, + "exampleValue" : null, + "label" : "Client Secret", + "placeholder" : null, + "controlType" : "TEXT", + "languageId" : null, + "maxLength" : null, + "minLength" : null, + "options" : null, + "optionsDataSource" : null + } ], + "refreshOn" : null, + "title" : "OAuth2 Authorization Code", + "type" : "OAUTH2_AUTHORIZATION_CODE", + "acquire" : null, + "apply" : null, + "authorizationCallback" : null, + "authorizationUrl" : { }, + "clientId" : null, + "clientSecret" : null, + "oauth2AuthorizationExtraQueryParameters" : null, + "pkce" : null, + "refresh" : null, + "refreshUrl" : { }, + "scopes" : { }, + "refreshToken" : null, + "tokenUrl" : { } + } ], + "properties" : null, + "version" : 1, + "authorizationRequired" : null, + "baseUri" : { }, + "test" : null + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index b9c4752d44e..bbca895a400 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -325,6 +325,7 @@ include("server:libs:modules:components:twilio") include("server:libs:modules:components:typeform") include("server:libs:modules:components:var") include("server:libs:modules:components:vtiger") +include("server:libs:modules:components:webflow") include("server:libs:modules:components:webhook") include("server:libs:modules:components:whatsapp") include("server:libs:modules:components:xero")