Skip to content
This repository has been archived by the owner on Sep 29, 2021. It is now read-only.

Latest commit

 

History

History
140 lines (115 loc) · 4.6 KB

Development.md

File metadata and controls

140 lines (115 loc) · 4.6 KB

Development

To extend the capabilities of this tool, there are two key classes you must implement, in addition to modifiying the proper files so that those classes may be instantiated.

Classes

Service Class

The service class is the backend implementation that performs the API calls and other communication with the remote service. The below is a bare-bones template of a service class that belongs in ./lib/services:

const Service = require('./Service')

class NewService extends Service {
  constructor (config) {
    // That first parameter becomes this.name
    super('newServiceName', config)
  }

  exec (dataEmitter) {
    // Return a Promise while executing remote communication for the service fetch. 
    // Once done, return an object like the one below, with a type key and a data 
    // key containing the information needed on the front end. Services may also
    // "emit" data by directly calling the function dataEmitter passed in the 
    // method signature with the object format below as the first parameter. The 
    // parent class handles caching of this data. That cache can be accessed at 
    // this.cachedResponse. Also, access the configuration, passed from the 
    // frontend at this.config.
    return Promise.resolve({
      type: this.name,
      data: {}
    })
  }
}

// When a Service is instantiated, this is used to provide a default configuration
NewService.defaultConfig = {
  someConfigKey: null
}

module.exports = NewService

Also, make sure to update the index.js file in ./lib/services to include this class.

ServiceManager

The method instantiateServiceByName(name, config) in ./liv/util/ServiceManager.js takes a name slug, matching this.name from the service class, and returns an instantiated class. This must be updated to include the new class.

Widget Class

The widget class is used to display the information on the front-end. The below is a bare-bones template of a widget class that belongs in ./ui/widgets:

import React from 'react'
import Widget from './Widget'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {
  commitTempConfig,
  setTemporaryConfig,
  removeService
} from '../util/actions'
import {
  WidgetEditorFieldGroup
} from '../util/widgetElements'

class NewWidget extends Widget {
  constructor (props) {
    // The first parameter can be any string, used fo the widget's title, but the
    // second paramter must match the slug used for the name in the service class
    super('Widget Nice Title', 'newServiceName', props)
  }

  renderWidget () {
    // getWidgetData returns the information sent in "data" by the service class
    const data = this.getWidgetData()
    return data && (
      <div>
        Some widget data
      </div>
    )
  }

  renderEditor () {
    // The "tempConfig" is a copy of the configuration made every time the widget
    // enters editing-mode. When the user hits "Save" on the editor, that temp
    // configuration is committed to the primary config and the service class is
    // restarted with that new config data. The easiest way to modify it is by 
    // calling the method, this.setTempConfigValue('key', value) as seen below.
    const tempConfig = this.getWidgetTempConfig()
    if (tempConfig) {
      return (
        <div>
          <WidgetEditorFieldGroup name='Config field name'>
            <input 
              className='widget-editor-input' 
              type='text' 
              value={tempConfig.someConfigKey} 
              onChange={(event) => this.setTempConfigValue('someConfigKey', event.target.value)} />
          </WidgetEditorFieldGroup>
        </div>
      )
    } else {
      return null
    }
  }
}

const stateToProps = (state) => {
  return {
    services: state.services
  }
}

const dispatchToProps = (dispatch) => {
  return bindActionCreators({
    commitTempConfig,
    setTemporaryConfig,
    removeService
  }, dispatch)
}

// These are used by the layout engine. "h" is the default h in row-units for 
// the widget and "isResizable" dictates whether or not the user may resize
// the widget.
NewWidget.widgetProps = {
  h: 3,
  isResizable: true
}

export default connect(stateToProps, dispatchToProps)(NewWidget)

Dashboard.js

The main React class of this application, Dashboard.js, contains two methods that must be updated to accommodate the new widget class:

  • renderWidget(service) takes a service object and uses service.name to determine which React/widget element to return.
  • getServiceProps(service) takes a service object and uses service.name to determine which React/widget widgetProps property to return.