diff --git a/assets/img/channels/community/blockbax.png b/assets/img/channels/community/blockbax.png new file mode 100644 index 000000000..2055ed018 Binary files /dev/null and b/assets/img/channels/community/blockbax.png differ diff --git a/assets/img/channels/community/flows/blockbax-dark.png b/assets/img/channels/community/flows/blockbax-dark.png new file mode 100644 index 000000000..b26ddee58 Binary files /dev/null and b/assets/img/channels/community/flows/blockbax-dark.png differ diff --git a/assets/img/channels/community/intro_screens/blockbax.png b/assets/img/channels/community/intro_screens/blockbax.png new file mode 100644 index 000000000..4bc73ef30 Binary files /dev/null and b/assets/img/channels/community/intro_screens/blockbax.png differ diff --git a/assets/js/components/channels/ChannelConnectionDetails.jsx b/assets/js/components/channels/ChannelConnectionDetails.jsx index c7a2fd5ed..334183cfc 100644 --- a/assets/js/components/channels/ChannelConnectionDetails.jsx +++ b/assets/js/components/channels/ChannelConnectionDetails.jsx @@ -15,6 +15,7 @@ import GoogleSheetForm from "./community/google_sheets/GoogleSheetUpdateForm.jsx import MicroshareForm from "./community/microshare/MicroshareUpdateForm.jsx"; import TagoForm from "./community/tago/TagoUpdateForm.jsx"; import UbidotsForm from "./community/ubidots/UbidotsUpdateForm.jsx"; +import BlockbaxForm from "./community/blockbax/BlockbaxUpdateForm"; const { Panel } = Collapse function DetailsUpdateWrapper({ handleUpdateDetailsChange, validInput, children, mobile }) { @@ -62,6 +63,17 @@ function DetailsUpdateWrapper({ handleUpdateDetailsChange, validInput, children, export default ({ channel, handleUpdateDetailsInput, handleUpdateDetailsChange, validInput, mobile}) => { switch (channel.type) { + case "blockbax": + return ( + + + + ) case "aws": return ( diff --git a/assets/js/components/channels/ChannelNew.jsx b/assets/js/components/channels/ChannelNew.jsx index 709e39c30..cc16ec1ff 100644 --- a/assets/js/components/channels/ChannelNew.jsx +++ b/assets/js/components/channels/ChannelNew.jsx @@ -27,6 +27,7 @@ import MobileLayout from "../mobile/MobileLayout"; import ArrowLeftOutlined from "@ant-design/icons/ArrowLeftOutlined"; import { CORE_INTEGRATION_TYPES, COMMUNITY_INTEGRATION_TYPES, getAllowedIntegrations } from "../../util/integrationInfo"; import { isMobile } from "../../util/constants"; +import BlockbaxForm from "./community/blockbax/BlockbaxForm.jsx"; @connect(null, mapDispatchToProps) class ChannelNew extends Component { @@ -64,6 +65,8 @@ class ChannelNew extends Component { const { type } = this.state switch (type) { + case "blockbax": + return case "cargo": return case "my_devices": diff --git a/assets/js/components/channels/community/blockbax/BlockbaxForm.jsx b/assets/js/components/channels/community/blockbax/BlockbaxForm.jsx new file mode 100644 index 000000000..c818c33de --- /dev/null +++ b/assets/js/components/channels/community/blockbax/BlockbaxForm.jsx @@ -0,0 +1,134 @@ +import React, { Component } from "react"; +import { IntegrationTypeTileSimple } from "../../IntegrationTypeTileSimple"; +import { Link } from "react-router-dom"; +import ChannelNameForm from "../../default/ChannelNameForm.jsx"; +import analyticsLogger from "../../../../util/analyticsLogger"; +import { Card, Typography, Input, Button, Row, Col } from "antd"; +const { Text } = Typography; + +class BlockbaxForm extends Component { + state = { + showNextSteps: false, + blockbaxAccessToken: "", + blockbaxInboundConnectorEndpoint: "", + validInput: true, + channelName: "", + }; + + handleInputUpdate = (e) => { + this.setState({ [e.target.name]: e.target.value }, () => { + const { blockbaxAccessToken, blockbaxInboundConnectorEndpoint } = + this.state; + + if ( + blockbaxAccessToken.length > 0 && + blockbaxInboundConnectorEndpoint.length > 0 + ) { + this.setState({ + showNextSteps: true, + validInput: true, + }); + } else { + this.setState({ + validInput: false, + }); + } + }); + }; + + handleNameInput = (e) => { + this.setState({ channelName: e.target.value }); + }; + + onSubmit = () => { + const { + blockbaxAccessToken, + blockbaxInboundConnectorEndpoint, + channelName, + } = this.state; + + const payload = { + channel: { + name: channelName, + type: this.props.type, + blockbaxInboundConnectorEndpoint, + credentials: { + blockbaxAccessToken, + }, + }, + }; + + this.props.createChannel(payload); + + const topic = this.props.mobile + ? "ACTION_CREATE_CHANNEL_MOBILE" + : "ACTION_CREATE_CHANNEL"; + + analyticsLogger.logEvent(topic, { + name: channelName, + type: this.props.type, + }); + }; + + render() { + const { type } = this.props; + + return ( + <> + + + + { + e.preventDefault(); + this.props.reset(); + }} + > + Change + + + + + + + {`${type === "update" ? "Update" : "Enter"} your Blockbax details`} + + + + + Blockbax Access Token + + + + Blockbax Inbdound Connector Endpoint + + + + + + {this.state.showNextSteps && ( + + )} + > + ); + } +} + +export default BlockbaxForm; diff --git a/assets/js/components/channels/community/blockbax/BlockbaxUpdateForm.jsx b/assets/js/components/channels/community/blockbax/BlockbaxUpdateForm.jsx new file mode 100644 index 000000000..c4c067ca6 --- /dev/null +++ b/assets/js/components/channels/community/blockbax/BlockbaxUpdateForm.jsx @@ -0,0 +1,69 @@ +import React, { Component } from "react"; +import { Typography, Input, Row, Col } from "antd"; +const { Text } = Typography; + +class BlockbaxUpdateForm extends Component { + state = { + blockbaxAccessToken: "", + blockbaxInboundConnectorEndpoint: "", + }; + + handleInputUpdate = (e) => { + this.setState({ [e.target.name]: e.target.value }, () => { + const { blockbaxAccessToken, blockbaxInboundConnectorEndpoint } = + this.state; + + if ( + blockbaxAccessToken.length > 0 && + blockbaxInboundConnectorEndpoint.length > 0 + ) { + this.props.onValidInput( + { + blockbaxAccessToken, + blockbaxInboundConnectorEndpoint, + }, + true + ); + } else { + this.props.onValidInput( + { + blockbaxAccessToken: "", + blockbaxInboundConnectorEndpoint: "", + }, + false + ); + } + }); + }; + + render() { + return ( + <> + Enter your Blockbax Integration Details + + + + Blockbax Access Token + + + + Blockbax Inbound Connector Endpoint + + + + > + ); + } +} + +export default BlockbaxUpdateForm; diff --git a/assets/js/util/integrationInfo.js b/assets/js/util/integrationInfo.js index 0e7009237..04dd19957 100644 --- a/assets/js/util/integrationInfo.js +++ b/assets/js/util/integrationInfo.js @@ -31,8 +31,12 @@ import TagoDark from "../../img/channels/community/flows/tago-dark.png"; import Ubidots from "../../img/channels/community/ubidots.png"; import UbidotsDark from "../../img/channels/community/flows/ubidots-dark.png"; import UbidotsIntro from "../../img/channels/community/intro_screens/ubidots.png"; +import Blockbax from "../../img/channels/community/blockbax.png" +import BlockbaxDark from "../../img/channels/community/flows/blockbax-dark.png" +import BlockbaxIntro from "../../img/channels/community/intro_screens/blockbax.png" export const integrationImgMap = { + blockbax: BlockbaxDark, adafruit: AdafruitDark, aws: AwsDark, azure: AzureDark, @@ -49,7 +53,7 @@ export const integrationImgMap = { akenza: AkenzaDark, }; -export const http_integrations = ["http", "cargo", "my_devices", "akenza", "datacake", "microshare", "tago", "ubidots", "google_sheets"] +export const http_integrations = ["http", "blockbax", "cargo", "my_devices", "akenza", "datacake", "microshare", "tago", "ubidots", "google_sheets"] export const mqtt_integrations = ["mqtt", "adafruit"] export const getAllowedIntegrations = () => { @@ -96,6 +100,18 @@ export const CORE_INTEGRATION_TYPES = [ ]; export const COMMUNITY_INTEGRATION_TYPES = [ + { + name: "Blockbax", + type: "blockbax", + img: `${Blockbax}`, + info: { + title: "Blockbax Low-Code IoT Platform", + desc: "Join the future of smart operations, automate your business through sensor and machine data without coding.", + docLink: "https://blockbax.com/docs/integrations/helium/", + externalLink: "https://blockbax.com/" + }, + introImg: `${BlockbaxIntro}` + }, { name: "Helium Cargo", type: "cargo", diff --git a/lib/console/channels/channel.ex b/lib/console/channels/channel.ex index 827c0aa07..747b10d81 100644 --- a/lib/console/channels/channel.ex +++ b/lib/console/channels/channel.ex @@ -6,8 +6,9 @@ defmodule Console.Channels.Channel do alias Console.Organizations.Organization alias Console.Channels.Channel - @http_types ~w(http cargo my_devices akenza datacake microshare tago ubidots google_sheets) + @http_types ~w(blockbax http cargo my_devices akenza datacake microshare tago ubidots google_sheets) @long_type_names %{ + "blockbax" => "Blockbax", "aws" => "AWS IoT", "azure" => "Azure IoT Hub", "iot_central" => "Azure IoT Central", diff --git a/lib/console/community/community_channels.ex b/lib/console/community/community_channels.ex index 90bc6ded8..fdda68da2 100644 --- a/lib/console/community/community_channels.ex +++ b/lib/console/community/community_channels.ex @@ -1,6 +1,12 @@ defmodule Console.CommunityChannels do def append_connection_details(channel) do case channel.type do + "blockbax" -> + channel + |> Map.put(:endpoint, "#{channel.credentials["blockbaxInboundConnectorEndpoint"]}") + |> Map.put(:method, "post") + |> Map.put(:headers, Jason.encode!(%{ "Content-Type" => "application/json" })) + |> Map.put(:headers, Jason.encode!(%{ "Authorization" => "ApiKey #{channel.credentials["blockbaxAccessToken"]}" })) "cargo" -> channel |> Map.put(:endpoint, "https://cargo.helium.com/api/payloads") @@ -60,6 +66,15 @@ defmodule Console.CommunityChannels do def inject_credentials(channel, show_underlying_type \\ true) do case channel.type do + "blockbax" -> + channel + |> Map.put(:credentials, %{ + "endpoint" => "#{channel.credentials["inboundConnectorEndpoint"]}", + "headers" => %{ "Authorization" => "ApiKey #{channel.credentials["accessToken"]}" }, + "method" => "post", + "url_params" => %{} + }) + |> Map.put(:type, (if show_underlying_type, do: "http", else: channel.type)) "cargo" -> channel |> Map.put(:credentials, %{ diff --git a/lib/console_web/controllers/v1/channel_controller.ex b/lib/console_web/controllers/v1/channel_controller.ex index cf8a3fed1..f67503f5f 100644 --- a/lib/console_web/controllers/v1/channel_controller.ex +++ b/lib/console_web/controllers/v1/channel_controller.ex @@ -77,6 +77,15 @@ defmodule ConsoleWeb.V1.ChannelController do if type in allowed_types do channel_params = case type do + "blockbax" -> + %{ + "name" => name, + "type" => type, + "organization_id" => current_organization.id, + "credentials" => %{ + "blockbaxAccessToken" => token, + } + } "akenza" -> %{ "credentials" => %{