1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-20 00:08:02 +01:00

Use 120 as width in prettier (#90)

This commit is contained in:
Simen Bekkhus 2017-08-28 21:40:44 +02:00 committed by GitHub
parent b176d63f56
commit 8ef9def08c
69 changed files with 325 additions and 1212 deletions

View File

@ -5,6 +5,15 @@
"finn-prettier"
],
"rules": {
"no-shadow": 0
"no-shadow": 0,
"prettier/prettier": [
2,
{
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 120
}
]
}
}

View File

@ -10,7 +10,7 @@
"env": {
"browser": true,
"commonjs": true,
"es6": true
"es6": true
},
"globals": {
"process": false
@ -23,6 +23,15 @@
},
"rules": {
"no-shadow": 0,
"react/sort-comp": 0
"react/sort-comp": 0,
"prettier/prettier": [
2,
{
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 120
}
]
}
}

View File

@ -89,18 +89,10 @@ export default class App extends Component {
return (
<span>
{result.map((entry, index) => (
<span
key={entry.link + index}
className={
index > 0 ? 'mdl-layout--large-screen-only' : ''
}
>
<span key={entry.link + index} className={index > 0 ? 'mdl-layout--large-screen-only' : ''}>
{index > 0 ? ' ' : null}
<Link
className={[
styles.headerTitleLink,
'mdl-color-text--primary-contrast',
].join(' ')}
className={[styles.headerTitleLink, 'mdl-color-text--primary-contrast'].join(' ')}
to={entry.link}
>
{entry.name}
@ -113,21 +105,13 @@ export default class App extends Component {
render() {
const shouldUpdateScroll = (prevRouterProps, { location }) => {
if (
prevRouterProps &&
location.pathname !== prevRouterProps.location.pathname
) {
if (prevRouterProps && location.pathname !== prevRouterProps.location.pathname) {
return location.action === 'POP';
} else {
return [0, 0];
}
};
const createListItem = (
path,
caption,
icon,
isDrawerNavigation = false
) => {
const createListItem = (path, caption, icon, isDrawerNavigation = false) => {
const linkColor =
isDrawerNavigation && this.context.router.isActive(path)
? 'mdl-color-text--black'
@ -137,20 +121,11 @@ export default class App extends Component {
? 'mdl-color-text--black'
: 'mdl-color-text--grey-600';
return (
<Link
to={path}
className={
isDrawerNavigation &&
[styles.navigationLink, linkColor].join(' ')
}
>
<Link to={path} className={isDrawerNavigation && [styles.navigationLink, linkColor].join(' ')}>
{icon && (
<Icon
name={icon}
className={
isDrawerNavigation &&
[styles.navigationIcon, iconColor].join(' ')
}
className={isDrawerNavigation && [styles.navigationIcon, iconColor].join(' ')}
/>
)}
{caption}
@ -168,79 +143,32 @@ export default class App extends Component {
</Navigation>
</Header>
<Drawer className="mdl-color--white">
<span
className={[
styles.drawerTitle,
'mdl-layout-title',
].join(' ')}
>
<img
src="public/logo.png"
width="32"
height="32"
className={styles.drawerTitleLogo}
/>
<span className={styles.drawerTitleText}>
Unleash
</span>
<span className={[styles.drawerTitle, 'mdl-layout-title'].join(' ')}>
<img src="public/logo.png" width="32" height="32" className={styles.drawerTitleLogo} />
<span className={styles.drawerTitleText}>Unleash</span>
</span>
<hr />
<Navigation className={styles.navigation}>
{createListItem(
'/features',
'Feature Toggles',
'list',
true
)}
{createListItem(
'/strategies',
'Strategies',
'extension',
true
)}
{createListItem(
'/history',
'Event History',
'history',
true
)}
{createListItem(
'/archive',
'Archived Toggles',
'archive',
true
)}
{createListItem(
'/applications',
'Applications',
'apps',
true
)}
{createListItem('/features', 'Feature Toggles', 'list', true)}
{createListItem('/strategies', 'Strategies', 'extension', true)}
{createListItem('/history', 'Event History', 'history', true)}
{createListItem('/archive', 'Archived Toggles', 'archive', true)}
{createListItem('/applications', 'Applications', 'apps', true)}
</Navigation>
<hr />
<Navigation className={styles.navigation}>
<a
href="https://github.com/Unleash"
target="_blank"
className={[
styles.navigationLink,
'mdl-color-text--grey-900',
].join(' ')}
className={[styles.navigationLink, 'mdl-color-text--grey-900'].join(' ')}
>
<i
className={[
'material-icons',
styles.navigationIcon,
styles.iconGitHub,
].join(' ')}
className={['material-icons', styles.navigationIcon, styles.iconGitHub].join(' ')}
/>GitHub
</a>
</Navigation>
</Drawer>
<ScrollContainer
scrollKey="container"
shouldUpdateScroll={shouldUpdateScroll}
>
<ScrollContainer scrollKey="container" shouldUpdateScroll={shouldUpdateScroll}>
<Content className="mdl-color--grey-50">
<Grid noSpacing className={styles.content}>
<Cell col={12}>
@ -252,54 +180,27 @@ export default class App extends Component {
<FooterSection type="middle">
<FooterDropDownSection title="Menu">
<FooterLinkList>
{createListItem(
'/features',
'Feature Toggles'
)}
{createListItem(
'/strategies',
'Strategies'
)}
{createListItem(
'/history',
'Event History'
)}
{createListItem(
'/archive',
'Archived Toggles'
)}
{createListItem(
'/applications',
'Applications'
)}
{createListItem('/features', 'Feature Toggles')}
{createListItem('/strategies', 'Strategies')}
{createListItem('/history', 'Event History')}
{createListItem('/archive', 'Archived Toggles')}
{createListItem('/applications', 'Applications')}
</FooterLinkList>
</FooterDropDownSection>
<FooterDropDownSection title="Clients">
<FooterLinkList>
<a href="https://github.com/Unleash/unleash-client-node/">
Node.js
</a>
<a href="https://github.com/Unleash/unleash-client-java/">
Java
</a>
<a href="https://github.com/Unleash/unleash-client-go/">
Go
</a>
<a href="https://github.com/Unleash/unleash-client-node/">Node.js</a>
<a href="https://github.com/Unleash/unleash-client-java/">Java</a>
<a href="https://github.com/Unleash/unleash-client-go/">Go</a>
</FooterLinkList>
</FooterDropDownSection>
</FooterSection>
<FooterSection type="bottom" logo="Unleash">
<FooterLinkList>
<a
href="https://github.com/Unleash/unleash/"
target="_blank"
>
<a href="https://github.com/Unleash/unleash/" target="_blank">
GitHub
</a>
<a
href="https://finn.no"
target="_blank"
>
<a href="https://finn.no" target="_blank">
<small>A product by</small> FINN.no
</a>
</FooterLinkList>

View File

@ -6,9 +6,7 @@ import renderer from 'react-test-renderer';
jest.mock('react-mdl');
test('renders correctly if no application', () => {
const tree = renderer
.create(<ClientApplications fetchApplication={jest.fn()} />)
.toJSON();
const tree = renderer.create(<ClientApplications fetchApplication={jest.fn()} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -61,16 +61,7 @@ class ClientApplications extends PureComponent {
return <ProgressBar indeterminate />;
}
const { application, storeApplicationMetaData } = this.props;
const {
appName,
instances,
strategies,
seenToggles,
url,
description,
icon = 'apps',
color,
} = application;
const { appName, instances, strategies, seenToggles, url, description, icon = 'apps', color } = application;
const content =
this.state.activeTab === 0 ? (
@ -83,17 +74,8 @@ class ClientApplications extends PureComponent {
({ name, description, enabled, notFound }, i) =>
notFound ? (
<ListItem twoLine key={i}>
<ListItemContent
icon={'report'}
subtitle={
'Missing, want to create?'
}
>
<Link
to={`/features/create?name=${name}`}
>
{name}
</Link>
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
<Link to={`/features/create?name=${name}`}>{name}</Link>
</ListItemContent>
</ListItem>
) : (
@ -101,22 +83,12 @@ class ClientApplications extends PureComponent {
<ListItemContent
icon={
<span>
<Switch
disabled
checked={!!enabled}
/>
<Switch disabled checked={!!enabled} />
</span>
}
subtitle={shorten(
description,
60
)}
subtitle={shorten(description, 60)}
>
<Link
to={`/features/view/${name}`}
>
{shorten(name, 50)}
</Link>
<Link to={`/features/view/${name}`}>{shorten(name, 50)}</Link>
</ListItemContent>
</ListItem>
)
@ -131,33 +103,14 @@ class ClientApplications extends PureComponent {
({ name, description, notFound }, i) =>
notFound ? (
<ListItem twoLine key={`${name}-${i}`}>
<ListItemContent
icon={'report'}
subtitle={
'Missing, want to create?'
}
>
<Link
to={`/strategies/create?name=${name}`}
>
{name}
</Link>
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
<Link to={`/strategies/create?name=${name}`}>{name}</Link>
</ListItemContent>
</ListItem>
) : (
<ListItem twoLine key={`${name}-${i}`}>
<ListItemContent
icon={'extension'}
subtitle={shorten(
description,
60
)}
>
<Link
to={`/strategies/view/${name}`}
>
{shorten(name, 50)}
</Link>
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
<Link to={`/strategies/view/${name}`}>{shorten(name, 50)}</Link>
</ListItemContent>
</ListItem>
)
@ -168,32 +121,20 @@ class ClientApplications extends PureComponent {
<h6>{instances.length} Instances registered</h6>
<hr />
<List>
{instances.map(
(
{
instanceId,
clientIp,
lastSeen,
sdkVersion,
},
i
) => (
<ListItem key={i} twoLine>
<ListItemContent
icon="timeline"
subtitle={
<span>
{clientIp} last seen at{' '}
<small>{formatFullDateTime(lastSeen)}</small>
</span>
}
>
{instanceId}{' '}
{sdkVersion ? `(${sdkVersion})` : ''}
</ListItemContent>
</ListItem>
)
)}
{instances.map(({ instanceId, clientIp, lastSeen, sdkVersion }, i) => (
<ListItem key={i} twoLine>
<ListItemContent
icon="timeline"
subtitle={
<span>
{clientIp} last seen at <small>{formatFullDateTime(lastSeen)}</small>
</span>
}
>
{instanceId} {sdkVersion ? `(${sdkVersion})` : ''}
</ListItemContent>
</ListItem>
))}
</List>
</Cell>
</Grid>
@ -206,46 +147,26 @@ class ClientApplications extends PureComponent {
<StatefulTextfield
value={url}
label="URL"
onBlur={e =>
storeApplicationMetaData(
appName,
'url',
e.target.value
)}
onBlur={e => storeApplicationMetaData(appName, 'url', e.target.value)}
/>
<br />
<StatefulTextfield
value={description}
label="Description"
rows={5}
onBlur={e =>
storeApplicationMetaData(
appName,
'description',
e.target.value
)}
onBlur={e => storeApplicationMetaData(appName, 'description', e.target.value)}
/>
</Cell>
<Cell col={6} tablet={12}>
<StatefulTextfield
value={icon}
label="Select icon"
onBlur={e =>
storeApplicationMetaData(
appName,
'icon',
e.target.value
)}
onBlur={e => storeApplicationMetaData(appName, 'icon', e.target.value)}
/>
<StatefulTextfield
value={color}
label="Select color"
onBlur={e =>
storeApplicationMetaData(
appName,
'color',
e.target.value
)}
onBlur={e => storeApplicationMetaData(appName, 'color', e.target.value)}
/>
</Cell>
</Grid>
@ -253,13 +174,7 @@ class ClientApplications extends PureComponent {
return (
<Card shadow={0} className={commonStyles.fullwidth}>
<CardTitle
style={{
paddingTop: '24px',
paddingRight: '64px',
wordBreak: 'break-all',
}}
>
<CardTitle style={{ paddingTop: '24px', paddingRight: '64px', wordBreak: 'break-all' }}>
<Icon name={icon} /> {appName}
</CardTitle>
{description && <CardText>{description}</CardText>}

View File

@ -1,9 +1,6 @@
import { connect } from 'react-redux';
import ApplicationEdit from './application-edit-component';
import {
fetchApplication,
storeApplicationMetaData,
} from '../../store/application/actions';
import { fetchApplication, storeApplicationMetaData } from '../../store/application/actions';
const mapStateToProps = (state, props) => {
let application = state.applications.getIn(['apps', props.appName]);

View File

@ -2,9 +2,7 @@ import { connect } from 'react-redux';
import ApplicationList from './application-list-component';
import { fetchAll } from '../../store/application/actions';
const mapStateToProps = state => ({
applications: state.applications.get('list').toJS(),
});
const mapStateToProps = state => ({ applications: state.applications.get('list').toJS() });
const Container = connect(mapStateToProps, { fetchAll })(ApplicationList);

View File

@ -102,8 +102,7 @@ exports[`renders correctly with no archived toggles 1`] = `
}
/>
<br />
No archived feature toggles, go see
No archived feature toggles, go see
<a
onClick={[Function]}
style={Object {}}

View File

@ -16,8 +16,7 @@ const archive = [
},
{
name: 'adin-pay-platform-sch-payment',
description:
'Enables use of schibsted payment from order-payment-management',
description: 'Enables use of schibsted payment from order-payment-management',
enabled: true,
strategies: [{ name: 'default', parameters: {} }],
createdAt: '2016-08-03T12:41:35.631Z',
@ -26,17 +25,13 @@ const archive = [
];
test('renders correctly with no archived toggles', () => {
const tree = renderer
.create(<ArchiveList fetchArchive={jest.fn()} archive={[]} />)
.toJSON();
const tree = renderer.create(<ArchiveList fetchArchive={jest.fn()} archive={[]} />).toJSON();
expect(tree).toMatchSnapshot();
});
test('renders correctly with archived toggles', () => {
const tree = renderer
.create(<ArchiveList fetchArchive={jest.fn()} archive={archive} />)
.toJSON();
const tree = renderer.create(<ArchiveList fetchArchive={jest.fn()} archive={archive} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -10,8 +10,6 @@ const mapStateToProps = state => {
};
};
const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(
ListComponent
);
const ArchiveListContainer = connect(mapStateToProps, { fetchArchive, revive })(ListComponent);
export default ArchiveListContainer;

View File

@ -17,20 +17,12 @@ class ArchiveList extends Component {
<Card shadow={0} className={commonStyles.fullwidth}>
{archive.length > 0 ? (
<div className={commonStyles.horisontalScroll}>
<DataTable
rows={archive}
className={commonStyles.fullwidth}
style={{ border: 0 }}
>
<DataTable rows={archive} className={commonStyles.fullwidth} style={{ border: 0 }}>
<TableHeader
style={{ width: '25px' }}
name="reviveName"
cellFormatter={reviveName => (
<IconButton
colored
name="undo"
onClick={() => revive(reviveName)}
/>
<IconButton colored name="undo" onClick={() => revive(reviveName)} />
)}
>
Revive
@ -50,14 +42,9 @@ class ArchiveList extends Component {
</div>
) : (
<div className={commonStyles.emptyState}>
<Icon
name="archive"
className="mdl-color-text--grey-300"
style={{ fontSize: '56px' }}
/>
<Icon name="archive" className="mdl-color-text--grey-300" style={{ fontSize: '56px' }} />
<br />
No archived feature toggles, go see{' '}
<Link to="/features">active toggles here</Link>
No archived feature toggles, go see <Link to="/features">active toggles here</Link>
</div>
)}
</Card>

View File

@ -6,14 +6,7 @@ import renderer from 'react-test-renderer';
jest.mock('react-mdl');
test('renders correctly with no clientInstances', () => {
const tree = renderer
.create(
<ClientStrategies
fetchClientInstances={jest.fn()}
clientInstances={[]}
/>
)
.toJSON();
const tree = renderer.create(<ClientStrategies fetchClientInstances={jest.fn()} clientInstances={[]} />).toJSON();
expect(tree).toMatchSnapshot();
});

View File

@ -16,11 +16,7 @@ class ClientStrategies extends Component {
const source = this.props.clientInstances;
return (
<DataTable
style={{ width: '100%' }}
rows={source}
selectable={false}
>
<DataTable style={{ width: '100%' }} rows={source} selectable={false}>
<TableHeader name="instanceId">Instance ID</TableHeader>
<TableHeader name="appName">Application name</TableHeader>
<TableHeader name="clientIp">IP</TableHeader>

View File

@ -2,12 +2,8 @@ import { connect } from 'react-redux';
import ClientInstances from './client-instance-component';
import { fetchClientInstances } from '../../store/client-instance-actions';
const mapStateToProps = state => ({
clientInstances: state.clientInstances.toJS(),
});
const mapStateToProps = state => ({ clientInstances: state.clientInstances.toJS() });
const StrategiesContainer = connect(mapStateToProps, { fetchClientInstances })(
ClientInstances
);
const StrategiesContainer = connect(mapStateToProps, { fetchClientInstances })(ClientInstances);
export default StrategiesContainer;

View File

@ -1,44 +1,22 @@
import React from 'react';
import { Link } from 'react-router';
import {
List,
ListItem,
ListItemContent,
Button,
Icon,
Switch,
MenuItem,
} from 'react-mdl';
import { List, ListItem, ListItemContent, Button, Icon, Switch, MenuItem } from 'react-mdl';
import styles from './common.scss';
export { styles };
export const shorten = (str, len = 50) =>
str && str.length > len ? `${str.substring(0, len)}...` : str;
export const shorten = (str, len = 50) => (str && str.length > len ? `${str.substring(0, len)}...` : str);
export const AppsLinkList = ({ apps }) => (
<List>
{apps.length > 0 &&
apps.map(({ appName, description = '-', icon = 'apps' }) => (
<ListItem twoLine key={appName}>
<span
className="mdl-list__item-primary-content"
style={{ minWidth: 0 }}
>
<span className="mdl-list__item-primary-content" style={{ minWidth: 0 }}>
<Icon name={icon} className="mdl-list__item-avatar" />
<Link
to={`/applications/${appName}`}
className={[styles.listLink, styles.truncate].join(
' '
)}
>
<Link to={`/applications/${appName}`} className={[styles.listLink, styles.truncate].join(' ')}>
{appName}
<span
className={[
'mdl-list__item-sub-title',
styles.truncate,
].join(' ')}
>
<span className={['mdl-list__item-sub-title', styles.truncate].join(' ')}>
{description}
</span>
</Link>
@ -62,9 +40,7 @@ export const HeaderTitle = ({ title, actions, subtitle }) => (
{subtitle && <small>{subtitle}</small>}
</div>
{actions && (
<div style={{ flex: '1', textAlign: 'right' }}>{actions}</div>
)}
{actions && <div style={{ flex: '1', textAlign: 'right' }}>{actions}</div>}
</div>
);
@ -84,24 +60,13 @@ export const FormButtons = ({ submitText = 'Create', onCancel }) => (
{submitText}
</Button>
&nbsp;
<Button
type="cancel"
ripple
raised
onClick={onCancel}
style={{ float: 'right' }}
>
<Button type="cancel" ripple raised onClick={onCancel} style={{ float: 'right' }}>
<Icon name="cancel" />&nbsp;&nbsp;&nbsp; Cancel
</Button>
</div>
);
export const SwitchWithLabel = ({
onChange,
checked,
children,
...switchProps
}) => (
export const SwitchWithLabel = ({ onChange, checked, children, ...switchProps }) => (
<span className={styles.switchWithLabel}>
<span className={styles.label}>{children}</span>
<span className={styles.switch}>
@ -141,12 +106,7 @@ export function getIcon(type) {
}
export const IconLink = ({ url, icon }) => (
<a
href={url}
target="_blank"
rel="noopener"
className="mdl-color-text--grey-600"
>
<a href={url} target="_blank" rel="noopener" className="mdl-color-text--grey-600">
<Icon name={icon} />
</a>
);
@ -158,17 +118,8 @@ export const DropdownButton = ({ label, id }) => (
</Button>
);
export const MenuItemWithIcon = ({
icon,
label,
disabled,
...menuItemProps
}) => (
<MenuItem
disabled={disabled}
style={{ display: 'flex', alignItems: 'center' }}
{...menuItemProps}
>
export const MenuItemWithIcon = ({ icon, label, disabled, ...menuItemProps }) => (
<MenuItem disabled={disabled} style={{ display: 'flex', alignItems: 'center' }} {...menuItemProps}>
<Icon name={icon} style={{ paddingRight: '16px' }} />
{label}
</MenuItem>
@ -176,11 +127,7 @@ export const MenuItemWithIcon = ({
const badNumbers = [NaN, Infinity, -Infinity];
export function calc(value, total, decimal) {
if (
typeof value !== 'number' ||
typeof total !== 'number' ||
typeof decimal !== 'number'
) {
if (typeof value !== 'number' || typeof total !== 'number' || typeof decimal !== 'number') {
return null;
}

View File

@ -7,5 +7,4 @@ const dateTimeOptions = {
second: '2-digit',
};
export const formatFullDateTime = v =>
new Date(v).toLocaleString('nb-NO', dateTimeOptions);
export const formatFullDateTime = v => new Date(v).toLocaleString('nb-NO', dateTimeOptions);

View File

@ -8,13 +8,7 @@ const ErrorComponent = ({ errors, ...props }) => {
const error = showError ? errors[0] : undefined;
const muteError = () => props.muteError(error);
return (
<Snackbar
action="Dismiss"
active={showError}
onActionClick={muteError}
onTimeout={muteError}
timeout={10000}
>
<Snackbar action="Dismiss" active={showError} onActionClick={muteError} onTimeout={muteError} timeout={10000}>
<Icon name="question_answer" /> {error}
</Snackbar>
);

View File

@ -17,23 +17,13 @@ const Feature = ({
const { name, description, enabled, strategies } = feature;
const { showLastHour = false } = settings;
const isStale = showLastHour
? metricsLastHour.isFallback
: metricsLastMinute.isFallback;
const isStale = showLastHour ? metricsLastHour.isFallback : metricsLastMinute.isFallback;
const percent =
1 *
(showLastHour
? calc(
metricsLastHour.yes,
metricsLastHour.yes + metricsLastHour.no,
0
)
: calc(
metricsLastMinute.yes,
metricsLastMinute.yes + metricsLastMinute.no,
0
));
? calc(metricsLastHour.yes, metricsLastHour.yes + metricsLastHour.no, 0)
: calc(metricsLastMinute.yes, metricsLastMinute.yes + metricsLastMinute.no, 0));
const strategiesToShow = Math.min(strategies.length, 3);
const remainingStrategies = strategies.length - strategiesToShow;
@ -45,18 +35,12 @@ const Feature = ({
{s.name}
</Chip>
));
const summaryChip = remainingStrategies > 0 && (
<Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>
);
const summaryChip = remainingStrategies > 0 && <Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
return (
<ListItem twoLine>
<span className={styles.listItemMetric}>
<Progress
strokeWidth={15}
percentage={percent}
isFallback={isStale}
/>
<Progress strokeWidth={15} percentage={percent} isFallback={isStale} />
</span>
<span className={styles.listItemToggle}>
<Switch
@ -66,36 +50,16 @@ const Feature = ({
checked={enabled}
/>
</span>
<span
className={[
'mdl-list__item-primary-content',
styles.listItemLink,
].join(' ')}
>
<span className={['mdl-list__item-primary-content', styles.listItemLink].join(' ')}>
<Link
to={`/features/view/${name}`}
className={[
commonStyles.listLink,
commonStyles.truncate,
].join(' ')}
className={[commonStyles.listLink, commonStyles.truncate].join(' ')}
>
{name}
<span
className={[
'mdl-list__item-sub-title',
commonStyles.truncate,
].join(' ')}
>
{description}
</span>
<span className={['mdl-list__item-sub-title', commonStyles.truncate].join(' ')}>{description}</span>
</Link>
</span>
<span
className={[
styles.listItemStrategies,
commonStyles.hideLt920,
].join(' ')}
>
<span className={[styles.listItemStrategies, commonStyles.hideLt920].join(' ')}>
{strategyChips}
{summaryChip}
</span>

View File

@ -1,9 +1,6 @@
import { connect } from 'react-redux';
import { hashHistory } from 'react-router';
import {
createFeatureToggles,
validateName,
} from '../../store/feature-actions';
import { createFeatureToggles, validateName } from '../../store/feature-actions';
import { createMapper, createActions } from '../input-helpers';
import FormAddComponent from './form-add-component';

View File

@ -92,10 +92,7 @@ class AddFeatureToggleComponent extends Component {
/>
<br />
<FormButtons
submitText={editmode ? 'Update' : 'Create'}
onCancel={onCancel}
/>
<FormButtons submitText={editmode ? 'Update' : 'Create'} onCancel={onCancel} />
</section>
</form>
);

View File

@ -10,9 +10,7 @@ class AddStrategy extends React.Component {
};
addStrategy = strategyName => {
const selectedStrategy = this.props.strategies.find(
s => s.name === strategyName
);
const selectedStrategy = this.props.strategies.find(s => s.name === strategyName);
const parameters = {};
selectedStrategy.parameters.forEach(({ name }) => {
@ -37,14 +35,7 @@ class AddStrategy extends React.Component {
backgroundColor: 'rgb(247, 248, 255)',
};
return (
<div
style={{
position: 'relative',
width: '25px',
height: '25px',
display: 'inline-block',
}}
>
<div style={{ position: 'relative', width: '25px', height: '25px', display: 'inline-block' }}>
<IconButton
name="add"
id="strategies-add"
@ -53,20 +44,10 @@ class AddStrategy extends React.Component {
title="Add Strategy"
onClick={this.stopPropagation}
/>
<Menu
target="strategies-add"
valign="bottom"
align="right"
ripple
style={menuStyle}
>
<Menu target="strategies-add" valign="bottom" align="right" ripple style={menuStyle}>
<MenuItem disabled>Add Strategy:</MenuItem>
{this.props.strategies.map(s => (
<MenuItem
key={s.name}
title={s.description}
onClick={() => this.addStrategy(s.name)}
>
<MenuItem key={s.name} title={s.description} onClick={() => this.addStrategy(s.name)}>
{s.name}
</MenuItem>
))}

View File

@ -15,13 +15,7 @@ class StrategiesList extends React.Component {
};
render() {
const {
strategies,
configuredStrategies,
moveStrategy,
removeStrategy,
updateStrategy,
} = this.props;
const { strategies, configuredStrategies, moveStrategy, removeStrategy, updateStrategy } = this.props;
if (!configuredStrategies || configuredStrategies.length === 0) {
return <i style={{ color: 'red' }}>No strategies added</i>;
@ -35,14 +29,10 @@ class StrategiesList extends React.Component {
moveStrategy={moveStrategy}
removeStrategy={removeStrategy.bind(null, i)}
updateStrategy={updateStrategy.bind(null, i)}
strategyDefinition={strategies.find(
s => s.name === strategy.name
)}
strategyDefinition={strategies.find(s => s.name === strategy.name)}
/>
));
return (
<div style={{ display: 'flex', flexWrap: 'wrap' }}>{blocks}</div>
);
return <div style={{ display: 'flex', flexWrap: 'wrap' }}>{blocks}</div>;
}
}

View File

@ -25,10 +25,7 @@ class StrategiesSection extends React.Component {
return (
<div>
<HeaderTitle
title="Activation strategies"
actions={<AddStrategy {...this.props} />}
/>
<HeaderTitle title="Activation strategies" actions={<AddStrategy {...this.props} />} />
<StrategiesList {...this.props} />
</div>
);

View File

@ -1,16 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Textfield,
Button,
Card,
CardTitle,
CardText,
CardActions,
CardMenu,
IconButton,
Icon,
} from 'react-mdl';
import { Textfield, Button, Card, CardTitle, CardText, CardActions, CardMenu, IconButton, Icon } from 'react-mdl';
import { DragSource, DropTarget } from 'react-dnd';
import { Link } from 'react-router';
import StrategyInputPercentage from './strategy-input-percentage';
@ -91,25 +81,17 @@ class StrategyConfigure extends React.Component {
return parameters.map(({ name, type, description, required }) => {
let value = this.props.strategy.parameters[name];
if (type === 'percentage') {
if (
value == null ||
(typeof value === 'string' && value === '')
) {
if (value == null || (typeof value === 'string' && value === '')) {
this.setConfig(name, 50);
}
return (
<div key={name}>
<StrategyInputPercentage
name={name}
onChange={this.handleConfigChange.bind(
this,
name
)}
onChange={this.handleConfigChange.bind(this, name)}
value={1 * value}
/>
{description && (
<p className={styles.helpText}>{description}</p>
)}
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else if (type === 'list') {
@ -122,14 +104,8 @@ class StrategyConfigure extends React.Component {
}
return (
<div key={name}>
<StrategyInputList
name={name}
list={list}
setConfig={this.setConfig}
/>
{description && (
<p className={styles.helpText}>{description}</p>
)}
<StrategyInputList name={name} list={list} setConfig={this.setConfig} />
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else if (type === 'number') {
@ -143,15 +119,10 @@ class StrategyConfigure extends React.Component {
style={{ width: '100%' }}
name={name}
label={name}
onChange={this.handleConfigChange.bind(
this,
name
)}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
/>
{description && (
<p className={styles.helpText}>{description}</p>
)}
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
} else {
@ -164,15 +135,10 @@ class StrategyConfigure extends React.Component {
required={required}
name={name}
label={name}
onChange={this.handleConfigChange.bind(
this,
name
)}
onChange={this.handleConfigChange.bind(this, name)}
value={value}
/>
{description && (
<p className={styles.helpText}>{description}</p>
)}
{description && <p className={styles.helpText}>{description}</p>}
</div>
);
}
@ -182,31 +148,18 @@ class StrategyConfigure extends React.Component {
}
render() {
const {
isDragging,
connectDragPreview,
connectDragSource,
connectDropTarget,
} = this.props;
const { isDragging, connectDragPreview, connectDragSource, connectDropTarget } = this.props;
let item;
if (this.props.strategyDefinition) {
const inputFields = this.renderInputFields(
this.props.strategyDefinition
);
const inputFields = this.renderInputFields(this.props.strategyDefinition);
const { name } = this.props.strategy;
item = (
<Card
shadow={0}
className={styles.card}
style={{ opacity: isDragging ? '0.1' : '1' }}
>
<Card shadow={0} className={styles.card} style={{ opacity: isDragging ? '0.1' : '1' }}>
<CardTitle className={styles.cardTitle}>
<Icon name="extension" />&nbsp;{name}
</CardTitle>
<CardText>
{this.props.strategyDefinition.description}
</CardText>
<CardText>{this.props.strategyDefinition.description}</CardText>
{inputFields && (
<CardActions border style={{ padding: '20px' }}>
{inputFields}
@ -214,18 +167,10 @@ class StrategyConfigure extends React.Component {
)}
<CardMenu className="mdl-color-text--white">
<Link
title="View strategy"
to={`/strategies/view/${name}`}
className={styles.editLink}
>
<Link title="View strategy" to={`/strategies/view/${name}`} className={styles.editLink}>
<Icon name="link" />
</Link>
<IconButton
title="Remove strategy from toggle"
name="delete"
onClick={this.handleRemove}
/>
<IconButton title="Remove strategy from toggle" name="delete" onClick={this.handleRemove} />
{connectDragSource(
<span className={styles.reorderIcon}>
<Icon name="reorder" />
@ -241,17 +186,10 @@ class StrategyConfigure extends React.Component {
<CardTitle>"{name}" deleted?</CardTitle>
<CardText>
The strategy "{name}" does not exist on this server.
<Link to={`/strategies/create?name=${name}`}>
Want to create it now?
</Link>
<Link to={`/strategies/create?name=${name}`}>Want to create it now?</Link>
</CardText>
<CardActions>
<Button
onClick={this.handleRemove}
label="remove strategy"
accent
raised
>
<Button onClick={this.handleRemove} label="remove strategy" accent raised>
Remove
</Button>
</CardActions>
@ -259,9 +197,7 @@ class StrategyConfigure extends React.Component {
);
}
return connectDropTarget(
connectDragPreview(<div className={styles.item}>{item}</div>)
);
return connectDropTarget(connectDragPreview(<div className={styles.item}>{item}</div>));
}
}

View File

@ -46,10 +46,7 @@ export default class InputList extends Component {
onClose(index) {
const { name, list, setConfig } = this.props;
list[index] = null;
setConfig(
name,
list.length === 1 ? '' : list.filter(Boolean).join(',')
);
setConfig(name, list.length === 1 ? '' : list.filter(Boolean).join(','));
}
render() {
@ -58,11 +55,7 @@ export default class InputList extends Component {
<div>
<p>{name}</p>
{list.map((entryValue, index) => (
<Chip
key={index + entryValue}
style={{ marginRight: '3px' }}
onClose={() => this.onClose(index)}
>
<Chip key={index + entryValue} style={{ marginRight: '3px' }} onClose={() => this.onClose(index)}>
{entryValue}
</Chip>
))}
@ -79,11 +72,7 @@ export default class InputList extends Component {
<IconButton
name="add"
raised
style={{
flex: 1,
flexGrow: 0,
margin: '20px 0 0 10px',
}}
style={{ flex: 1, flexGrow: 0, margin: '20px 0 0 10px' }}
onClick={this.setValue}
/>
</div>

View File

@ -13,13 +13,6 @@ export default ({ name, value, onChange }) => (
<div style={labelStyle}>
{name}: {value}%
</div>
<Slider
min={0}
max={100}
defaultValue={value}
value={value}
onChange={onChange}
label={name}
/>
<Slider min={0} max={100} defaultValue={value} value={value} onChange={onChange} label={name} />
</div>
);

View File

@ -2,22 +2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import Feature from './feature-list-item-component';
import { Link } from 'react-router';
import {
Icon,
FABButton,
Textfield,
Menu,
MenuItem,
Card,
CardActions,
List,
} from 'react-mdl';
import { Icon, FABButton, Textfield, Menu, MenuItem, Card, CardActions, List } from 'react-mdl';
import {
MenuItemWithIcon,
DropdownButton,
styles as commonStyles,
} from '../common';
import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
import styles from './feature.scss';
export default class FeatureListComponent extends React.PureComponent {
@ -47,10 +34,7 @@ export default class FeatureListComponent extends React.PureComponent {
}
toggleMetrics() {
this.props.updateSetting(
'showLastHour',
!this.props.settings.showLastHour
);
this.props.updateSetting('showLastHour', !this.props.settings.showLastHour);
}
setFilter(v) {
@ -62,12 +46,7 @@ export default class FeatureListComponent extends React.PureComponent {
}
render() {
const {
features,
toggleFeature,
featureMetrics,
settings,
} = this.props;
const { features, toggleFeature, featureMetrics, settings } = this.props;
return (
<div>
@ -81,32 +60,16 @@ export default class FeatureListComponent extends React.PureComponent {
label="Search"
style={{ width: '100%' }}
/>
<Link
to="/features/create"
className={styles.toolbarButton}
>
<Link to="/features/create" className={styles.toolbarButton}>
<FABButton accent title="Create feature toggle">
<Icon name="add" />
</FABButton>
</Link>
</div>
<Card
shadow={0}
className={commonStyles.fullwidth}
style={{ overflow: 'visible' }}
>
<Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
<CardActions>
<DropdownButton
id="metric"
label={`Last ${settings.showLastHour
? 'hour'
: 'minute'}`}
/>
<Menu
target="metric"
onClick={() => this.toggleMetrics()}
style={{ width: '168px' }}
>
<DropdownButton id="metric" label={`Last ${settings.showLastHour ? 'hour' : 'minute'}`} />
<Menu target="metric" onClick={() => this.toggleMetrics()} style={{ width: '168px' }}>
<MenuItemWithIcon
icon="hourglass_empty"
disabled={!settings.showLastHour}
@ -120,46 +83,25 @@ export default class FeatureListComponent extends React.PureComponent {
label="Last hour"
/>
</Menu>
<DropdownButton
id="sorting"
label={`By ${settings.sort}`}
/>
<DropdownButton id="sorting" label={`By ${settings.sort}`} />
<Menu
target="sorting"
onClick={e =>
this.setSort(
e.target.getAttribute('data-target')
)}
onClick={e => this.setSort(e.target.getAttribute('data-target'))}
style={{ width: '168px' }}
>
<MenuItem
disabled={settings.sort === 'name'}
data-target="name"
>
<MenuItem disabled={settings.sort === 'name'} data-target="name">
Name
</MenuItem>
<MenuItem
disabled={settings.sort === 'enabled'}
data-target="enabled"
>
<MenuItem disabled={settings.sort === 'enabled'} data-target="enabled">
Enabled
</MenuItem>
<MenuItem
disabled={settings.sort === 'created'}
data-target="created"
>
<MenuItem disabled={settings.sort === 'created'} data-target="created">
Created
</MenuItem>
<MenuItem
disabled={settings.sort === 'strategies'}
data-target="strategies"
>
<MenuItem disabled={settings.sort === 'strategies'} data-target="strategies">
Strategies
</MenuItem>
<MenuItem
disabled={settings.sort === 'metrics'}
data-target="metrics"
>
<MenuItem disabled={settings.sort === 'metrics'} data-target="metrics">
Metrics
</MenuItem>
</Menu>
@ -170,12 +112,8 @@ export default class FeatureListComponent extends React.PureComponent {
<Feature
key={i}
settings={settings}
metricsLastHour={
featureMetrics.lastHour[feature.name]
}
metricsLastMinute={
featureMetrics.lastMinute[feature.name]
}
metricsLastHour={featureMetrics.lastHour[feature.name]}
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
feature={feature}
toggleFeature={toggleFeature}
/>

View File

@ -1,8 +1,5 @@
import { connect } from 'react-redux';
import {
toggleFeature,
fetchFeatureToggles,
} from '../../store/feature-actions';
import { toggleFeature, fetchFeatureToggles } from '../../store/feature-actions';
import { fetchFeatureMetrics } from '../../store/feature-metrics-actions';
import { updateSettingForGroup } from '../../store/settings/actions';
@ -33,9 +30,7 @@ const mapStateToProps = state => {
a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1
);
} else if (settings.sort === 'created') {
features = features.sort(
(a, b) => (new Date(a.createdAt) > new Date(b.createdAt) ? -1 : 1)
);
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) {
@ -47,13 +42,9 @@ const mapStateToProps = state => {
return 0;
});
} else if (settings.sort === 'strategies') {
features = features.sort(
(a, b) => (a.strategies.length > b.strategies.length ? -1 : 1)
);
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;
const target = settings.showLastHour ? featureMetrics.lastHour : featureMetrics.lastMinute;
features = features.sort((a, b) => {
if (!target[a.name]) {
@ -83,8 +74,6 @@ const mapDispatchToProps = {
updateSetting: updateSettingForGroup('feature'),
};
const FeatureListContainer = connect(mapStateToProps, mapDispatchToProps)(
FeatureListComponent
);
const FeatureListContainer = connect(mapStateToProps, mapDispatchToProps)(FeatureListComponent);
export default FeatureListContainer;

View File

@ -12,10 +12,7 @@ const StrategyChipItem = ({ strategy }) => (
<ChipContact className="mdl-color--blue-grey mdl-color-text--white">
<Icon style={{ marginTop: '3px' }} name="link" />
</ChipContact>
<Link
to={`/strategies/view/${strategy.name}`}
className="mdl-color-text--blue-grey"
>
<Link to={`/strategies/view/${strategy.name}`} className="mdl-color-text--blue-grey">
{strategy.name}
</Link>
</Chip>
@ -25,9 +22,7 @@ const StrategyChipItem = ({ strategy }) => (
const StrategiesList = ({ strategies }) => (
<div style={{ verticalAlign: 'middle', paddingTop: '14px' }}>
With {strategies.length > 1 ? 'strategies' : 'strategy'}{' '}
{strategies.map((strategy, i) => (
<StrategyChipItem key={i} strategy={strategy} />
))}
{strategies.map((strategy, i) => <StrategyChipItem key={i} strategy={strategy} />)}
</div>
);
@ -59,10 +54,8 @@ export default class MetricComponent extends React.Component {
seenApps = [],
} = metrics;
const lastHourPercent =
1 * calc(lastHour.yes, lastHour.yes + lastHour.no, 0);
const lastMinutePercent =
1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0);
const lastHourPercent = 1 * calc(lastHour.yes, lastHour.yes + lastHour.no, 0);
const lastMinutePercent = 1 * calc(lastMinute.yes, lastMinute.yes + lastMinute.no, 0);
return (
<div style={{ padding: '16px' }}>
@ -75,9 +68,7 @@ export default class MetricComponent extends React.Component {
animatePercentageText
/>
{lastMinute.isFallback ? (
<p className="mdl-color-text--grey-500">
No metrics available
</p>
<p className="mdl-color-text--grey-500">No metrics available</p>
) : (
<p>
<strong>Last minute</strong>
@ -86,14 +77,9 @@ export default class MetricComponent extends React.Component {
)}
</Cell>
<Cell col={4} tablet={4} phone={12}>
<Progress
percentage={lastHourPercent}
isFallback={lastHour.isFallback}
/>
<Progress percentage={lastHourPercent} isFallback={lastHour.isFallback} />
{lastHour.isFallback ? (
<p className="mdl-color-text--grey-500">
No metrics available
</p>
<p className="mdl-color-text--grey-500">No metrics available</p>
) : (
<p>
<strong>Last hour</strong>
@ -115,20 +101,14 @@ export default class MetricComponent extends React.Component {
/>
<div>
<small>
<strong>
Not used in an app in the last hour.
</strong>
This might be due to your client
implementation is not reporting usage.
<strong>Not used in an app in the last hour.</strong>
This might be due to your client implementation is not reporting usage.
</small>
</div>
</div>
)}
<AppsLinkList apps={seenApps} />
<span>
Created{' '}
{formatFullDateTime(featureToggle.createdAt)}
</span>
<span>Created {formatFullDateTime(featureToggle.createdAt)}</span>
</Cell>
</Grid>
<hr />

View File

@ -1,9 +1,6 @@
import { connect } from 'react-redux';
import {
fetchFeatureMetrics,
fetchSeenApps,
} from '../../store/feature-metrics-actions';
import { fetchFeatureMetrics, fetchSeenApps } from '../../store/feature-metrics-actions';
import MatricComponent from './metric-component';
@ -18,10 +15,7 @@ function getMetricsForToggle(state, toggleName) {
}
if (state.featureMetrics.hasIn(['lastHour', toggleName])) {
result.lastHour = state.featureMetrics.getIn(['lastHour', toggleName]);
result.lastMinute = state.featureMetrics.getIn([
'lastMinute',
toggleName,
]);
result.lastMinute = state.featureMetrics.getIn(['lastMinute', toggleName]);
}
return result;
}

View File

@ -41,9 +41,7 @@ class Progress extends Component {
const TOTAL_ANIMATION_TIME = 5000;
const diff = start > target ? -(start - target) : target - start;
const perCycle = TOTAL_ANIMATION_TIME / diff;
const cyclesCounter = Math.round(
Math.abs(TOTAL_ANIMATION_TIME / perCycle)
);
const cyclesCounter = Math.round(Math.abs(TOTAL_ANIMATION_TIME / perCycle));
const perCycleTime = Math.round(Math.abs(perCycle));
return {
@ -95,9 +93,7 @@ class Progress extends Component {
const diameter = Math.PI * 2 * radius;
const progressStyle = {
strokeDasharray: `${diameter}px ${diameter}px`,
strokeDashoffset: `${(100 - this.state.percentage) /
100 *
diameter}px`,
strokeDashoffset: `${(100 - this.state.percentage) / 100 * diameter}px`,
};
return isFallback ? (
@ -113,9 +109,7 @@ class Progress extends Component {
) : (
<svg viewBox="0 0 100 100">
<path
className={[styles.trail, 'mdl-color-text--grey-300'].join(
' '
)}
className={[styles.trail, 'mdl-color-text--grey-300'].join(' ')}
d={pathDescription}
strokeWidth={strokeWidth}
fillOpacity={0}

View File

@ -1,16 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Tabs,
Tab,
ProgressBar,
Button,
Card,
CardTitle,
CardText,
CardActions,
Switch,
} from 'react-mdl';
import { Tabs, Tab, ProgressBar, Button, Card, CardTitle, CardText, CardActions, Switch } from 'react-mdl';
import { hashHistory, Link } from 'react-router';
import HistoryComponent from '../history/history-list-toggle-container';
@ -90,9 +80,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
);
}
const activeTabId = TABS[this.props.activeTab]
? TABS[this.props.activeTab]
: TABS.view;
const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.view;
const tabContent = this.getTabContent(activeTab);
const removeToggle = () => {
@ -106,16 +94,8 @@ export default class ViewFeatureToggleComponent extends React.Component {
};
return (
<Card
shadow={0}
className={commonStyles.fullwidth}
style={{ overflow: 'visible' }}
>
<CardTitle
style={{ paddingTop: '24px', wordBreak: 'break-all' }}
>
{featureToggle.name}
</CardTitle>
<Card shadow={0} className={commonStyles.fullwidth} style={{ overflow: 'visible' }}>
<CardTitle style={{ paddingTop: '24px', wordBreak: 'break-all' }}>{featureToggle.name}</CardTitle>
<CardText>{featureToggle.description}</CardText>
<CardActions
border
@ -145,22 +125,9 @@ export default class ViewFeatureToggleComponent extends React.Component {
tabBarProps={{ style: { width: '100%' } }}
className="mdl-color--grey-100"
>
<Tab
onClick={() => this.goToTab('view', featureToggleName)}
>
Metrics
</Tab>
<Tab
onClick={() => this.goToTab('edit', featureToggleName)}
>
Edit
</Tab>
<Tab
onClick={() =>
this.goToTab('history', featureToggleName)}
>
History
</Tab>
<Tab onClick={() => this.goToTab('view', featureToggleName)}>Metrics</Tab>
<Tab onClick={() => this.goToTab('edit', featureToggleName)}>Edit</Tab>
<Tab onClick={() => this.goToTab('history', featureToggleName)}>History</Tab>
</Tabs>
{tabContent}
</Card>

View File

@ -1,19 +1,13 @@
import { connect } from 'react-redux';
import {
fetchFeatureToggles,
toggleFeature,
removeFeatureToggle,
} from '../../store/feature-actions';
import { fetchFeatureToggles, toggleFeature, removeFeatureToggle } from '../../store/feature-actions';
import ViewToggleComponent from './view-component';
export default connect(
(state, props) => ({
features: state.features.toJS(),
featureToggle: state.features
.toJS()
.find(toggle => toggle.name === props.featureToggleName),
featureToggle: state.features.toJS().find(toggle => toggle.name === props.featureToggleName),
activeTab: props.activeTab,
}),
{

View File

@ -9,8 +9,6 @@ const mapStateToProps = state => {
};
};
const HistoryListContainer = connect(mapStateToProps, { fetchHistory })(
HistoryComponent
);
const HistoryListContainer = connect(mapStateToProps, { fetchHistory })(HistoryComponent);
export default HistoryListContainer;

View File

@ -84,18 +84,12 @@ class HistoryItem extends PureComponent {
changes = entry.diffs.map(buildDiff);
} else {
// Just show the data if there is no diff yet.
changes = (
<div className={KLASSES.N}>
{JSON.stringify(entry.data, null, 2)}
</div>
);
changes = <div className={KLASSES.N}>{JSON.stringify(entry.data, null, 2)}</div>;
}
return (
<pre style={{ overflowX: 'auto', overflowY: 'hidden' }}>
<code className="smalltext man">
{changes.length === 0 ? '(no changes)' : changes}
</code>
<code className="smalltext man">{changes.length === 0 ? '(no changes)' : changes}</code>
</pre>
);
}

View File

@ -2,11 +2,7 @@ import React, { Component } from 'react';
import HistoryItemDiff from './history-item-diff';
import HistoryItemJson from './history-item-json';
import { Table, TableHeader } from 'react-mdl';
import {
DataTableHeader,
SwitchWithLabel,
styles as commonStyles,
} from '../common';
import { DataTableHeader, SwitchWithLabel, styles as commonStyles } from '../common';
import { formatFullDateTime } from '../common/util';
import styles from './history.scss';
@ -26,11 +22,7 @@ class HistoryList extends Component {
const truncateTableCell = v => (
<span
className={commonStyles.truncate}
style={{
display: 'inline-block',
verticalAlign: 'middle',
width: '100%',
}}
style={{ display: 'inline-block', verticalAlign: 'middle', width: '100%' }}
>
{v}
</span>
@ -39,9 +31,7 @@ class HistoryList extends Component {
let entries;
if (showData) {
entries = history.map(entry => (
<HistoryItemJson key={`log${entry.id}`} entry={entry} />
));
entries = history.map(entry => <HistoryItemJson key={`log${entry.id}`} entry={entry} />);
} else {
entries = (
<Table
@ -55,33 +45,16 @@ class HistoryList extends Component {
)
)}
className={commonStyles.fullwidth}
style={{
border: 0,
tableLayout: 'fixed',
minWidth: '840px',
}}
style={{ border: 0, tableLayout: 'fixed', minWidth: '840px' }}
>
<TableHeader
name="type"
cellFormatter={truncateTableCell}
style={{ width: '136px' }}
>
<TableHeader name="type" cellFormatter={truncateTableCell} style={{ width: '136px' }}>
Type
</TableHeader>
<TableHeader
name="createdBy"
cellFormatter={truncateTableCell}
style={{ width: '115px' }}
>
<TableHeader name="createdBy" cellFormatter={truncateTableCell} style={{ width: '115px' }}>
User
</TableHeader>
<TableHeader name="diff">Diff</TableHeader>
<TableHeader
numeric
name="createdAt"
cellFormatter={formatFullDateTime}
style={{ width: '165px' }}
>
<TableHeader numeric name="createdAt" cellFormatter={formatFullDateTime} style={{ width: '165px' }}>
Time
</TableHeader>
</Table>
@ -93,10 +66,7 @@ class HistoryList extends Component {
<DataTableHeader
title={this.props.title}
actions={
<SwitchWithLabel
checked={showData}
onChange={this.toggleShowDiff.bind(this)}
>
<SwitchWithLabel checked={showData} onChange={this.toggleShowDiff.bind(this)}>
Full events
</SwitchWithLabel>
}

View File

@ -52,44 +52,23 @@ export function createActions({ id, prepare = v => v }) {
},
setValue(key, value) {
dispatch(
createSet({ id: getId(id, ownProps), key, value })
);
dispatch(createSet({ id: getId(id, ownProps), key, value }));
},
pushToList(key, value) {
dispatch(
createPush({ id: getId(id, ownProps), key, value })
);
dispatch(createPush({ id: getId(id, ownProps), key, value }));
},
removeFromList(key, index) {
dispatch(
createPop({ id: getId(id, ownProps), key, index })
);
dispatch(createPop({ id: getId(id, ownProps), key, index }));
},
moveItem(key, index, toIndex) {
dispatch(
createMove({
id: getId(id, ownProps),
key,
index,
toIndex,
})
);
dispatch(createMove({ id: getId(id, ownProps), key, index, toIndex }));
},
updateInList(key, index, newValue, merge = false) {
dispatch(
createUp({
id: getId(id, ownProps),
key,
index,
newValue,
merge,
})
);
dispatch(createUp({ id: getId(id, ownProps), key, index, newValue, merge }));
},
incValue(key) {

View File

@ -13,19 +13,12 @@ const prepare = (methods, dispatch) => {
// clean
const parameters = (input.parameters || [])
.filter(name => !!name)
.map(
({
name,
type = 'string',
description = '',
required = false,
}) => ({
name,
type,
description,
required,
})
);
.map(({ name, type = 'string', description = '', required = false }) => ({
name,
type,
description,
required,
}));
createStrategy({
name: input.name,

View File

@ -1,15 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Textfield,
IconButton,
Menu,
MenuItem,
Checkbox,
Grid,
Cell,
} from 'react-mdl';
import { Textfield, IconButton, Menu, MenuItem, Checkbox, Grid, Cell } from 'react-mdl';
import { FormButtons } from '../common';
const trim = value => {
@ -25,13 +17,7 @@ function gerArrayWithEntries(num) {
}
const Parameter = ({ set, input = {}, index }) => (
<div
style={{
background: '#f1f1f1',
padding: '16px 20px',
marginBottom: '20px',
}}
>
<div style={{ background: '#f1f1f1', padding: '16px 20px', marginBottom: '20px' }}>
<Textfield
style={{ width: '50%' }}
floatingLabel
@ -46,8 +32,7 @@ const Parameter = ({ set, input = {}, index }) => (
style={{
borderRadius: '2px',
cursor: 'pointer',
boxShadow:
'0 2px 2px 0 rgba(0,0,0,.04),0 3px 1px -2px rgba(0,0,0,.1),0 1px 5px 0 rgba(0,0,0,.12)',
boxShadow: '0 2px 2px 0 rgba(0,0,0,.04),0 3px 1px -2px rgba(0,0,0,.1),0 1px 5px 0 rgba(0,0,0,.12)',
marginLeft: '10px',
border: '1px solid #f1f1f1',
backgroundColor: 'white',
@ -55,22 +40,13 @@ const Parameter = ({ set, input = {}, index }) => (
}}
>
{input.type || 'string'}
<IconButton
name="arrow_drop_down"
onClick={evt => evt.preventDefault()}
/>
<IconButton name="arrow_drop_down" onClick={evt => evt.preventDefault()} />
</span>
<Menu target={`${index}-type-menu`} align="right">
<MenuItem onClick={() => set({ type: 'string' })}>
string
</MenuItem>
<MenuItem onClick={() => set({ type: 'percentage' })}>
percentage
</MenuItem>
<MenuItem onClick={() => set({ type: 'string' })}>string</MenuItem>
<MenuItem onClick={() => set({ type: 'percentage' })}>percentage</MenuItem>
<MenuItem onClick={() => set({ type: 'list' })}>list</MenuItem>
<MenuItem onClick={() => set({ type: 'number' })}>
number
</MenuItem>
<MenuItem onClick={() => set({ type: 'number' })}>number</MenuItem>
</Menu>
</div>
<Textfield
@ -95,8 +71,7 @@ const EditHeader = () => (
<div>
<h4 style={{ marginTop: '16px' }}>Edit strategy</h4>
<p style={{ background: '#ffb7b7', padding: '16px 20px' }}>
Be carefull! Changing a strategy definition might also require
changes to the implementation in the clients.
Be carefull! Changing a strategy definition might also require changes to the implementation in the clients.
</p>
</div>
);
@ -110,12 +85,7 @@ const CreateHeader = () => (
const Parameters = ({ input = [], count = 0, updateInList }) => (
<div>
{gerArrayWithEntries(count).map((v, i) => (
<Parameter
key={i}
set={v => updateInList('parameters', i, v, true)}
index={i}
input={input[i]}
/>
<Parameter key={i} set={v => updateInList('parameters', i, v, true)} index={i} input={input[i]} />
))}
</div>
);
@ -139,24 +109,13 @@ class AddStrategy extends Component {
if (this.props.initCallRequired === true) {
this.props.init(this.props.input);
if (this.props.input.parameters) {
this.props.setValue(
'_params',
this.props.input.parameters.length
);
this.props.setValue('_params', this.props.input.parameters.length);
}
}
}
render() {
const {
input,
setValue,
updateInList,
incValue,
onCancel,
editmode = false,
onSubmit,
} = this.props;
const { input, setValue, updateInList, incValue, onCancel, editmode = false, onSubmit } = this.props;
return (
<Grid className="mdl-color--white">
@ -170,8 +129,7 @@ class AddStrategy extends Component {
required
disabled={editmode}
pattern="^[0-9a-zA-Z\.\-]+$"
onChange={({ target }) =>
setValue('name', trim(target.value))}
onChange={({ target }) => setValue('name', trim(target.value))}
value={input.name}
/>
<br />
@ -181,15 +139,10 @@ class AddStrategy extends Component {
rows={1}
label="Description"
name="description"
onChange={({ target }) =>
setValue('description', target.value)}
onChange={({ target }) => setValue('description', target.value)}
value={input.description}
/>
<Parameters
input={input.parameters}
count={input._params}
updateInList={updateInList}
/>
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
<IconButton
raised
name="add"
@ -202,10 +155,7 @@ class AddStrategy extends Component {
&nbsp;Add parameter
<br />
<hr />
<FormButtons
submitText={editmode ? 'Update' : 'Create'}
onCancel={onCancel}
/>
<FormButtons submitText={editmode ? 'Update' : 'Create'} onCancel={onCancel} />
</form>
</Cell>
</Grid>

View File

@ -28,19 +28,12 @@ const prepare = (methods, dispatch) => {
// clean
const parameters = (input.parameters || [])
.filter(name => !!name)
.map(
({
name,
type = 'string',
description = '',
required = false,
}) => ({
name,
type,
description,
required,
})
);
.map(({ name, type = 'string', description = '', required = false }) => ({
name,
type,
description,
required,
}));
updateStrategy({
name: input.name,

View File

@ -2,14 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router';
import {
List,
ListItem,
ListItemContent,
IconButton,
Grid,
Cell,
} from 'react-mdl';
import { List, ListItem, ListItemContent, IconButton, Grid, Cell } from 'react-mdl';
import { HeaderTitle } from '../common';
class StrategiesListComponent extends Component {
@ -33,10 +26,7 @@ class StrategiesListComponent extends Component {
<IconButton
raised
name="add"
onClick={() =>
this.context.router.push(
'/strategies/create'
)}
onClick={() => this.context.router.push('/strategies/create')}
title="Add new strategy"
/>
}
@ -45,24 +35,15 @@ class StrategiesListComponent extends Component {
{strategies.length > 0 ? (
strategies.map((strategy, i) => (
<ListItem key={i} twoLine>
<ListItemContent
icon="extension"
subtitle={strategy.description}
>
<Link
to={`/strategies/view/${strategy.name}`}
>
<ListItemContent icon="extension" subtitle={strategy.description}>
<Link to={`/strategies/view/${strategy.name}`}>
<strong>{strategy.name}</strong>
</Link>
</ListItemContent>
{strategy.editable === false ? (
''
) : (
<IconButton
name="delete"
onClick={() =>
removeStrategy(strategy)}
/>
<IconButton name="delete" onClick={() => removeStrategy(strategy)} />
)}
</ListItem>
))

View File

@ -20,8 +20,6 @@ const mapDispatchToProps = dispatch => ({
fetchStrategies: () => fetchStrategies()(dispatch),
});
const StrategiesListContainer = connect(mapStateToProps, mapDispatchToProps)(
StrategiesListComponent
);
const StrategiesListContainer = connect(mapStateToProps, mapDispatchToProps)(StrategiesListComponent);
export default StrategiesListContainer;

View File

@ -13,15 +13,8 @@ class ShowStrategyComponent extends PureComponent {
renderParameters(params) {
if (params) {
return params.map(({ name, type, description, required }, i) => (
<ListItem
twoLine
key={`${name}-${i}`}
title={required ? 'Required' : ''}
>
<ListItemContent
avatar={required ? 'add' : ' '}
subtitle={description}
>
<ListItem twoLine key={`${name}-${i}`} title={required ? 'Required' : ''}>
<ListItemContent avatar={required ? 'add' : ' '} subtitle={description}>
{name} <small>({type})</small>
</ListItemContent>
</ListItem>

View File

@ -54,9 +54,7 @@ export default class StrategyDetails extends Component {
}
render() {
const activeTabId = TABS[this.props.activeTab]
? TABS[this.props.activeTab]
: TABS.view;
const activeTabId = TABS[this.props.activeTab] ? TABS[this.props.activeTab] : TABS.view;
const strategy = this.props.strategy;
if (!strategy) {
return <ProgressBar indeterminate />;
@ -67,17 +65,12 @@ export default class StrategyDetails extends Component {
return (
<Grid className="mdl-color--white">
<Cell col={12}>
<HeaderTitle
title={strategy.name}
subtitle={strategy.description}
/>
<HeaderTitle title={strategy.name} subtitle={strategy.description} />
{strategy.editable === false ? (
''
) : (
<Tabs activeTab={activeTabId} ripple>
<Tab onClick={() => this.goToTab('view')}>
Details
</Tab>
<Tab onClick={() => this.goToTab('view')}>Details</Tab>
<Tab onClick={() => this.goToTab('edit')}>Edit</Tab>
</Tabs>
)}

View File

@ -5,17 +5,10 @@ import { fetchAll } from '../../store/application/actions';
import { fetchFeatureToggles } from '../../store/feature-actions';
const mapStateToProps = (state, props) => {
let strategy = state.strategies
.get('list')
.find(n => n.name === props.strategyName);
const applications = state.applications
.get('list')
.filter(app => app.strategies.includes(props.strategyName));
let strategy = state.strategies.get('list').find(n => n.name === props.strategyName);
const applications = state.applications.get('list').filter(app => app.strategies.includes(props.strategyName));
const toggles = state.features.filter(
toggle =>
toggle
.get('strategies')
.findIndex(s => s.name === props.strategyName) > -1
toggle => toggle.get('strategies').findIndex(s => s.name === props.strategyName) > -1
);
return {

View File

@ -15,11 +15,7 @@ export default class ShowUserComponent extends React.Component {
render() {
return (
<a
className="mdl-navigation__link"
href="#edit-user"
onClick={this.openEdit}
>
<a className="mdl-navigation__link" href="#edit-user" onClick={this.openEdit}>
<Tooltip label={this.props.user.userName || 'Unknown'} large>
<Icon name="account_circle" />
</Tooltip>

View File

@ -39,25 +39,17 @@ class EditUserComponent extends React.Component {
render() {
return (
<div>
<Modal
isOpen={this.props.user.showDialog}
contentLabel="test"
style={customStyles}
>
<Modal isOpen={this.props.user.showDialog} contentLabel="test" style={customStyles}>
<h2>Action required</h2>
<div>
<p>
You have to specify a username to use Unleash. This
will allow us to track your changes.
</p>
<p>You have to specify a username to use Unleash. This will allow us to track your changes.</p>
<form onSubmit={this.handleSubmit}>
<Textfield
label="Username"
name="username"
required
value={this.props.user.userName}
onChange={e =>
this.props.updateUserName(e.target.value)}
onChange={e => this.props.updateUserName(e.target.value)}
/>
<br />
<Button raised accent>

View File

@ -4,10 +4,7 @@ const URI = 'api/admin/features';
function validateToggle(featureToggle) {
return new Promise((resolve, reject) => {
if (
!featureToggle.strategies ||
featureToggle.strategies.length === 0
) {
if (!featureToggle.strategies || featureToggle.strategies.length === 0) {
reject(new Error('You must add at least one activation strategy'));
} else {
resolve(featureToggle);

View File

@ -1,9 +1,7 @@
const defaultErrorMessage = 'Unexptected exception when talking to unleash-api';
function extractJoiMsg(body) {
return body.details.length > 0
? body.details[0].message
: defaultErrorMessage;
return body.details.length > 0 ? body.details[0].message : defaultErrorMessage;
}
function extractLegacyMsg(body) {
return body && body.length > 0 ? body[0].msg : defaultErrorMessage;
@ -14,10 +12,7 @@ export function throwIfNotSuccess(response) {
if (response.status > 399 && response.status < 404) {
return new Promise((resolve, reject) => {
response.json().then(body => {
const errorMsg =
body && body.isJoi
? extractJoiMsg(body)
: extractLegacyMsg(body);
const errorMsg = body && body.isJoi ? extractJoiMsg(body) : extractLegacyMsg(body);
let error = new Error(errorMsg);
error.statusCode = response.status;
reject(error);

View File

@ -4,13 +4,7 @@ import 'react-mdl/extra/material.js';
import React from 'react';
import ReactDOM from 'react-dom';
import {
applyRouterMiddleware,
Router,
Route,
IndexRedirect,
hashHistory,
} from 'react-router';
import { applyRouterMiddleware, Router, Route, IndexRedirect, hashHistory } from 'react-router';
import { useScroll } from 'react-router-scroll';
import { Provider } from 'react-redux';
import thunkMiddleware from 'redux-thunk';
@ -33,60 +27,31 @@ import ApplicationView from './page/applications/view';
let composeEnhancers;
if (
process.env.NODE_ENV !== 'production' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
) {
if (process.env.NODE_ENV !== 'production' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
} else {
composeEnhancers = compose;
}
const unleashStore = createStore(
store,
composeEnhancers(applyMiddleware(thunkMiddleware))
);
const unleashStore = createStore(store, composeEnhancers(applyMiddleware(thunkMiddleware)));
// "pageTitle" and "link" attributes are for internal usage only
ReactDOM.render(
<Provider store={unleashStore}>
<Router
history={hashHistory}
render={applyRouterMiddleware(useScroll())}
>
<Router history={hashHistory} render={applyRouterMiddleware(useScroll())}>
<Route path="/" component={App}>
<IndexRedirect to="/features" />
<Route pageTitle="Feature Toggles" link="/features">
<Route
pageTitle="Feature toggles"
path="/features"
component={Features}
/>
<Route
pageTitle="New"
path="/features/create"
component={CreateFeatureToggle}
/>
<Route
pageTitle=":name"
path="/features/:activeTab/:name"
component={ViewFeatureToggle}
/>
<Route pageTitle="Feature toggles" path="/features" component={Features} />
<Route pageTitle="New" path="/features/create" component={CreateFeatureToggle} />
<Route pageTitle=":name" path="/features/:activeTab/:name" component={ViewFeatureToggle} />
</Route>
<Route pageTitle="Strategies" link="/strategies">
<Route
pageTitle="Strategies"
path="/strategies"
component={Strategies}
/>
<Route
pageTitle="New"
path="/strategies/create"
component={CreateStrategies}
/>
<Route pageTitle="Strategies" path="/strategies" component={Strategies} />
<Route pageTitle="New" path="/strategies/create" component={CreateStrategies} />
<Route
pageTitle=":strategyName"
path="/strategies/:activeTab/:strategyName"
@ -95,34 +60,14 @@ ReactDOM.render(
</Route>
<Route pageTitle="Event History" link="/history">
<Route
pageTitle="Event history"
path="/history"
component={HistoryPage}
/>
<Route
pageTitle=":toggleName"
path="/history/:toggleName"
component={HistoryTogglePage}
/>
<Route pageTitle="Event history" path="/history" component={HistoryPage} />
<Route pageTitle=":toggleName" path="/history/:toggleName" component={HistoryTogglePage} />
</Route>
<Route
pageTitle="Archived Toggles"
path="/archive"
component={Archive}
/>
<Route pageTitle="Archived Toggles" path="/archive" component={Archive} />
<Route pageTitle="Applications" link="/applications">
<Route
pageTitle="Applications"
path="/applications"
component={Applications}
/>
<Route
pageTitle=":name"
path="/applications/:name"
component={ApplicationView}
/>
<Route pageTitle="Applications" path="/applications" component={Applications} />
<Route pageTitle=":name" path="/applications/:name" component={ApplicationView} />
</Route>
</Route>
</Router>

View File

@ -2,9 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ApplicationEditComponent from '../../component/application/application-edit-container';
const render = ({ params }) => (
<ApplicationEditComponent appName={params.name} />
);
const render = ({ params }) => <ApplicationEditComponent appName={params.name} />;
render.propTypes = {
params: PropTypes.object.isRequired,

View File

@ -9,11 +9,6 @@ export default class Features extends PureComponent {
render() {
const { params } = this.props;
return (
<ViewFeatureToggle
featureToggleName={params.name}
activeTab={params.activeTab}
/>
);
return <ViewFeatureToggle featureToggleName={params.name} activeTab={params.activeTab} />;
}
}

View File

@ -2,9 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import HistoryListToggle from '../../component/history/history-list-toggle-container';
const render = ({ params }) => (
<HistoryListToggle toggleName={params.toggleName} />
);
const render = ({ params }) => <HistoryListToggle toggleName={params.toggleName} />;
render.propTypes = {
params: PropTypes.object.isRequired,

View File

@ -2,12 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ShowStrategy from '../../component/strategies/strategy-details-container';
const render = ({ params }) => (
<ShowStrategy
strategyName={params.strategyName}
activeTab={params.activeTab}
/>
);
const render = ({ params }) => <ShowStrategy strategyName={params.strategyName} activeTab={params.activeTab} />;
render.propTypes = {
params: PropTypes.object.isRequired,

View File

@ -2,8 +2,7 @@ import api from '../../data/applications-api';
export const RECEIVE_ALL_APPLICATIONS = 'RECEIVE_ALL_APPLICATIONS';
export const ERROR_RECEIVE_ALL_APPLICATIONS = 'ERROR_RECEIVE_ALL_APPLICATIONS';
export const ERROR_UPDATING_APPLICATION_DATA =
'ERROR_UPDATING_APPLICATION_DATA';
export const ERROR_UPDATING_APPLICATION_DATA = 'ERROR_UPDATING_APPLICATION_DATA';
export const RECEIVE_APPLICATION = 'RECEIVE_APPLICATION';
@ -17,10 +16,7 @@ const recieveApplication = json => ({
value: json,
});
const errorReceiveApplications = (
statusCode,
type = ERROR_RECEIVE_ALL_APPLICATIONS
) => ({
const errorReceiveApplications = (statusCode, type = ERROR_RECEIVE_ALL_APPLICATIONS) => ({
type,
statusCode,
});
@ -37,14 +33,7 @@ export function storeApplicationMetaData(appName, key, value) {
return dispatch =>
api
.storeApplicationMetaData(appName, key, value)
.catch(error =>
dispatch(
errorReceiveApplications(
error,
ERROR_UPDATING_APPLICATION_DATA
)
)
);
.catch(error => dispatch(errorReceiveApplications(error, ERROR_UPDATING_APPLICATION_DATA)));
}
export function fetchApplication(appName) {

View File

@ -8,10 +8,7 @@ function getInitState() {
const store = (state = getInitState(), action) => {
switch (action.type) {
case RECEIVE_APPLICATION:
return state.setIn(
['apps', action.value.appName],
new Map(action.value)
);
return state.setIn(['apps', action.value.appName], new Map(action.value));
case RECEIVE_ALL_APPLICATIONS:
return state.set('list', new List(action.value.applications));
default:

View File

@ -8,9 +8,7 @@ function getInitState() {
const archiveStore = (state = getInitState(), action) => {
switch (action.type) {
case REVIVE_TOGGLE:
return state.update('list', list =>
list.filter(item => item.name !== action.value)
);
return state.update('list', list => list.filter(item => item.name !== action.value));
case RECEIVE_ARCHIVE:
return state.set('list', new List(action.value));
default:

View File

@ -7,11 +7,7 @@ import {
ERROR_UPDATE_FEATURE_TOGGLE,
} from './feature-actions';
import {
ERROR_UPDATING_STRATEGY,
ERROR_CREATING_STRATEGY,
ERROR_RECEIVE_STRATEGIES,
} from './strategy/actions';
import { ERROR_UPDATING_STRATEGY, ERROR_CREATING_STRATEGY, ERROR_RECEIVE_STRATEGIES } from './strategy/actions';
const debug = require('debug')('unleash:error-store');
@ -40,9 +36,7 @@ const strategies = (state = getInitState(), action) => {
case ERROR_RECEIVE_STRATEGIES:
return addErrorIfNotAlreadyInList(state, action.error.message);
case MUTE_ERROR:
return state.update('list', list =>
list.remove(list.indexOf(action.error))
);
return state.update('list', list => list.remove(list.indexOf(action.error)));
default:
return state;
}

View File

@ -85,9 +85,7 @@ export function requestUpdateFeatureToggle(featureToggle) {
return api
.update(featureToggle)
.then(() =>
dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle })
)
.then(() => dispatch({ type: UPDATE_FEATURE_TOGGLE, featureToggle }))
.catch(dispatchAndThrow(dispatch, ERROR_UPDATE_FEATURE_TOGGLE));
};
}
@ -98,9 +96,7 @@ export function removeFeatureToggle(featureToggleName) {
return api
.remove(featureToggleName)
.then(() =>
dispatch({ type: REMOVE_FEATURE_TOGGLE, featureToggleName })
)
.then(() => dispatch({ type: REMOVE_FEATURE_TOGGLE, featureToggleName }))
.catch(dispatchAndThrow(dispatch, ERROR_REMOVE_FEATURE_TOGGLE));
};
}

View File

@ -1,14 +1,8 @@
import { Map as $Map, fromJS } from 'immutable';
import {
RECEIVE_FEATURE_METRICS,
RECEIVE_SEEN_APPS,
} from './feature-metrics-actions';
import { RECEIVE_FEATURE_METRICS, RECEIVE_SEEN_APPS } from './feature-metrics-actions';
const metrics = (
state = fromJS({ lastHour: {}, lastMinute: {}, seenApps: {} }),
action
) => {
const metrics = (state = fromJS({ lastHour: {}, lastMinute: {}, seenApps: {} }), action) => {
switch (action.type) {
case RECEIVE_SEEN_APPS:
return state.set('seenApps', new $Map(action.value));

View File

@ -16,9 +16,7 @@ const features = (state = new List([]), action) => {
return state.push(new $Map(action.featureToggle));
case REMOVE_FEATURE_TOGGLE:
debug(REMOVE_FEATURE_TOGGLE, action);
return state.filter(
toggle => toggle.get('name') !== action.featureToggleName
);
return state.filter(toggle => toggle.get('name') !== action.featureToggleName);
case TOGGLE_FEATURE_TOGGLE:
debug(TOGGLE_FEATURE_TOGGLE, action);
return state.map(toggle => {

View File

@ -8,10 +8,7 @@ function getInitState() {
const historyStore = (state = getInitState(), action) => {
switch (action.type) {
case RECEIVE_HISTORY_FOR_TOGGLE:
return state.setIn(
['toggles', action.value.toggleName],
new List(action.value.events)
);
return state.setIn(['toggles', action.value.toggleName], new List(action.value.events));
case RECEIVE_HISTORY:
return state.set('list', new List(action.value));
default:

View File

@ -9,41 +9,12 @@ export const actions = {
MOVE: 'MOVE',
};
export const createInit = ({ id, value }) => ({
type: actions.INIT,
id,
value,
});
export const createInc = ({ id, key }) => ({
type: actions.INCREMENT_VALUE,
id,
key,
});
export const createSet = ({ id, key, value }) => ({
type: actions.SET_VALUE,
id,
key,
value,
});
export const createPush = ({ id, key, value }) => ({
type: actions.LIST_PUSH,
id,
key,
value,
});
export const createPop = ({ id, key, index }) => ({
type: actions.LIST_POP,
id,
key,
index,
});
export const createMove = ({ id, key, index, toIndex }) => ({
type: actions.MOVE,
id,
key,
index,
toIndex,
});
export const createInit = ({ id, value }) => ({ type: actions.INIT, id, value });
export const createInc = ({ id, key }) => ({ type: actions.INCREMENT_VALUE, id, key });
export const createSet = ({ id, key, value }) => ({ type: actions.SET_VALUE, id, key, value });
export const createPush = ({ id, key, value }) => ({ type: actions.LIST_PUSH, id, key, value });
export const createPop = ({ id, key, index }) => ({ type: actions.LIST_POP, id, key, index });
export const createMove = ({ id, key, index, toIndex }) => ({ type: actions.MOVE, id, key, index, toIndex });
export const createUp = ({ id, key, index, newValue, merge }) => ({
type: actions.LIST_UP,
id,

View File

@ -7,5 +7,4 @@ export const updateSetting = (group, field, value) => ({
value,
});
export const updateSettingForGroup = group => (field, value) =>
updateSetting(group, field, value);
export const updateSettingForGroup = group => (field, value) => updateSetting(group, field, value);

View File

@ -15,10 +15,7 @@ function getInitState() {
}
function updateSetting(state, action) {
const newState = state.updateIn(
[action.group, action.field],
() => action.value
);
const newState = state.updateIn([action.group, action.field], () => action.value);
localStorage.setItem(SETTINGS, JSON.stringify(newState.toJSON()));
return newState;

View File

@ -1,10 +1,5 @@
import { List, Map as $Map } from 'immutable';
import {
RECEIVE_STRATEGIES,
REMOVE_STRATEGY,
ADD_STRATEGY,
UPDATE_STRATEGY,
} from './actions';
import { RECEIVE_STRATEGIES, REMOVE_STRATEGY, ADD_STRATEGY, UPDATE_STRATEGY } from './actions';
function getInitState() {
return new $Map({ list: new List() });

View File

@ -20,9 +20,7 @@ function readCookie() {
}
function writeCookie(userName) {
document.cookie = `${COOKIE_NAME}=${encodeURIComponent(
userName
)}; expires=Thu, 18 Dec 2099 12:00:00 UTC`;
document.cookie = `${COOKIE_NAME}=${encodeURIComponent(userName)}; expires=Thu, 18 Dec 2099 12:00:00 UTC`;
}
function getInitState() {

View File

@ -54,17 +54,14 @@ module.exports = {
sourceMap: true,
modules: true,
importLoaders: 1,
localIdentName:
'[name]__[local]___[hash:base64:5]',
localIdentName: '[name]__[local]___[hash:base64:5]',
},
},
{
loader: 'sass-loader',
options: {
// data: '@import "theme/_config.scss";',
includePaths: [
path.resolve(__dirname, './src'),
],
includePaths: [path.resolve(__dirname, './src')],
},
},
],
@ -72,10 +69,7 @@ module.exports = {
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader',
}),
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }),
},
],
},

View File

@ -1253,7 +1253,15 @@ chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
chalk@^2.0.0, chalk@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d"
dependencies:
ansi-styles "^3.1.0"
escape-string-regexp "^1.0.5"
supports-color "^4.0.0"
chalk@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies:
@ -2465,10 +2473,14 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.0.2, function-bind@^1.1.0:
function-bind@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
function-bind@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@ -3364,7 +3376,14 @@ js-tokens@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
js-yaml@^3.7.0, js-yaml@^3.9.1:
js-yaml@^3.7.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.0.tgz#4ffbbf25c2ac963b8299dc74da7e3740de1c18ce"
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
js-yaml@^3.9.1:
version "3.9.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.1.tgz#08775cebdfdd359209f0d2acd383c8f86a6904a0"
dependencies: