Introduction

Screen Shot 2015-09-08 at 4.44.46 PM.png

Wrapping up the series, we are taking our Simple Stream Integration (SSI) to the next level and really pushing the bounds of what we can do with a simple activity in Jive before finding ourselves needing middleware. We are building on to our App that we created in Episode 2 and adding two-way communication between Jive and StatusPage.io. In many ways, we are walking away from the limitations of the dataset that first created the activity in Jive from the subscribed StatusPage webhook payload. Within the external object's view, we have an app that we can send POST and GET requests to StatusPage to retrieve incidents related to the component ID from when the activity was generated and also add new incidents—without needing to leave Jive. To make sure the requests and tokens are kept secure and only select Jive Groups can see this additional feature, we'll be utilizing the Jive Connects service.

 

 

The Goal

Imagine one of your clusters goes down and you get a activity in Jive from StatusPage.io that you and your team can collaborate on the activity, view the incidents generated by your team or automated services, and add/delete/update incidents as they come in—all from within Jive and without needing to spend time switching services, websites or tools. Ultimately, this saves time, money and confusion while keeping your information and credentials secure while proving a rich and easy to use UI. That's a lot to ask, but that's exactly what we'll be building here and you can do the same with your own custom simple stream integration/app within just a few hours without middleware.

 

Tools Used

 

Files Modified

  • /apps/[your app name]/public/app.xml
  • /apps/[your app name]/public/ext-object.html
  • /apps/[your app name]/public/javascripts/main.js
  • /apps/[your app name]/public/stylesheets/main.css
  • /extension_src/public/configuration.html
  • /extension_src/public/style.css
  • /extension_src/public/logo.png (added logo for activity stream configuration page)

 

Get the Files on GitHub

The source code for this project is available on GitHub.

 

You can use the Jive SDK to create your own simple stream integration that picks up after

Dev Tool: Build an App w/ the Simple Stream Integration Builder (2 of 3)

 

  • Install the Jive Node SDK
  • Then use the following command:
    • jive-sdk create simple-stream --name="my-stream"
      • You can replace my-stream with a value of your choosing.

 

Now you should be ready to follow this walk-through. =)

 


 

Creating An SSI App with 2-Way Communication For StatusPage Using Jive Connects

 

Setting Up Jive Connects

Jive Connects is a broker for proxying requests to a remote service. Since it is set up on the server side, it can add authentication headers from anonymous, basic, to OAuth 2.0 without exposing this information to anyone but the intended service. More importantly, it is needed because of browser access restrictions for network access outside of the application from which it was loaded. By using Jive Connects, we can use its HTTP verb methods (GET, POST, HEAD, PUT, DELETE) to pull and push data from other sources into our App. Permissions to the installation of the add-on containing the Jive Connects service can also be set up; however, once added to the group and authorized, all users who are members of the group in which the add-on is installed can view/use the add-on and that Jive Connects service.

 

Walk-Through Video

 

Admin-side Setup for Jive Connects

Screen Shot 2015-09-08 at 6.44.23 AM.png

  1. To get the admin set up, we start from our Admin Console (requires admin privileges) by clicking our profile picture in the top navigation banner, "Manage" > "Admin Console"
  2. We need to add the service that will use the Jive Connects API in the Jive Admin Console. Click the "Add-ons" menu > "App Services" side menu > "Add New Service"
  3. Enter a Name of the service. We included the URL of our StatusPage instance to avoid confusion for which one this service belongs to.
    • Note: This name will be visible to end-users when they first use the app, so being descriptive is recommended.  StatusPage.io - [URL] - Incidents
  4. Authentication style can vary based on the external service's API requirements. Jive Connects supports Anonymous, API Key, Basic, OAuth 2.0.
    • Note:  Due to the way StatusPage's APIs are designed we are choosing Anonymous so everyone can share the API key
  5. Description is whatever you feel is appropriate for the service for anyone who will need to reference this service internally to understand what it connects.
  6. "Tags" is the identifier that your App can use to identify this specific Jive Connects service. Tag's take the form of URIs and must be unique and begin with "jive:service://".
    • Note: For our purposes, we are using "jive:service://statuspage.io/incidents.api?version=1" where version matches the StatusPage API version
  7. The "Service URL" will be the base URL for all requests to their API. Jive Connects let's us append to this URL but not prepend or modify from within our App.
    • Note:  Since the StatusPage API contains a unique ID for each Page instance as the base for all of their API calls, we included that in our service URL
      https://api.statuspage.io/v1/pages/[Your StatusPage.io Page ID]
  8. While Jive Connects is capable of storing multiple keys per user, we felt that this use-case was best served as multiple user's sharing a single API key.  To do this, we are hard-coding the Authorization token into the Jive Connects service, such that it is never transmitted to the browser.  Per StatusPage documentation, we could do this by always passing the key as a request parameter or header.  We chose header to keep it hidden.  To keep it safe.
    • Note:  Click the "Add a new HTTP Header" and enter the header parameter per the StatusPage documentation:  Authorization:  OAuth [APIKEY]
    • Note: To get our API key from StatusPage and you can find instructions on how to get that from here.

