@@ -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%' }}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{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 (
);
+ }
+}
+
+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 = ({
}) => (
);
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 (
-
+
+
+
);
}
}
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')],
},