From 95650a923683559b629628e1a7061bfc2d73fe22 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 5 Jan 2018 14:51:07 -0500 Subject: [PATCH] documentation to close #6 --- Development.md | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ Readme.md | 6 ++- 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 Development.md diff --git a/Development.md b/Development.md new file mode 100644 index 0000000..5f18c70 --- /dev/null +++ b/Development.md @@ -0,0 +1,140 @@ +# 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`: + +```Javascript +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`: + +```Javascript +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 && ( +
+ Some widget data +
+ ) + } + + 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 ( +
+ + this.setTempConfigValue('someConfigKey', event.target.value)} /> + +
+ ) + } 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. diff --git a/Readme.md b/Readme.md index e423db0..a168a19 100644 --- a/Readme.md +++ b/Readme.md @@ -26,4 +26,8 @@ Each widget on the app's screen draws its data via various APIs, and InBrief is ## Installation -To install InBrief on your computer, head to the [Releases](https://github.com/johnjones4/InBrief/releases) section and download the appropriate file for your system. (Currently, there are only builds for Linux and Mac) Once running, there's a "plus" icon in the bottom right-hand corner of the window. Click that to add widgets. When a widget is added, click the edit button in its upper right-hand corner to configure it for your needs. \ No newline at end of file +To install InBrief on your computer, head to the [Releases](https://github.com/johnjones4/InBrief/releases) section and download the appropriate file for your system. (Currently, there are only builds for Linux and Mac) Once running, there's a "plus" icon in the bottom right-hand corner of the window. Click that to add widgets. When a widget is added, click the edit button in its upper right-hand corner to configure it for your needs. + +## Extending + +To extend the capabilities of this application and add additional dashboard panels, see the [Development](Development.md) documentation