Since this app is being installed as an add-on, the fields below such as Groups/Users with Access to this Service are no longer relevant.

When opening the app for the first time, a authorized user will be presented with a verification screen in order to enable the Jive Connects service to this App. This only needs to be done once by one user to enable it for the entire group.

 

Enable App to Access Jive Connects

Now that we have the Jive Connects service created and configured, we can use the tag created earlier and tie it to an alias to be used by our app. The alias can be any name you want it to be and your app will reference that name in order to access the Jive Connects Service. The title will be displayed at the first initialization of the service when it is first called on the Jive Connects authorization screen (this will pop up in the app load). The content between the tags is your Jive Connects service tag that you will paste in between. We need to open the /apps/[your app name]/public/app.xml file and the following anywhere before the closing </ModulePrefs>:

<!-- Begin Jive Connects feature -->
<Require feature="jive-connects-v1">
  <Param name="alias:StatusPageIncidents|title:Read StatusPage Incidents Service">jive:service://statuspage.io/incidents_api?version=1</Param>
</Require>
<!-- End Jive Connects feature -->

 


 

Customizing the App Look and Feel with HTML and CSS

Screen Shot 2015-09-08 at 5.00.58 PM.png

For purposes of this blog and personal preferences, we aren't going to go into details of how you should make your App look. But instead, I'll tell you what I did, why I chose it and you can download the source files from GitHub to see the code.

 

The Configuration Window

We are going to backtrack for a second and edit the configuration screen for our integration that we get our endpoint URL to look a little less generic and bit more StatusPage while spending very little time on it. We need to edit the /extension_src/public/configuration.html and styles.css file to get the look we want. I also went ahead and added the StatusPage.io logo to make it clearer on which integration is being installed and/or configured.

 

Customizing the App View

To start, we edit the /apps/[Your App Name]/public/ext-object.html and stylesheets/main.css files. For this example, I wanted to give the look and feel of StatusPage.io in our integration so that the end user would feel just as comfortable and transition into operating on the StatusPage incident within Jive as they would within StatusPage; the whole process should feel seamless.

 


 

Using the StatusPage.io API within the Jive External Object App

In this example, we will be taking the StatusPage.io v1 Components and Incident's API and adding it to our App to be able to get the current status of the component related to our activity, read incidents related to the component that was posted after the date the activity was created within Jive. In addition to reading it, we will add the ability to push a realtime incident update and delete an existing incident from within the App view—without ever leaving Jive. The App can be expanded even further to add the ability to update an incident with minor tweaks. As stated previously, all communication between the App and StatusPage.io is proxied through the Jive Connects service.

 

Here is a break down of the construction of a Jive Connects POST request in /apps/[your app name]/public/javascripts/main.js:

