Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation to the readme civic-6468 #6

Open
wants to merge 7 commits into
base: 0.6.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 102 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,103 @@ As an example of what you might get from wiring it all up, here is a screenshot

Changing the filter values at the top will reload the data -- and, in some cases, change the layout -- of the visualizations below them.

## Anatomy of a dashboard
- Settings file: it holds all the configuration required to instantiate a dashboard.
- Data Handlers: a set of functions to adapt the raw data for each component.
- State handlers: a set of functions to manipulate the application state base on conditions.
- Custom components: components that are not included in the react-dash library and you need to create ad hoc for your project.

## Settings object
Dashboard are just javascript objects. Concretely a settings object that stores all the required information to built a dashboard. Namely: layouts, components, data sources, data handlers, etc.

You have two options to start a DKAN Dash project:

1. Use the module as it is without any custom component.
2. Add customizations like components and data handlers.

The second option is by far the most common scenario.

Just remember that all the customizations needs to happen inside the `custom_dash` module. Don't hack dkan_dash.

This setting object can be placed either in a file or in the database.

**IMPORTANT: Database stored settings always takes precedent over file stored settings**

### Database stored settings
This option is ideal when you need to perform updates in your dashboard without push any code. For example, if you need to change the dashboard title, chart colors, field names, etc.

### File stored settings
For developers it's easy to work with files. Files can be tracked by a control version system so it's easy to rollback when something wrong happens.

By convention, the settings files should be placed in `custom_dash/js/src` and with the suffix `Settings` named like `dashboardNameSettings.js`.

**In order to use an object stored in a file you will need to follow some conventions:**

- All the dashboard settings should be stored at `Drupal.settings.dkanDash.devSettings.some__uri`
- Each devSettings key is a dashboard setting object
- Dashboard settings are pick base on the path. For example, for the path `dashboard/people` you need a key `dashboard__people` in the `Drupal.settings.dkanDash.devSettings` object.
- Setting objects should not contain functions. To transform data, data handlers are the way to go. Remember you can create and use your own components.

## Quick start

### Requirements
- DKAN
- react-dash
- npm or yarn

### Steps
1. Make sure you have JSONEditor and react-dash libraries in the libraries directory.
2. Download and enable dkan_dash.
3. Go to `/node/add/react-dashboard`
4. Set a title
5. Switch the JSONEditor to code mode.
6. Copy and paste the following JSON object and save

```
{
"title": "A dashboard title",
"regions": [
{
"id": "some-region",
"children": [
{
"id": "hello",
"type": "Markup",
"content": "<h1>Hello</h1>"
}
]
}
]
}
```

## Customizations
By default react-dash was created to be customized. These may include data handlers, custom components, state handlers, etc.

### Before start
Because all the custom code is transpiled all the files must reside inside the directory `custom_dash/src/js`. Files outside that folder will be ignored.
Beside this, you also need import your files within `custom_dash/src/js/index.js`. By doing this, babel (the tranpiler) knows which files should be transpiled and which ignored.

## How to transpile your custom code
```
> yarn
> yarn run dev
```

## Extended workflow

Sometimes it's useful to develop react-dash features while you are working in a project. Without the extended workflow if you need to add a new feature to react-dash and test that in your project you will need to rebuild react-dash, copy distribution files, rebuild dkan_dash, etc.

Custom Dash build process allow you to define some environment variables indicating where `react-dash` and `dkan_dash` repositories are located and thus perform the build steps automatically.

```
> yarn
> export REACT_DASH_PATH=/path/to/react/dash
> export REACT_DASH_PATH=/path/to/dkan_dash
> yarn run dev
```


## Who DKAN Dash is for
We built DKAN Dash as a way to do complex custom data visualization dashboards in a repeatable way using DKAN's [Datastore API](http://docs.getdkan.com/en/stable/apis/datastore-api.html) as a data backend. DKAN Dash and its supporting ecosystem are really a development framework that allows for highly customizable data visualizations while minimizing boilerplate code and unnecessary repetition.

