Storybook fixes. Add stateful class MultiSelectDropdown shared component. Add Select Roles story for that component.

pull/10616/head
Hunter Trujillo 2017-03-01 13:32:54 -07:00
parent 22ba509ea7
commit 0a1f310deb
7 changed files with 167 additions and 32 deletions

View File

@ -1,28 +0,0 @@
const express = require('express');
const request = require('request');
const app = express();
app.use('/', (req, res) => {
console.log(`${req.method} ${req.url}`);
const headers = {};
headers['Access-Control-Allow-Origin'] = '*';
headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE, OPTIONS';
headers['Access-Control-Allow-Credentials'] = false;
headers['Access-Control-Max-Age'] = '86400'; // 24 hours
headers['Access-Control-Allow-Headers'] = 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept';
res.writeHead(200, headers);
if (req.method === 'OPTIONS') {
res.end();
}
else {
const url = 'http://localhost:8888' + req.url;
req.pipe(request(url)).pipe(res);
}
});
app.listen(3888, () => {
console.log('corsless proxy server now running')
});

View File

@ -17,9 +17,7 @@
"test:lint": "npm run lint; npm run test", "test:lint": "npm run lint; npm run test",
"test:dev": "nodemon --exec npm run test:lint", "test:dev": "nodemon --exec npm run test:lint",
"clean": "rm -rf build", "clean": "rm -rf build",
"storybook": "start-storybook -p 6006", "storybook": "node ./storybook"
"build-storybook": "build-storybook",
"proxy": "node ./corsless"
}, },
"author": "", "author": "",
"eslintConfig": { "eslintConfig": {

View File

@ -0,0 +1,123 @@
import React, {Component, PropTypes} from 'react'
import OnClickOutside from 'shared/components/OnClickOutside'
import classNames from 'classnames'
import _ from 'lodash'
class MultiSelectDropdown extends Component {
constructor(props) {
super(props)
this.state = {
isOpen: false,
localSelectedItems: this.props.selectedItems,
}
this.onSelect = ::this.onSelect
this.onApplyFunctions = ::this.onApplyFunctions
}
componentWillReceiveProps(nextProps) {
if (!_.isEqual(this.state.localSelectedItems, nextProps.selectedItems)) {
this.setState({
localSelectedItems: nextProps.selectedItems,
})
}
}
handleClickOutside() {
this.setState({isOpen: false})
}
toggleMenu(e) {
e.stopPropagation()
this.setState({isOpen: !this.state.isOpen})
}
onSelect(item, e) {
e.stopPropagation()
const {localSelectedItems} = this.state
let nextItems
if (this.isSelected(item)) {
nextItems = localSelectedItems.filter((i) => i !== item)
} else {
nextItems = localSelectedItems.concat(item)
}
this.setState({localSelectedItems: nextItems})
}
isSelected(item) {
return this.state.localSelectedItems.indexOf(item) > -1
}
onApplyFunctions(e) {
e.stopPropagation()
this.setState({isOpen: false})
this.props.onApply(this.state.localSelectedItems)
}
render() {
const {localSelectedItems, isOpen} = this.state
const {label} = this.props
const labelText = isOpen ? "0 Selected" : "Apply Function"
return (
<div className={classNames('dropdown multi-select-dropdown', {open: isOpen})}>
<div onClick={::this.toggleMenu} className="btn btn-xs btn-info dropdown-toggle" type="button">
<span className="multi-select-dropdown__label">
{
label ?
label :
localSelectedItems.length ? localSelectedItems.map((s) => s).join(', ') : labelText
}
</span>
<span className="caret"></span>
</div>
{this.renderMenu()}
</div>
)
}
renderMenu() {
const {items} = this.props
return (
<div className="dropdown-options">
<li className="multi-select-dropdown__apply" onClick={this.onApplyFunctions} style={{listStyle: 'none'}}>
<div className="btn btn-xs btn-info btn-block">Apply</div>
</li>
<ul className="dropdown-menu multi-select-dropdown__menu" aria-labelledby="dropdownMenu1">
{items.map((listItem, i) => {
return (
<li
key={i}
className={classNames('multi-select-dropdown__item', {active: this.isSelected(listItem)})}
onClick={_.wrap(listItem, this.onSelect)}
>
<a href="#">{listItem}</a>
</li>
)
})}
</ul>
</div>
)
}
}
const {
arrayOf,
func,
string,
} = PropTypes
MultiSelectDropdown.propTypes = {
onApply: func.isRequired,
items: arrayOf(string.isRequired).isRequired,
selectedItems: arrayOf(string.isRequired).isRequired,
label: string,
}
export default OnClickOutside(MultiSelectDropdown)

22
ui/stories/admin.js Normal file
View File

@ -0,0 +1,22 @@
import React from 'react'
import {storiesOf, action, linkTo} from '@kadira/storybook'
import MultiSelectDropdown from 'shared/components/MultiSelectDropdown'
storiesOf('MultiSelectDropdown', module)
.add('Select Roles', () => (
<MultiSelectDropdown
items={[
'Admin',
'User',
'Chrono Giraffe',
'Prophet',
'Susford',
]}
selectedItems={[
'User',
'Chrono Giraffe',
]}
label={'Select Roles'}
onApply={action('onApply')}
/>
))

View File

@ -3,3 +3,4 @@ import 'src/style/chronograf.scss';
// Kapacitor Stories // Kapacitor Stories
import './kapacitor' import './kapacitor'
import './admin'

View File

@ -12,7 +12,7 @@ import queryConfigs from './stubs/queryConfigs';
// Actions for Spies // Actions for Spies
import * as kapacitorActions from 'src/kapacitor/actions/view' import * as kapacitorActions from 'src/kapacitor/actions/view'
import * as queryActions from 'src/chronograf/actions/view'; import * as queryActions from 'src/data_explorer/actions/view';
// Components // Components
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'; import KapacitorRule from 'src/kapacitor/components/KapacitorRule';

19
ui/storybook.js Normal file
View File

@ -0,0 +1,19 @@
const express = require('express')
const request = require('request')
const {default: storybook} = require('@kadira/storybook/dist/server/middleware')
const app = express()
const handler = (req, res) => {
console.log(`${req.method} ${req.url}`)
const url = 'http://localhost:8888' + req.url
req.pipe(request(url)).pipe(res)
}
app.use(storybook('./.storybook'))
app.get('/chronograf/v1/*', handler)
app.post('/chronograf/v1/*', handler)
app.listen(6006, () => {
console.log('storybook proxy server now running')
})