function() {
     osapi.jive.connects.post({ // This is the POST method for Jive Connects, can be swapped to GET, DELETE, PUT, or HEAD and follows same formatting 
          alias : '[The Alias You Assigned in Your app.xml File]', // Since one App can have more than one service, each request needs an alias
          href : '/[Rest of the Endpoint of the API Appended to the Service URL]' // Varies based on which part of the external service API you are calling
     }).execute(function(response) {
          if (response.error) {
               // Handle response.error content here
          }
          else {
               // Do something with response.content if there's a payload
               // or response.headers
               // or response.status
     }
}

 

Viewing the Current Component Status

We will be calling the StatusPage.io Component API using Jive Connects GET method to make the HTTP request. On a success, the payload we get back from StatusPage's Components endpoint can be viewed in response.content and we go through that array of objects to find the matching component ID to our activity, once that's done, we call the renderStatus() method with the name and current status to be displayed. We are handling any errors by displaying the response.error in the appropriate div.

loadStatus : function() {
  var appObj = this;
  osapi.jive.connects.get({
        alias : 'StatusPageIncidents',
        href : '/components.json'
    }).execute(function(response) {
  if (response.error) {
  $('#component_status').html("Received the following error: " + JSON.stringify(response.error, null, '\t'));
  gadgets.window.adjustHeight();
  }
  else {
  response.content.map(function(obj){
  if (obj.id == app.context.body.component_update.component_id){
  app.renderStatus(obj.name, obj.status);
  }
  })
  }
  })
  },

 

The process of loading and viewing the StatusPage.io Incidents API is similar to the way we received the components JSON—by using the Jive Connects get() method and pointing the request to the /incidents.json path. We are using the JavaScript map() method to go through the response.content's array of objects in order find when each incident is referring to the activity's component and then eliminating any incidents that were created BEFORE the activity was generated. Lastly, we filter out any empty objects from the array before we call our own renderIncidents() method to create the DIV's to display each of the incidents.

  var appObj = this;
  osapi.jive.connects.get({
        alias : 'StatusPageIncidents',
        href : '/incidents.json'
    }).execute(function(response) {
  if (response.error) {
  $('#incidents').html("Received the following error: " + JSON.stringify(response.error, null, '\t'));
  gadgets.window.adjustHeight();
  }
  else {
       //
  //Please see our Git repo for the full source code
     //
  app.renderIncidents(reData);
  }
    })

 

Deleting a StatusPage.io Incident through Jive Connects

We are just doing a rinse and repeat of the Jive Connects calls and switching the verb that we use to perform our task. To delete a incident, we just need to use the delete() method in Jive Connects and pass the incident ID in the request URL. After it completes, we reload the incidents by calling our custom loadIncidents() method.

  var appObj = this;
  osapi.jive.connects.delete({
  alias : 'StatusPageIncidents',
  href : '/incidents/'+incident_id+'.json'
  }).execute(function(response){
  if (response.error){
  $('#incidents').html("Received the following error: " + JSON.stringify(response.error, null, '\t'));
  gadgets.window.adjustHeight();
  }
  else {
  app.loadIncidents();
  }
  })

 

Adding a StatusPage.io Incident through Jive Connects

NewIncident.png

In order to create a new incident, we set up a form in the /apps/[your app name]/public/ext-object.html file that contains the necessary fields (incident name, incidents status, message). We are not using the twitter option in our example and the component we will be appending this incident to is going to be the same component as the activity's. Upon submitting the form, we call our addIncidents() method, which uses the Jive Connects' POST verb to add the incident to StatusPage.io. We create a string with all of the parameters that we need to send over to StatusPage.io—and include the component ID—all to the formatting required by StatusPage's API. In this POST request, we are going to include a header value { 'Content-Type' : "application/x-www-form-urlencoded" } and a body that contains the string we put together from the form and place it in encodeURI() so that StatusPage's service can read it according to their requirements. After a successful request, we call our loadIncidents() to view the newly added incident.

 

 

  // See the GIT repo for source code

  osapi.jive.connects.post({
  alias : 'StatusPageIncidents',
  href : '/incidents.json',
  headers : {'Content-Type' : "application/x-www-form-urlencoded"},
  body : encodeURI(message)
    }).execute(function(response) {
  if (response.error) {
  $('#incidents').html("Received the following error: " + JSON.stringify(response.error, null, '\t'));
  gadgets.window.adjustHeight();
  }
  else {
  app.loadIncidents();
  app.incidentForm();
  }
    })

 


 

Hot Tips

  • You may get an error when installing the add-on about an extra .DS_Store file if you've been browsing around your directory with Finder on Mac. If you go to the root of your integration folder in terminal, type in the code below to remove all the .DS_Store files from the project; build your project again with Jive-SDK
    find . -name ".DS_Store" -type f -delete
    
  • You can have multiple Jive Connects services' running in one app. This is useful in cases where you may have two different external services that you are sending requests to/from
  • If you do not want to enter a object.url in your original xform.js file, or if you do not want to see the "Go to item" link in your activity tile, you can remove it with the "hideGoToItem" property in your activity.object. Read more about this and look at examples here ›

 


 

What's Next?