Expand Down Expand Up @@ -74,6 +171,8 @@ The react-dash library [ships with an example project](https://github.com/NuCivi
## Further reading

1. The [React Dash](https://react-dashboard.readthedocs.io) documentation is a complete resource for information on the standalone library.
2. Take a look at the files in the [custom_dash](https://github.com/NuCivic/custom_dash) repo to see how a specific implementation would be structured.
3. Look for news and updates on the [DKAN blog](http://getdkan.com/blog/)
4. Join the `#dashboards` channel on the [DKAN Community Slack](https://dkansignup.herokuapp.com/)
3. Take a look at the [Dkan documentation](http://dkan.readthedocs.io/en/latest/)
4. Take a look at the files in the [custom_dash](https://github.com/NuCivic/custom_dash) repo to see how a specific implementation would be structured.
5. Look for news and updates on the [DKAN blog](http://getdkan.com/blog/)
6. Join the `#dashboards` channel on the [DKAN Community Slack](https://dkansignup.herokuapp.com/)

15 changes: 13 additions & 2 deletions dist/dkan_dash.min.css

Large diffs are not rendered by default.

2,057 changes: 2,025 additions & 32 deletions dist/dkan_dash.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/dkan_dash.min.js.map

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions dkan_dash.module
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ function dkan_dash_theme($existing, $type, $theme, $path){
'path' => $path,
);
$theme['react_dashboard-embed'] = array(
'variables' => array(
'content' => t('HTML for dashboard embeds'),
),
'variables' => array(),
'template' => 'react_dashboard-embed',
'path' => $path,
);
Expand Down Expand Up @@ -56,15 +54,24 @@ function dkan_dash_menu() {
'access arguments' => array('access content'),
'type' => MENU_CALLBACK
);
$items['dashboard/%node/iframe'] = array(
'title' => 'Dashboard',
$items['dashboard/%dashboard/iframe'] = array(
'page callback' => 'dkan_dash_iframe',
'page arguments' => array(1),
'access arguments' => array('access content'),
);
return $items;
}

function dashboard_load($name) {
$alias = 'dashboard/' . $name;
$path = drupal_lookup_path('source', $alias);
$node = menu_get_object('node', 1, $path);
if(!empty($node)) {
return $node;
}
return FALSE;
}

/**
* Create and endpoint ready to be consumed by the react autocomplete
* component included inside the react dashboard library.
Expand Down Expand Up @@ -141,7 +148,7 @@ function dkan_dash_libraries_info() {
* Implements hook_preprocess_page().
*/
function dkan_dash_preprocess_page(&$vars) {
if (in_array_match('/page__dashboard__iframe/', $vars['theme_hook_suggestions'])) {
if (in_array_match('/page__dashboard__.+__iframe/', $vars['theme_hook_suggestions'])) {
header_remove('X-Frame-Options');
$vars['theme_hook_suggestions'][] = 'react_dashboard-embed';
}
Expand Down
8 changes: 5 additions & 3 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "index.js",
"scripts": {
"build": "export MODE=production;node ./node_modules/webpack/bin/webpack.js",
"build-dev": "export MODE=external;node ./node_modules/webpack/bin/webpack.js",
"dev": "export MODE=development;node ./node_modules/webpack/bin/webpack.js --watch"
},
"repository": {
Expand All @@ -14,7 +15,7 @@
"dependencies": {
"create-react-class": "^15.5.2",
"react": "*",
"react-dash": "https://github.com/NuCivic/react-dash#fix-multiple-construct-calls",
"react-dash": "git+https://github.com/NuCivic/react-dash#v0.6.14.2",
"react-dom": "*",
"whatwg-fetch": "^2.0.2"
},
Expand All @@ -28,13 +29,14 @@
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-runtime": "^6.6.1",
"chokidar": "^1.7.0",
"colors": "^1.1.2",
"css-loader": "^0.23.1",
"eslint-plugin-react": "^3.6.2",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"fs-extra": "^3.0.1",
"node-sass": "^3.4.2",
"phantomjs": "^2.1.3",
"phantomjs-polyfill": "0.0.2",
"sass-loader": "^3.2.0",
"style-loader": "^0.13.0",
"webpack": "^1.12.14"
Expand Down
2 changes: 1 addition & 1 deletion js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import DKANDash from './dkan_dash';
import { DataHandler } from 'react-dash';

let settings;
let settingsPath = window.location.pathname.substr(1).replace('/', '__');
let settingsPath = window.location.pathname.substr(1).replace('/iframe', '').replace('/', '__');

if (Drupal.settings.dkanDash.devSettings[settingsPath]) {
settings = Drupal.settings.dkanDash.devSettings[settingsPath];
Expand Down
51 changes: 44 additions & 7 deletions js/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/* eslint-disable no-var */
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var MODE = process.env.MODE;
var plugins = [new ExtractTextPlugin('dkan_dash.min.css')];
var devtool = (MODE === 'production') ? 'source-map' : 'eval';
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const fs = require('fs-extra');
const chokidar = require('chokidar');
const colors = require('colors');
const { exec } = require('child_process');
const MODE = process.env.MODE;
const isProduction = MODE === 'production';
const devtool = isProduction ? 'source-map' : 'eval';
let plugins = [new ExtractTextPlugin('dkan_dash.min.css')];

if(MODE === 'production') {
plugins = plugins.concat([
Expand All @@ -24,6 +29,38 @@ if(MODE === 'production') {
]);
}

/*========================================
= REACT DASH BUILD =
========================================*/
if(process.env.REACT_DASH_PATH) {
const originRD = path.resolve(process.env.REACT_DASH_PATH);
const destinationRD = path.join(__dirname, 'node_modules', 'react-dash');
const originRDSrc = path.join(originRD, 'src');
const originRDDistFiles = path.join(originRD, 'dist');
const destinationRDDistFiles = path.join(destinationRD, 'dist');

const build = () => {
console.log('---- BUILDING REACT DASH -----'.cyan);
exec('npm run build', {cwd: process.env.REACT_DASH_PATH }, (error, stdout, stderr) => {
if(error || stderr) throw new Error(error || stderr);
console.log(stdout);
fs.copySync(originRDDistFiles, destinationRDDistFiles);
console.log('------ REACT DASH BUILT ------'.green);
});
};

const watcher = chokidar.watch(originRDSrc, {
persistent: MODE === 'external' ? false : true,
ignoreInitial: true
});

watcher
.on('change', build)
.on('add', build)
.on('unlink', build);
}
/*===== End of REACT DASH BUILD ======*/

module.exports = {
devtool: devtool,
entry: ['whatwg-fetch','./src/index'],
Expand All @@ -36,7 +73,7 @@ module.exports = {
loaders: [
{
test: /\.js?$/,
loaders: ['babel'],
loaders: ['babel-loader'],
include: path.join(__dirname, 'src')
},
{ test: /\.css$/, loader: ExtractTextPlugin.extract('css-loader') },
Expand Down
Loading