diff --git a/frontend/index.html b/frontend/index.html index 7c0bb5e22d..4ab51d9e47 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,12 +2,15 @@ Unleash Admin + +
+ diff --git a/frontend/package.json b/frontend/package.json index 68605919be..6219d96abe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,12 +34,13 @@ "immutability-helper": "^2.0.0", "immutable": "^3.8.1", "normalize.css": "^5.0.0", + "percent": "^2.0.0", "react": "^15.3.1", "react-addons-css-transition-group": "^15.3.1", "react-dom": "^15.3.1", + "react-mdl": "^1.9.0", "react-redux": "^4.4.5", "react-router": "^3.0.0", - "react-toolbox": "^1.2.1", "redux": "^3.6.0", "redux-thunk": "^2.1.0", "whatwg-fetch": "^2.0.0" diff --git a/frontend/src/component/app.jsx b/frontend/src/component/app.jsx index 2f044b5fd0..5b8fecbda9 100644 --- a/frontend/src/component/app.jsx +++ b/frontend/src/component/app.jsx @@ -1,14 +1,18 @@ import React, { Component } from 'react'; -import { Layout, Panel, NavDrawer, AppBar } from 'react-toolbox'; +import { Layout, Drawer, Header, Navigation, Content, + Footer, FooterSection, FooterDropDownSection, FooterLinkList, + Grid, Cell +} from 'react-mdl'; import style from './styles.scss'; import ErrorContainer from './error/error-container'; import UserContainer from './user/user-container'; import ShowUserContainer from './user/show-user-container'; -import Navigation from './nav'; + export default class App extends Component { + constructor (props) { super(props); this.state = { drawerActive: false }; @@ -17,14 +21,102 @@ export default class App extends Component { this.setState({ drawerActive: !this.state.drawerActive }); }; } + static contextTypes = { + router: React.PropTypes.object, + } onOverlayClick = () => this.setState({ drawerActive: false }); render () { + const createListItem = (path, caption) => + + {caption} + ; + + return ( +
+ + +
Unleash Admin / The Title}> + + Github + + +
+ + + {createListItem('/features', 'Feature toggles')} + {createListItem('/strategies', 'Strategies')} + {createListItem('/history', 'Event history')} + {createListItem('/archive', 'Archived toggles')} +
+ {createListItem('/metrics', 'Client metrics')} + {createListItem('/client-strategies', 'Client strategies')} + {createListItem('/client-instances', 'Client instances')} +
+
+ + + + {this.props.children} + + + + + +
+
+ ); + + + return (
- +
@@ -33,11 +125,11 @@ export default class App extends Component {
- + {this.props.children}
- +
diff --git a/frontend/src/component/archive/archive-list-component.jsx b/frontend/src/component/archive/archive-list-component.jsx index 52bd0ce863..07bc66d221 100644 --- a/frontend/src/component/archive/archive-list-component.jsx +++ b/frontend/src/component/archive/archive-list-component.jsx @@ -1,30 +1,5 @@ import React, { Component } from 'react'; -import { List, ListItem, ListSubHeader } from 'react-toolbox/lib/list'; -import FontIcon from 'react-toolbox/lib/font_icon'; -import Chip from 'react-toolbox/lib/chip'; -import Switch from 'react-toolbox/lib/switch'; - -const ArchivedFeature = ({ feature, revive }) => { - const { name, description, enabled, strategies } = feature; - const actions = [ -
{strategies && strategies.map(s => {s.name})}
, - revive(feature)} />, - ]; - - const leftActions = [ - , - ]; - - return ( - - ); -}; +import { DataTable, TableHeader, Chip, Switch, IconButton } from 'react-mdl'; class ArchiveList extends Component { componentDidMount () { @@ -34,12 +9,20 @@ class ArchiveList extends Component { render () { const { archive, revive } = this.props; return ( - - - {archive.length > 0 ? - archive.map((feature, i) => ) : - } - +
+
Toggle Archive
+ + + ( + revive(name)} /> + )}>Revive + (v ? 'Yes' : '-')}>Enabled + Toggle name + Created + +
); } } diff --git a/frontend/src/component/client-instance/client-instance-component.js b/frontend/src/component/client-instance/client-instance-component.js index 6d22b39433..83c6772691 100644 --- a/frontend/src/component/client-instance/client-instance-component.js +++ b/frontend/src/component/client-instance/client-instance-component.js @@ -1,13 +1,5 @@ import React, { Component, PropTypes } from 'react'; -import Table from 'react-toolbox/lib/table'; - -const Model = { - appName: { type: String, title: 'Application Name' }, - instanceId: { type: String }, - clientIp: { type: String }, - createdAt: { type: String }, - lastSeen: { type: String }, -}; +import { DataTable, TableHeader } from 'react-mdl'; class ClientStrategies extends Component { static propTypes () { @@ -25,11 +17,20 @@ class ClientStrategies extends Component { const source = this.props.clientInstances; return ( - + > + + + Instance ID + Application name + IP + Created + Last Seen + + ); } } diff --git a/frontend/src/component/client-strategy/strategy-component.js b/frontend/src/component/client-strategy/strategy-component.js index 3814f84dcb..fc65e23f55 100644 --- a/frontend/src/component/client-strategy/strategy-component.js +++ b/frontend/src/component/client-strategy/strategy-component.js @@ -1,10 +1,5 @@ import React, { Component } from 'react'; -import Table from 'react-toolbox/lib/table'; - -const Model = { - appName: { type: String, title: 'Application Name' }, - strategies: { type: String }, -}; +import { DataTable, TableHeader } from 'react-mdl'; class ClientStrategies extends Component { @@ -13,19 +8,25 @@ class ClientStrategies extends Component { } render () { - const source = this.props.clientStrategies.map(item => ( + const source = this.props.clientStrategies + // temp hack for ignoring dumb data + .filter(item => item.strategies) + .map(item => ( { appName: item.appName, - strategies: item.strategies.join(', '), + strategies: item.strategies && item.strategies.join(', '), }) ); return ( -
+ > + Application name + Strategies + ); } } diff --git a/frontend/src/component/error/error-component.jsx b/frontend/src/component/error/error-component.jsx index 8230da2f5c..9cad4d9c25 100644 --- a/frontend/src/component/error/error-component.jsx +++ b/frontend/src/component/error/error-component.jsx @@ -1,6 +1,7 @@ -import Snackbar from 'react-toolbox/lib/snackbar'; import React, { PropTypes } from 'react'; +import { Snackbar } from 'react-mdl'; + class ErrorComponent extends React.Component { static propTypes () { return { diff --git a/frontend/src/component/feature/feature-component.jsx b/frontend/src/component/feature/feature-component.jsx index 1fe816c2c6..b76e745075 100644 --- a/frontend/src/component/feature/feature-component.jsx +++ b/frontend/src/component/feature/feature-component.jsx @@ -1,10 +1,10 @@ import React, { PropTypes } from 'react'; - import { Link } from 'react-router'; -import FontIcon from 'react-toolbox/lib/font_icon'; -import Switch from 'react-toolbox/lib/switch'; -import { ListItem } from 'react-toolbox/lib/list'; -import Chip from 'react-toolbox/lib/chip'; +import { Chip, Switch, Icon, Tooltip, IconButton, ChipContact } from 'react-mdl'; +import percentLib from 'percent'; +import Progress from './progress'; + + import style from './feature.scss'; @@ -12,42 +12,55 @@ const Feature = ({ feature, onFeatureClick, onFeatureRemove, - metricsLastHour = { yes: 0, no: 0, hasData: false }, - metricsLastMinute = { yes: 0, no: 0, hasData: false }, + settings, + metricsLastHour = { yes: 0, no: 0, isFallback: true }, + metricsLastMinute = { yes: 0, no: 0, isFallback: true }, }) => { - const { name, description, enabled, strategies, createdAt } = feature; - const created = new Date(createdAt); + const { name, description, enabled, strategies } = feature; - const actions = [ -
{strategies && strategies.map((s, i) => {s.name})}
, -
({created.toLocaleDateString('nb-NO')})
, - - - , - - - , - onFeatureRemove(name)} />, - ]; - - const leftActions = [ - - {metricsLastHour.yes} / {metricsLastHour.no} - , - - {metricsLastMinute.yes} / {metricsLastMinute.no} - , - onFeatureClick(feature)} checked={enabled} />, - ]; + const { showLastHour = false } = settings; + const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback; + const percent = 1 * (showLastHour ? + percentLib.calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0) : + percentLib.calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0) + ); return ( - +
  • + +
    + { + isStale ? + : +
    + +
    + } +
    + +   + + onFeatureClick(feature)} checked={enabled} /> + + + {name} {(description && description.substring(0, 100)) || ''} + +
    + + + {strategies && strategies.map((s, i) => + {s.name} + )} + + + + + + + onFeatureRemove(name)} className={style.iconListItem} /> + + +
  • ); }; diff --git a/frontend/src/component/feature/feature.scss b/frontend/src/component/feature/feature.scss index 636272d55f..ee67a619da 100644 --- a/frontend/src/component/feature/feature.scss +++ b/frontend/src/component/feature/feature.scss @@ -1,7 +1,3 @@ -.link { - color: #212121; -} - .action { color: #aaa !important; cursor: pointer; @@ -14,3 +10,52 @@ .no { color: red; } + +.link { + color: #212121; + text-decoration: none; +} + +.link small { + color: #aaa; + font-weight: 100; +} + +.link:hover { + color: #000; +} + +.iconList { + display: flex; +} + +.iconListItem { + flex: 1; + color: #bbb !important; +} +.iconListItem *:hover { + color: #333; +} + +.iconListItemChip { + flex: 1; + margin-left: 5px !important; +} + +.topList { + display: flex; + margin: 10px 10px 10px 10px; +} + +.topListItem0 { + flex: 1; + flex-grow: 0; +} + +.topListItem { + flex: 1; +} + +.topListItem2 { + flex: 2; +} \ No newline at end of file diff --git a/frontend/src/component/feature/form-edit-container.jsx b/frontend/src/component/feature/form-edit-container.jsx index 44a7b62fce..c5b4848314 100644 --- a/frontend/src/component/feature/form-edit-container.jsx +++ b/frontend/src/component/feature/form-edit-container.jsx @@ -3,7 +3,7 @@ import { hashHistory } from 'react-router'; import { requestUpdateFeatureToggle } from '../../store/feature-actions'; import { createMapper, createActions } from '../input-helpers'; -import FormComponent from './form'; +import EditAndView from './view-and-edit'; const ID = 'edit-feature-toggle'; function getId (props) { @@ -59,4 +59,4 @@ const actions = createActions({ prepare, }); -export default connect(mapStateToProps, actions)(FormComponent); +export default connect(mapStateToProps, actions)(EditAndView); diff --git a/frontend/src/component/feature/form/index.jsx b/frontend/src/component/feature/form/index.jsx index c6de46468b..cbe25cc7c2 100644 --- a/frontend/src/component/feature/form/index.jsx +++ b/frontend/src/component/feature/form/index.jsx @@ -1,7 +1,5 @@ import React, { Component, PropTypes } from 'react'; -import Input from 'react-toolbox/lib/input'; -import Button from 'react-toolbox/lib/button'; -import Switch from 'react-toolbox/lib/switch'; +import { Textfield, Button, Switch } from 'react-mdl'; import StrategiesSection from './strategies-section-container'; const trim = (value) => { @@ -45,29 +43,31 @@ class AddFeatureToggleComponent extends Component { return (
    - validateName(v)} - onChange={(v) => setValue('name', trim(v))} /> - validateName(v.target.value)} + onChange={(v) => setValue('name', trim(v.target.value))} /> +
    + setValue('description', v)} /> + onChange={(v) => setValue('description', v.target.value)} />
    setValue('enabled', v)} /> + onChange={(v) => { + // todo is wrong way to get value? + setValue('enabled', (console.log(v.target) && v.target.value === 'on')); + }}>Enabled
    @@ -78,12 +78,9 @@ class AddFeatureToggleComponent extends Component { removeStrategy={removeStrategy} />
    - -
    - -   - ); } diff --git a/frontend/src/component/feature/form/strategies-add.jsx b/frontend/src/component/feature/form/strategies-add.jsx index c255b40b0b..7b771abf26 100644 --- a/frontend/src/component/feature/form/strategies-add.jsx +++ b/frontend/src/component/feature/form/strategies-add.jsx @@ -1,6 +1,7 @@ import React, { PropTypes } from 'react'; -import Dropdown from 'react-toolbox/lib/dropdown'; -import FontIcon from 'react-toolbox/lib/font_icon'; +// import Dropdown from 'react-toolbox/lib/dropdown'; +// TODO use menu +import { Icon } from 'react-mdl'; class AddStrategy extends React.Component { @@ -41,7 +42,7 @@ class AddStrategy extends React.Component { return (
    - +
    {item.name} {item.description} @@ -56,9 +57,9 @@ class AddStrategy extends React.Component { return s; }); - return ( -
    - + +*/ + + return ( +
    +
    ); } diff --git a/frontend/src/component/feature/form/strategy-configure.jsx b/frontend/src/component/feature/form/strategy-configure.jsx index db9c670506..ffad0f65d8 100644 --- a/frontend/src/component/feature/form/strategy-configure.jsx +++ b/frontend/src/component/feature/form/strategy-configure.jsx @@ -1,6 +1,5 @@ import React, { PropTypes } from 'react'; -import Input from 'react-toolbox/lib/input'; -import Button from 'react-toolbox/lib/button'; +import { Textfield, Button } from 'react-mdl'; class StrategyConfigure extends React.Component { @@ -30,7 +29,7 @@ class StrategyConfigure extends React.Component { renderInputFields (strategyDefinition) { if (strategyDefinition.parametersTemplate) { return Object.keys(strategyDefinition.parametersTemplate).map(field => ( - - +
    +
    + + this.toggleMetrics()} className={styles.topListItem0}> + { settings.showLastHour && + + + } + { '1 hour' } + +   + this.toggleMetrics()} className={styles.topListItem0}> + { !settings.showLastHour && + + + } + { '1 minute' } + + + +
    + { this.setFilter(e.target.value); }} + label="Filter toggles" + style={{ width: '100%' }} + /> +
    + +
    + + this.setSort(e.target.getAttribute('data-target'))}> + Filter by: + Default + Name + Enabled + Application name + Created + Strategies + Metrics + +
    + + + + + + +
    + +
      {features.map((feature, i) => )} - +
    +
    - + + Create new feature toggle - +
    ); } } diff --git a/frontend/src/component/feature/list-container.jsx b/frontend/src/component/feature/list-container.jsx index e15f2d5bba..cbd0165ef7 100644 --- a/frontend/src/component/feature/list-container.jsx +++ b/frontend/src/component/feature/list-container.jsx @@ -1,19 +1,79 @@ import { connect } from 'react-redux'; import { toggleFeature, fetchFeatureToggles, removeFeatureToggle } from '../../store/feature-actions'; import { fetchFeatureMetrics } from '../../store/feature-metrics-actions'; +import { updateSettingForGroup } from '../../store/settings/actions'; + import FeatureListComponent from './list-component'; -const mapStateToProps = (state) => ({ - features: state.features.toJS(), - featureMetrics: state.featureMetrics.toJS(), -}); +const mapStateToProps = (state) => { + const featureMetrics = state.featureMetrics.toJS(); + const settings = state.settings.toJS().feature || {}; + let features = state.features.toJS(); + if (settings.filter) { + features = features.filter(feature => + ( + feature.name.indexOf(settings.filter) > -1 || + feature.description.indexOf(settings.filter) > -1 || + feature.strategies.some(s => s && s.name && s.name.indexOf(settings.filter) > -1) + ) + ); + } + + if (settings.sort) { + if (settings.sort === 'enabled') { + features = features.sort((a, b) => ( + // eslint-disable-next-line + a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1 + )); + } else if (settings.sort === 'appName') { + // AppName + // features = features.sort((a, b) => { + // if (a.appName < b.appName) { return -1; } + // if (a.appName > b.appName) { return 1; } + // return 0; + // }); + } else if (settings.sort === 'created') { + features = features.sort((a, b) => ( + new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1 + )); + } else if (settings.sort === 'name') { + features = features.sort((a, b) => { + if (a.name < b.name) { return -1; } + if (a.name > b.name) { return 1; } + return 0; + }); + } else if (settings.sort === 'strategies') { + features = features.sort((a, b) => ( + a.strategies.length > b.strategies.length ? -1 : 1 + )); + } else if (settings.sort === 'metrics') { + const target = settings.showLastHour ? featureMetrics.lastHour : featureMetrics.lastMinute; + + features = features.sort((a, b) => { + if (!target[a.name]) { return 1; } + if (!target[b.name]) { return -1; } + if (target[a.name].yes > target[b.name].yes) { + return -1; + } + return 1; + }); + } + } + + return { + features, + featureMetrics, + settings, + }; +}; const mapDispatchToProps = { onFeatureClick: toggleFeature, onFeatureRemove: removeFeatureToggle, fetchFeatureToggles, fetchFeatureMetrics, + updateSetting: updateSettingForGroup('feature'), }; const FeatureListContainer = connect( diff --git a/frontend/src/component/feature/progress.jsx b/frontend/src/component/feature/progress.jsx new file mode 100644 index 0000000000..d374b1c90f --- /dev/null +++ b/frontend/src/component/feature/progress.jsx @@ -0,0 +1,86 @@ +import React, { PropTypes, Component } from 'react'; +import styles from './progress.scss'; + +class Progress extends Component { + constructor (props) { + super(props); + + this.state = { + percentage: props.initialAnimation ? 0 : props.percentage, + }; + } + + componentDidMount () { + if (this.props.initialAnimation) { + this.initialTimeout = setTimeout(() => { + this.requestAnimationFrame = window.requestAnimationFrame(() => { + this.setState({ + percentage: this.props.percentage, + }); + }); + }, 0); + } + } + + componentWillReceiveProps ({ percentage }) { + this.setState({ percentage }); + } + + componentWillUnmount () { + clearTimeout(this.initialTimeout); + window.cancelAnimationFrame(this.requestAnimationFrame); + } + + render () { + const { strokeWidth, percentage } = this.props; + const radius = (50 - strokeWidth / 2); + const pathDescription = ` + M 50,50 m 0,-${radius} + a ${radius},${radius} 0 1 1 0,${2 * radius} + a ${radius},${radius} 0 1 1 0,-${2 * radius} + `; + + const diameter = Math.PI * 2 * radius; + const progressStyle = { + strokeDasharray: `${diameter}px ${diameter}px`, + strokeDashoffset: `${((100 - this.state.percentage) / 100 * diameter)}px`, + }; + + return ( + + + + + {percentage}% + ); + } +} + +Progress.propTypes = { + percentage: PropTypes.number.isRequired, + strokeWidth: PropTypes.number, + initialAnimation: PropTypes.bool, + textForPercentage: PropTypes.func, +}; + +Progress.defaultProps = { + strokeWidth: 8, + initialAnimation: false, +}; + +export default Progress; diff --git a/frontend/src/component/feature/progress.scss b/frontend/src/component/feature/progress.scss new file mode 100644 index 0000000000..c036577277 --- /dev/null +++ b/frontend/src/component/feature/progress.scss @@ -0,0 +1,17 @@ +.path { + stroke: #3f51b5; + stroke-linecap: round; + transition: stroke-dashoffset 5s ease 0s; +} + +.trail { + stroke: #d6d6d6; +} + +.text { + fill: rgba(0, 0, 0, 0.7); + font-size: 25px; + line-height: 25px; + dominant-baseline: middle; + text-anchor: middle; +} \ No newline at end of file diff --git a/frontend/src/component/feature/view-and-edit.jsx b/frontend/src/component/feature/view-and-edit.jsx new file mode 100644 index 0000000000..d58b4ef832 --- /dev/null +++ b/frontend/src/component/feature/view-and-edit.jsx @@ -0,0 +1,22 @@ +import React, { PropTypes } from 'react'; + +import FormComponent from './form'; + + +const Render = (props) => { + return ( +
    +

    {props.featureToggle.name}

    + +

    add metrics

    +

    add apps

    +

    add instances

    + +
    +
    Edit
    + +
    + ); +}; + +export default Render; diff --git a/frontend/src/component/history/history-item-diff.jsx b/frontend/src/component/history/history-item-diff.jsx index 48d7f42b3d..e98bb530f8 100644 --- a/frontend/src/component/history/history-item-diff.jsx +++ b/frontend/src/component/history/history-item-diff.jsx @@ -1,6 +1,5 @@ import React, { PropTypes, PureComponent } from 'react'; - -import FontIcon from 'react-toolbox/lib/font_icon'; +import { Icon } from 'react-mdl'; import style from './history.scss'; @@ -110,7 +109,7 @@ class HistoryItem extends PureComponent {
    {id}
    Type:
    - + {type}
    Timestamp:
    diff --git a/frontend/src/component/history/history-list-component.jsx b/frontend/src/component/history/history-list-component.jsx index 9f41eca401..d13ecfc3ea 100644 --- a/frontend/src/component/history/history-list-component.jsx +++ b/frontend/src/component/history/history-list-component.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import HistoryItemDiff from './history-item-diff'; import HistoryItemJson from './history-item-json'; -import Switch from 'react-toolbox/lib/switch'; +import { Switch } from 'react-mdl'; import style from './history.scss'; @@ -28,11 +28,7 @@ class HistoryList extends Component { return (
    - + Show full events {entries}
    ); diff --git a/frontend/src/component/metrics/metrics-component.js b/frontend/src/component/metrics/metrics-component.js index 5ce58eabb8..e2071220a5 100644 --- a/frontend/src/component/metrics/metrics-component.js +++ b/frontend/src/component/metrics/metrics-component.js @@ -1,6 +1,5 @@ import React, { Component } from 'react'; -import { List, ListItem, ListSubHeader, ListDivider } from 'react-toolbox/lib/list'; -import Chip from 'react-toolbox/lib/chip'; +import { DataTable, TableHeader } from 'react-mdl'; class Metrics extends Component { @@ -12,17 +11,22 @@ class Metrics extends Component { const { globalCount, clientList } = this.props; return ( - - - - {clientList.map(({ name, count, ping, appName }, i) => - {count}]} - key={name + i} - caption={appName} - legend={`${name} pinged ${ping}`} /> - )} - +
    +

    {`Total of ${globalCount} toggles`}

    + + Instance + Application name + (v.toString()) + }>Last seen + Counted + + +
    ); } } diff --git a/frontend/src/component/nav.jsx b/frontend/src/component/nav.jsx deleted file mode 100644 index 0b1272243f..0000000000 --- a/frontend/src/component/nav.jsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { Component } from 'react'; -import { ListSubHeader, List, ListItem, ListDivider } from 'react-toolbox'; -import style from './styles.scss'; - -export default class UnleashNav extends Component { - static contextTypes = { - router: React.PropTypes.object, - } - - render () { - const createListItem = (path, caption) => - ; - - return ( - - {createListItem('/features', 'Feature toggles')} - {createListItem('/strategies', 'Strategies')} - {createListItem('/history', 'Event history')} - {createListItem('/archive', 'Archived toggles')} - - - - - {createListItem('/applications', 'Client applications')} - {createListItem('/client-strategies', 'Client strategies')} - - - - - {createListItem('/docs', 'Documentation')} - - - - - - -

    A product by FINN.no

    -
    -
    - - ); - } -}; diff --git a/frontend/src/component/strategies/add-strategy.jsx b/frontend/src/component/strategies/add-strategy.jsx index 80220f9246..f81d4695bf 100644 --- a/frontend/src/component/strategies/add-strategy.jsx +++ b/frontend/src/component/strategies/add-strategy.jsx @@ -1,7 +1,6 @@ import React, { PropTypes } from 'react'; -import Input from 'react-toolbox/lib/input'; -import Button from 'react-toolbox/lib/button'; +import { Textfield, Button, IconButton } from 'react-mdl'; const trim = (value) => { if (value && value.trim) { @@ -19,11 +18,10 @@ export const PARAM_PREFIX = 'param_'; const genParams = (input, num = 0, setValue) => (
    {gerArrayWithEntries(num).map((v, i) => { const key = `${PARAM_PREFIX}${i + 1}`; return ( - setValue(key, value)} + onChange={({ target }) => setValue(key, target.value)} value={input[key]} /> ); })}
    ); @@ -38,22 +36,25 @@ const AddStrategy = ({ }) => (
    - setValue('name', trim(value))} + onChange={({ target }) => setValue('name', trim(target.value))} value={input.name} /> - + setValue('description', value)} + onChange={({ target }) => setValue('description', target.value)} value={input.description} />
    {genParams(input, input._params, setValue)} -   -
    ); diff --git a/frontend/src/component/strategies/list-component.jsx b/frontend/src/component/strategies/list-component.jsx index 4a3208652b..a0c45c06e4 100644 --- a/frontend/src/component/strategies/list-component.jsx +++ b/frontend/src/component/strategies/list-component.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; -import { List, ListItem, ListSubHeader, ListDivider } from 'react-toolbox/lib/list'; -import FontIcon from 'react-toolbox/lib/font_icon'; -import Chip from 'react-toolbox/lib/chip'; + +import { List, ListItem, ListItemContent, Icon, IconButton, Chip } from 'react-mdl'; import style from './strategies.scss'; @@ -25,27 +24,24 @@ class StrategiesListComponent extends Component { const { strategies, removeStrategy } = this.props; return ( - - +
    +
    Strategies
    + this.context.router.push('/strategies/create')} title="Add new strategy"/> + +
    + {strategies.length > 0 ? strategies.map((strategy, i) => { - const actions = this.getParameterMap(strategy).concat([ - , - ]); - - return ( - + + {strategy.name} {strategy.description} + removeStrategy(strategy)} /> + ); - }) : } - - this.context.router.push('/strategies/create')} - caption="Add" legend="new strategy" leftIcon="add" /> + }) : No entries} + + +
    ); } } diff --git a/frontend/src/component/user/show-user-component.jsx b/frontend/src/component/user/show-user-component.jsx index 53f438a7eb..b248fec497 100644 --- a/frontend/src/component/user/show-user-component.jsx +++ b/frontend/src/component/user/show-user-component.jsx @@ -18,7 +18,7 @@ export default class ShowUserComponent extends React.Component { ); diff --git a/frontend/src/component/user/user-component.jsx b/frontend/src/component/user/user-component.jsx index 5290392b0b..6d4d717df1 100644 --- a/frontend/src/component/user/user-component.jsx +++ b/frontend/src/component/user/user-component.jsx @@ -1,6 +1,5 @@ import React, { PropTypes } from 'react'; -import Dialog from 'react-toolbox/lib/dialog'; -import Input from 'react-toolbox/lib/input'; +import { Textfield, Dialog, DialogTitle, DialogContent, DialogActions, Button } from 'react-mdl'; class EditUserComponent extends React.Component { static propTypes () { @@ -16,31 +15,29 @@ class EditUserComponent extends React.Component { } render () { - const actions = [ - { label: 'Save', onClick: this.props.save }, - ]; - return ( - - -

    - You hav to specify a username to use Unleash. This will allow us to track changes. -

    -
    - this.props.updateUserName(v)} - /> - -
    +
    + + Action required + +

    + You are logged in as:You hav to specify a username to use Unleash. This will allow us to track changes. +

    +
    + this.props.updateUserName(e.target.value)} + /> + +
    + + + +
    +
    ); } } diff --git a/frontend/src/page/features/edit.js b/frontend/src/page/features/edit.js index 8cba022d9b..3700ea861a 100644 --- a/frontend/src/page/features/edit.js +++ b/frontend/src/page/features/edit.js @@ -10,10 +10,7 @@ export default class Features extends Component { render () { return ( -
    -
    Edit feature toggle
    - -
    + ); } }; diff --git a/frontend/src/theme/_config.scss b/frontend/src/theme/_config.scss deleted file mode 100644 index 23243086ea..0000000000 --- a/frontend/src/theme/_config.scss +++ /dev/null @@ -1,31 +0,0 @@ -@import "~react-toolbox/lib/colors"; -@import "~react-toolbox/lib/globals"; -@import "~react-toolbox/lib/mixins"; -@import "~react-toolbox/lib/commons"; - -$color-primary:$palette-blue-400; -$color-primary-dark: $palette-blue-700; - -$navigation-drawer-desktop-width: 4 * $standard-increment-desktop !default; -$navigation-drawer-max-desktop-width: 70 * $unit !default; - -// Mobile: -// Width = Screen width − 56 dp -// Maximum width: 320dp -$navigation-drawer-mobile-width: 5 * $standard-increment-mobile !default; - -// sass doesn't like use of variable here: calc(100% - $standard-increment-mobile); -$navigation-drawer-max-mobile-width: calc(100% - 5.6rem) !default; - -.appBar { - .leftIcon { - transition-timing-function: $animation-curve-default; - transition-duration: $animation-duration; - transition-property: width, min-width; - } - @media screen and (min-width: $layout-breakpoint-sm) { - .leftIcon { - display: none; - } - } -} \ No newline at end of file diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 4568040db8..01c643ac5e 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -54,7 +54,7 @@ module.exports = { plugins, sassLoader: { - data: '@import "theme/_config.scss";', + // data: '@import "theme/_config.scss";', includePaths: [path.resolve(__dirname, './src')], },