mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-26 13:48:33 +02:00
Merge branch 'master' into add_sdk_version
This commit is contained in:
commit
73a0ffccee
@ -67,13 +67,13 @@
|
|||||||
"babel-preset-stage-0": "^6.5.0",
|
"babel-preset-stage-0": "^6.5.0",
|
||||||
"babel-preset-stage-2": "^6.13.0",
|
"babel-preset-stage-2": "^6.13.0",
|
||||||
"css-loader": "^0.25.0",
|
"css-loader": "^0.25.0",
|
||||||
"eslint": "^3.4.0",
|
"eslint": "^4.1.1",
|
||||||
"eslint-config-finn": "1.0.0-alpha.11",
|
"eslint-config-finn": "^2.0.0",
|
||||||
"eslint-config-finn-react": "^1.0.0-alpha.2",
|
"eslint-config-finn-react": "^2.0.0",
|
||||||
"eslint-plugin-react": "^6.2.0",
|
"eslint-plugin-react": "^7.1.0",
|
||||||
"extract-text-webpack-plugin": "^1.0.1",
|
"extract-text-webpack-plugin": "^1.0.1",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^19.0.2",
|
"jest": "^20.0.4",
|
||||||
"node-sass": "~3.12.1",
|
"node-sass": "~3.12.1",
|
||||||
"postcss-loader": "^0.13.0",
|
"postcss-loader": "^0.13.0",
|
||||||
"react-test-renderer": "^15.4.2",
|
"react-test-renderer": "^15.4.2",
|
||||||
|
@ -146,42 +146,42 @@ export default class App extends Component {
|
|||||||
</Navigation>
|
</Navigation>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<ScrollContainer scrollKey="container" shouldUpdateScroll={shouldUpdateScroll}>
|
<ScrollContainer scrollKey="container" shouldUpdateScroll={shouldUpdateScroll}>
|
||||||
<Content className="mdl-color--grey-50">
|
<Content className="mdl-color--grey-50">
|
||||||
<Grid noSpacing className={styles.content}>
|
<Grid noSpacing className={styles.content}>
|
||||||
<Cell col={12}>
|
<Cell col={12}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
<ErrorContainer />
|
<ErrorContainer />
|
||||||
</Cell>
|
</Cell>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Footer size="mega">
|
<Footer size="mega">
|
||||||
<FooterSection type="middle">
|
<FooterSection type="middle">
|
||||||
<FooterDropDownSection title="Menu">
|
<FooterDropDownSection title="Menu">
|
||||||
|
<FooterLinkList>
|
||||||
|
{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>
|
||||||
|
</FooterLinkList>
|
||||||
|
</FooterDropDownSection>
|
||||||
|
</FooterSection>
|
||||||
|
<FooterSection type="bottom" logo="Unleash">
|
||||||
<FooterLinkList>
|
<FooterLinkList>
|
||||||
{createListItem('/features', 'Feature Toggles')}
|
<a href="https://github.com/Unleash/unleash/" target="_blank">
|
||||||
{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>
|
|
||||||
</FooterLinkList>
|
|
||||||
</FooterDropDownSection>
|
|
||||||
</FooterSection>
|
|
||||||
<FooterSection type="bottom" logo="Unleash">
|
|
||||||
<FooterLinkList>
|
|
||||||
<a href="https://github.com/Unleash/unleash/" target="_blank">
|
|
||||||
GitHub
|
GitHub
|
||||||
</a>
|
</a>
|
||||||
<a href="https://finn.no" target="_blank"><small>A product by</small> FINN.no</a>
|
<a href="https://finn.no" target="_blank"><small>A product by</small> FINN.no</a>
|
||||||
</FooterLinkList>
|
</FooterLinkList>
|
||||||
</FooterSection>
|
</FooterSection>
|
||||||
</Footer>
|
</Footer>
|
||||||
</Content>
|
</Content>
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
</Layout>
|
</Layout>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,25 +69,25 @@ class ClientApplications extends PureComponent {
|
|||||||
<h6> Toggles</h6>
|
<h6> Toggles</h6>
|
||||||
<hr />
|
<hr />
|
||||||
<List>
|
<List>
|
||||||
{seenToggles.map(({ name, description, enabled, notFound }, i) =>
|
{seenToggles.map(({ name, description, enabled, notFound }, i) =>
|
||||||
(notFound ?
|
(notFound ?
|
||||||
<ListItem twoLine key={i}>
|
<ListItem twoLine key={i}>
|
||||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||||
<Link to={`/features/create?name=${name}`}>
|
<Link to={`/features/create?name=${name}`}>
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem> :
|
</ListItem> :
|
||||||
<ListItem twoLine key={i}>
|
<ListItem twoLine key={i}>
|
||||||
<ListItemContent
|
<ListItemContent
|
||||||
icon={<span><Switch disabled checked={!!enabled} /></span>}
|
icon={<span><Switch disabled checked={!!enabled} /></span>}
|
||||||
subtitle={shorten(description, 60)}>
|
subtitle={shorten(description, 60)}>
|
||||||
<Link to={`/features/view/${name}`}>
|
<Link to={`/features/view/${name}`}>
|
||||||
{shorten(name, 50)}
|
{shorten(name, 50)}
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>)
|
</ListItem>)
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell col={6} tablet={4} phone={12}>
|
<Cell col={6} tablet={4} phone={12}>
|
||||||
@ -96,20 +96,20 @@ class ClientApplications extends PureComponent {
|
|||||||
<List>
|
<List>
|
||||||
{strategies.map(({ name, description, notFound }, i) => (
|
{strategies.map(({ name, description, notFound }, i) => (
|
||||||
notFound ?
|
notFound ?
|
||||||
<ListItem twoLine key={`${name}-${i}`}>
|
<ListItem twoLine key={`${name}-${i}`}>
|
||||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||||
<Link to={`/strategies/create?name=${name}`}>
|
<Link to={`/strategies/create?name=${name}`}>
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem> :
|
</ListItem> :
|
||||||
<ListItem twoLine key={`${name}-${i}`}>
|
<ListItem twoLine key={`${name}-${i}`}>
|
||||||
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
|
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
|
||||||
<Link to={`/strategies/view/${name}`}>
|
<Link to={`/strategies/view/${name}`}>
|
||||||
{shorten(name, 50)}
|
{shorten(name, 50)}
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Cell>
|
</Cell>
|
||||||
@ -117,17 +117,17 @@ class ClientApplications extends PureComponent {
|
|||||||
<h6>{instances.length} Instances registered</h6>
|
<h6>{instances.length} Instances registered</h6>
|
||||||
<hr />
|
<hr />
|
||||||
<List>
|
<List>
|
||||||
{instances.map(({ instanceId, clientIp, lastSeen, sdkVersion }, i) => (
|
{instances.map(({ instanceId, clientIp, lastSeen, sdkVersion }, i) => (
|
||||||
<ListItem key={i} twoLine>
|
<ListItem key={i} twoLine>
|
||||||
<ListItemContent
|
<ListItemContent
|
||||||
icon="timeline"
|
icon="timeline"
|
||||||
subtitle={
|
subtitle={
|
||||||
<span>{clientIp} last seen at <small>{formatFullDateTime(lastSeen)}</small></span>
|
<span>{clientIp} last seen at <small>{formatFullDateTime(lastSeen)}</small></span>
|
||||||
}>
|
}>
|
||||||
{instanceId} {sdkVersion ? `(${sdkVersion})` : ''}
|
{instanceId} {sdkVersion ? `(${sdkVersion})` : ''}
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Grid>) : (
|
</Grid>) : (
|
||||||
|
@ -3,7 +3,6 @@ import { ProgressBar, Card } from 'react-mdl';
|
|||||||
import { AppsLinkList, styles as commonStyles } from '../common';
|
import { AppsLinkList, styles as commonStyles } from '../common';
|
||||||
|
|
||||||
class ClientStrategies extends Component {
|
class ClientStrategies extends Component {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.props.fetchAll();
|
this.props.fetchAll();
|
||||||
}
|
}
|
||||||
|
@ -17,24 +17,24 @@ class ArchiveList extends Component {
|
|||||||
<Card shadow={0} className={commonStyles.fullwidth}>
|
<Card shadow={0} className={commonStyles.fullwidth}>
|
||||||
{
|
{
|
||||||
archive.length > 0 ?
|
archive.length > 0 ?
|
||||||
<div className={commonStyles.horisontalScroll}>
|
<div className={commonStyles.horisontalScroll}>
|
||||||
<DataTable
|
<DataTable
|
||||||
rows={archive}
|
rows={archive}
|
||||||
className={commonStyles.fullwidth}
|
className={commonStyles.fullwidth}
|
||||||
style={{ border: 0 }}>
|
style={{ border: 0 }}>
|
||||||
<TableHeader style={{ width: '25px' }} name="reviveName" cellFormatter={(reviveName) => (
|
<TableHeader style={{ width: '25px' }} name="reviveName" cellFormatter={(reviveName) => (
|
||||||
<IconButton colored name="undo" onClick={() => revive(reviveName)} />
|
<IconButton colored name="undo" onClick={() => revive(reviveName)} />
|
||||||
)}>Revive</TableHeader>
|
)}>Revive</TableHeader>
|
||||||
<TableHeader style={{ width: '25px' }} name="enabled" cellFormatter={(v) => (v ? 'Yes' : '-')}>
|
<TableHeader style={{ width: '25px' }} name="enabled" cellFormatter={(v) => (v ? 'Yes' : '-')}>
|
||||||
Enabled</TableHeader>
|
Enabled</TableHeader>
|
||||||
<TableHeader name="name">Toggle name</TableHeader>
|
<TableHeader name="name">Toggle name</TableHeader>
|
||||||
<TableHeader numeric name="createdAt">Created</TableHeader>
|
<TableHeader numeric name="createdAt">Created</TableHeader>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
</div> :
|
</div> :
|
||||||
<div className={commonStyles.emptyState}>
|
<div className={commonStyles.emptyState}>
|
||||||
<Icon name="archive" className="mdl-color-text--grey-300" style={{ fontSize: '56px' }}/><br />
|
<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>
|
</div>
|
||||||
}
|
}
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { DataTable, TableHeader } from 'react-mdl';
|
import { DataTable, TableHeader } from 'react-mdl';
|
||||||
|
|
||||||
class ClientStrategies extends Component {
|
class ClientStrategies extends Component {
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
|
@ -15,28 +15,28 @@ export const shorten = (str, len = 50) => (str && str.length > len ? `${str.subs
|
|||||||
|
|
||||||
export const AppsLinkList = ({ apps }) => (
|
export const AppsLinkList = ({ apps }) => (
|
||||||
<List>
|
<List>
|
||||||
{apps.length > 0 && apps.map(({ appName, description = '-', icon = 'apps' }) => (
|
{apps.length > 0 && apps.map(({ appName, description = '-', icon = 'apps' }) => (
|
||||||
<ListItem twoLine key={appName}>
|
<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"/>
|
<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}
|
{appName}
|
||||||
<span className={['mdl-list__item-sub-title', styles.truncate].join(' ')}>{description}</span>
|
<span className={['mdl-list__item-sub-title', styles.truncate].join(' ')}>{description}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const HeaderTitle = ({ title, actions, subtitle }) => (
|
export const HeaderTitle = ({ title, actions, subtitle }) => (
|
||||||
<div style={{ display: 'flex', borderBottom: '1px solid #f1f1f1', marginBottom: '10px', padding: '16px 20px ' }}>
|
<div style={{ display: 'flex', borderBottom: '1px solid #f1f1f1', marginBottom: '10px', padding: '16px 20px ' }}>
|
||||||
<div style={{ flex: '2' }}>
|
<div style={{ flex: '2' }}>
|
||||||
<h6 style={{ margin: 0 }}>{title}</h6>
|
<h6 style={{ margin: 0 }}>{title}</h6>
|
||||||
{subtitle && <small>{subtitle}</small>}
|
{subtitle && <small>{subtitle}</small>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{actions && <div style={{ flex: '1', textAlign: 'right' }}>{actions}</div>}
|
{actions && <div style={{ flex: '1', textAlign: 'right' }}>{actions}</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ export const SwitchWithLabel = ({ onChange, checked, children, ...switchProps })
|
|||||||
|
|
||||||
export const TogglesLinkList = ({ toggles }) => (
|
export const TogglesLinkList = ({ toggles }) => (
|
||||||
<List style={{ textAlign: 'left' }} className={styles.truncate}>
|
<List style={{ textAlign: 'left' }} className={styles.truncate}>
|
||||||
{toggles.length > 0 && toggles.map(({ name, description = '-', icon = 'toggle' }) => (
|
{toggles.length > 0 && toggles.map(({ name, description = '-', icon = 'toggle' }) => (
|
||||||
<ListItem twoLine key={name}>
|
<ListItem twoLine key={name}>
|
||||||
<ListItemContent avatar={icon} subtitle={description}>
|
<ListItemContent avatar={icon} subtitle={description}>
|
||||||
<Link key={name} to={`/features/view/${name}`}>
|
<Link key={name} to={`/features/view/${name}`}>
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ export function getIcon (type) {
|
|||||||
|
|
||||||
export const IconLink = ({ url, icon }) => (
|
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}/>
|
<Icon name={icon}/>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
import { Snackbar, Icon } from 'react-mdl';
|
import { Snackbar, Icon } from 'react-mdl';
|
||||||
|
|
||||||
class ErrorComponent extends React.Component {
|
class ErrorComponent extends React.Component {
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
|
@ -7,7 +7,7 @@ const mapDispatchToProps = {
|
|||||||
muteError,
|
muteError,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
errors: state.error.get('list').toArray(),
|
errors: state.error.get('list').toArray(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ const Feature = ({
|
|||||||
const remainingStrategies = strategies.length - strategiesToShow;
|
const remainingStrategies = strategies.length - strategiesToShow;
|
||||||
|
|
||||||
const strategyChips = strategies && strategies.slice(0, strategiesToShow).map((s, i) =>
|
const strategyChips = strategies && strategies.slice(0, strategiesToShow).map((s, i) =>
|
||||||
<Chip className={styles.strategyChip} key={i}>{s.name}</Chip>);
|
<Chip className={styles.strategyChip} key={i}>{s.name}</Chip>);
|
||||||
const summaryChip = remainingStrategies > 0 &&
|
const summaryChip = remainingStrategies > 0 &&
|
||||||
<Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
|
<Chip className={styles.strategyChip}>+{remainingStrategies}</Chip>;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ const prepare = (methods, dispatch) => {
|
|||||||
|
|
||||||
methods.validateName = (featureToggleName) => {
|
methods.validateName = (featureToggleName) => {
|
||||||
validateName(featureToggleName)
|
validateName(featureToggleName)
|
||||||
.then(() => methods.setValue('nameError', undefined))
|
.then(() => methods.setValue('nameError', undefined))
|
||||||
.catch((err) => methods.setValue('nameError', err.message));
|
.catch((err) => methods.setValue('nameError', err.message));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ const mapStateToProps = createMapper({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const prepare = (methods, dispatch) => {
|
const prepare = (methods, dispatch) => {
|
||||||
methods.onSubmit = (input) => (
|
methods.onSubmit = (input) => (
|
||||||
(e) => {
|
(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -35,7 +35,7 @@ const prepare = (methods, dispatch) => {
|
|||||||
delete s.id;
|
delete s.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// TODO: should add error handling
|
// TODO: should add error handling
|
||||||
requestUpdateFeatureToggle(input)(dispatch)
|
requestUpdateFeatureToggle(input)(dispatch)
|
||||||
.then(() => methods.clear())
|
.then(() => methods.clear())
|
||||||
.then(() => hashHistory.push(`/features/view/${input.name}`));
|
.then(() => hashHistory.push(`/features/view/${input.name}`));
|
||||||
|
@ -13,7 +13,6 @@ const trim = (value) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class AddFeatureToggleComponent extends Component {
|
class AddFeatureToggleComponent extends Component {
|
||||||
|
|
||||||
componentWillMount () {
|
componentWillMount () {
|
||||||
// TODO unwind this stuff
|
// TODO unwind this stuff
|
||||||
if (this.props.initCallRequired === true) {
|
if (this.props.initCallRequired === true) {
|
||||||
@ -69,10 +68,10 @@ class AddFeatureToggleComponent extends Component {
|
|||||||
{!editmode && <div>
|
{!editmode && <div>
|
||||||
<br />
|
<br />
|
||||||
<Switch
|
<Switch
|
||||||
checked={enabled}
|
checked={enabled}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setValue('enabled', !enabled);
|
setValue('enabled', !enabled);
|
||||||
}}>Enabled</Switch>
|
}}>Enabled</Switch>
|
||||||
<hr />
|
<hr />
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
@ -92,7 +91,6 @@ class AddFeatureToggleComponent extends Component {
|
|||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AddFeatureToggleComponent.propTypes = {
|
AddFeatureToggleComponent.propTypes = {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { Menu, MenuItem, IconButton } from 'react-mdl';
|
import { Menu, MenuItem, IconButton } from 'react-mdl';
|
||||||
|
|
||||||
class AddStrategy extends React.Component {
|
class AddStrategy extends React.Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
strategies: PropTypes.array.isRequired,
|
strategies: PropTypes.array.isRequired,
|
||||||
|
@ -5,7 +5,6 @@ import HTML5Backend from 'react-dnd-html5-backend';
|
|||||||
|
|
||||||
@DragDropContext(HTML5Backend) // eslint-disable-line new-cap
|
@DragDropContext(HTML5Backend) // eslint-disable-line new-cap
|
||||||
class StrategiesList extends React.Component {
|
class StrategiesList extends React.Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
strategies: PropTypes.array.isRequired,
|
strategies: PropTypes.array.isRequired,
|
||||||
|
@ -5,7 +5,6 @@ import AddStrategy from './strategies-add';
|
|||||||
import { HeaderTitle } from '../../common';
|
import { HeaderTitle } from '../../common';
|
||||||
|
|
||||||
class StrategiesSection extends React.Component {
|
class StrategiesSection extends React.Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
strategies: PropTypes.array.isRequired,
|
strategies: PropTypes.array.isRequired,
|
||||||
|
@ -45,7 +45,6 @@ const dragTarget = {
|
|||||||
isDragging: monitor.isDragging(),
|
isDragging: monitor.isDragging(),
|
||||||
}))
|
}))
|
||||||
class StrategyConfigure extends React.Component {
|
class StrategyConfigure extends React.Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
strategy: PropTypes.object.isRequired,
|
strategy: PropTypes.object.isRequired,
|
||||||
@ -122,7 +121,7 @@ class StrategyConfigure extends React.Component {
|
|||||||
label={name}
|
label={name}
|
||||||
onChange={this.handleConfigChange.bind(this, name)}
|
onChange={this.handleConfigChange.bind(this, name)}
|
||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
{description && <p className={styles.helpText}>{description}</p>}
|
{description && <p className={styles.helpText}>{description}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -138,7 +137,7 @@ class StrategyConfigure extends React.Component {
|
|||||||
label={name}
|
label={name}
|
||||||
onChange={this.handleConfigChange.bind(this, name)}
|
onChange={this.handleConfigChange.bind(this, name)}
|
||||||
value={value}
|
value={value}
|
||||||
/>
|
/>
|
||||||
{description && <p className={styles.helpText}>{description}</p>}
|
{description && <p className={styles.helpText}>{description}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -165,8 +164,8 @@ class StrategyConfigure extends React.Component {
|
|||||||
</CardText>
|
</CardText>
|
||||||
{
|
{
|
||||||
inputFields && <CardActions border style={{ padding: '20px' }}>
|
inputFields && <CardActions border style={{ padding: '20px' }}>
|
||||||
{inputFields}
|
{inputFields}
|
||||||
</CardActions>
|
</CardActions>
|
||||||
}
|
}
|
||||||
|
|
||||||
<CardMenu className="mdl-color-text--white">
|
<CardMenu className="mdl-color-text--white">
|
||||||
|
@ -3,10 +3,9 @@ import {
|
|||||||
Textfield,
|
Textfield,
|
||||||
IconButton,
|
IconButton,
|
||||||
Chip,
|
Chip,
|
||||||
} from 'react-mdl';
|
} from 'react-mdl';
|
||||||
|
|
||||||
export default class InputList extends Component {
|
export default class InputList extends Component {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
list: PropTypes.array.isRequired,
|
list: PropTypes.array.isRequired,
|
||||||
@ -18,7 +17,7 @@ export default class InputList extends Component {
|
|||||||
window.removeEventListener('keydown', this.onKeyHandler, false);
|
window.removeEventListener('keydown', this.onKeyHandler, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocus = (e) => {
|
onFocus = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
window.addEventListener('keydown', this.onKeyHandler, false);
|
window.addEventListener('keydown', this.onKeyHandler, false);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Slider } from 'react-mdl';
|
import { Slider } from 'react-mdl';
|
||||||
|
|
||||||
const labelStyle = {
|
const labelStyle = {
|
||||||
margin: '20px 0',
|
margin: '20px 0',
|
||||||
|
@ -7,7 +7,6 @@ import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../com
|
|||||||
import styles from './feature.scss';
|
import styles from './feature.scss';
|
||||||
|
|
||||||
export default class FeatureListComponent extends React.PureComponent {
|
export default class FeatureListComponent extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
toggleFeature: PropTypes.func.isRequired,
|
toggleFeature: PropTypes.func.isRequired,
|
||||||
@ -89,16 +88,16 @@ export default class FeatureListComponent extends React.PureComponent {
|
|||||||
<hr/>
|
<hr/>
|
||||||
<List>
|
<List>
|
||||||
{features.map((feature, i) =>
|
{features.map((feature, i) =>
|
||||||
<Feature key={i}
|
(<Feature key={i}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
metricsLastHour={featureMetrics.lastHour[feature.name]}
|
metricsLastHour={featureMetrics.lastHour[feature.name]}
|
||||||
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
|
metricsLastMinute={featureMetrics.lastMinute[feature.name]}
|
||||||
feature={feature}
|
feature={feature}
|
||||||
toggleFeature={toggleFeature}/>
|
toggleFeature={toggleFeature}/>)
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ const mapStateToProps = (state) => {
|
|||||||
const regex = new RegExp(settings.filter, 'i');
|
const regex = new RegExp(settings.filter, 'i');
|
||||||
features = features.filter(feature =>
|
features = features.filter(feature =>
|
||||||
(
|
(
|
||||||
regex.test(feature.name) ||
|
regex.test(feature.name) ||
|
||||||
regex.test(feature.description) ||
|
regex.test(feature.description) ||
|
||||||
feature.strategies.some(s => s && s.name && regex.test(s.name))
|
feature.strategies.some(s => s && s.name && regex.test(s.name))
|
||||||
)
|
)
|
||||||
@ -72,8 +72,8 @@ const mapDispatchToProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const FeatureListContainer = connect(
|
const FeatureListContainer = connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(FeatureListComponent);
|
)(FeatureListComponent);
|
||||||
|
|
||||||
export default FeatureListContainer;
|
export default FeatureListContainer;
|
||||||
|
@ -18,7 +18,7 @@ const StrategyChipItem = ({ strategy }) => (
|
|||||||
// TODO what about "missing" strategies here?
|
// TODO what about "missing" strategies here?
|
||||||
const StrategiesList = ({ strategies }) => (
|
const StrategiesList = ({ strategies }) => (
|
||||||
<div style={{ verticalAlign: 'middle', paddingTop: '14px' }}>With {strategies.length > 1 ? 'strategies' : 'strategy'} {
|
<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>
|
}</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class Progress extends Component {
|
|||||||
|
|
||||||
const current = this.state.percentageText;
|
const current = this.state.percentageText;
|
||||||
|
|
||||||
targetState.cyclesCounter --;
|
targetState.cyclesCounter--;
|
||||||
if (targetState.cyclesCounter <= 0) {
|
if (targetState.cyclesCounter <= 0) {
|
||||||
this.setState({ percentageText: targetState.target });
|
this.setState({ percentageText: targetState.target });
|
||||||
return;
|
return;
|
||||||
@ -99,7 +99,7 @@ class Progress extends Component {
|
|||||||
return (isFallback ?
|
return (isFallback ?
|
||||||
<svg viewBox="0 0 24 24" className="mdl-color-text--grey-300">{
|
<svg viewBox="0 0 24 24" className="mdl-color-text--grey-300">{
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
}<path fill="currentColor" d="M17.3,18C19,16.5 20,14.4 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12C4,14.4 5,16.5 6.7,18C8.2,16.7 10,16 12,16C14,16 15.9,16.7 17.3,18M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,9A1,1 0 0,1 8,10A1,1 0 0,1 7,11A1,1 0 0,1 6,10A1,1 0 0,1 7,9M10,6A1,1 0 0,1 11,7A1,1 0 0,1 10,8A1,1 0 0,1 9,7A1,1 0 0,1 10,6M17,9A1,1 0 0,1 18,10A1,1 0 0,1 17,11A1,1 0 0,1 16,10A1,1 0 0,1 17,9M14.4,6.1C14.9,6.3 15.1,6.9 15,7.4L13.6,10.8C13.8,11.1 14,11.5 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12C10,11 10.7,10.1 11.7,10L13.1,6.7C13.3,6.1 13.9,5.9 14.4,6.1Z" />
|
}<path fill="currentColor" d="M17.3,18C19,16.5 20,14.4 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12C4,14.4 5,16.5 6.7,18C8.2,16.7 10,16 12,16C14,16 15.9,16.7 17.3,18M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M7,9A1,1 0 0,1 8,10A1,1 0 0,1 7,11A1,1 0 0,1 6,10A1,1 0 0,1 7,9M10,6A1,1 0 0,1 11,7A1,1 0 0,1 10,8A1,1 0 0,1 9,7A1,1 0 0,1 10,6M17,9A1,1 0 0,1 18,10A1,1 0 0,1 17,11A1,1 0 0,1 16,10A1,1 0 0,1 17,9M14.4,6.1C14.9,6.3 15.1,6.9 15,7.4L13.6,10.8C13.8,11.1 14,11.5 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12C10,11 10.7,10.1 11.7,10L13.1,6.7C13.3,6.1 13.9,5.9 14.4,6.1Z" />
|
||||||
</svg> :
|
</svg> :
|
||||||
<svg viewBox="0 0 100 100">
|
<svg viewBox="0 0 100 100">
|
||||||
<path
|
<path
|
||||||
@ -107,7 +107,7 @@ class Progress extends Component {
|
|||||||
d={pathDescription}
|
d={pathDescription}
|
||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
fillOpacity={0}
|
fillOpacity={0}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<path
|
<path
|
||||||
className={[styles.path, colorClassName].join(' ')}
|
className={[styles.path, colorClassName].join(' ')}
|
||||||
@ -115,13 +115,13 @@ class Progress extends Component {
|
|||||||
strokeWidth={strokeWidth}
|
strokeWidth={strokeWidth}
|
||||||
fillOpacity={0}
|
fillOpacity={0}
|
||||||
style={progressStyle}
|
style={progressStyle}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<text
|
<text
|
||||||
className={styles.text}
|
className={styles.text}
|
||||||
x={50}
|
x={50}
|
||||||
y={50}
|
y={50}
|
||||||
>{this.state.percentageText}%</text>
|
>{this.state.percentageText}%</text>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ const TABS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default class ViewFeatureToggleComponent extends React.Component {
|
export default class ViewFeatureToggleComponent extends React.Component {
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
@ -73,7 +72,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
Could not find the toggle <Link to={{ pathname: '/features/create', query: { name: featureToggleName } }}>
|
Could not find the toggle <Link to={{ pathname: '/features/create', query: { name: featureToggleName } }}>
|
||||||
{featureToggleName}</Link>
|
{featureToggleName}</Link>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -82,7 +81,7 @@ export default class ViewFeatureToggleComponent extends React.Component {
|
|||||||
const tabContent = this.getTabContent(activeTab);
|
const tabContent = this.getTabContent(activeTab);
|
||||||
|
|
||||||
const removeToggle = () => {
|
const removeToggle = () => {
|
||||||
if (window.confirm('Are you sure you want to remove this toggle?')) { // eslint-disable-line no-alert
|
if (window.confirm('Are you sure you want to remove this toggle?')) { // eslint-disable-line no-alert
|
||||||
removeFeatureToggle(featureToggle.name);
|
removeFeatureToggle(featureToggle.name);
|
||||||
hashHistory.push('/features');
|
hashHistory.push('/features');
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import HistoryList from './history-list-container';
|
|||||||
import { styles as commonStyles } from '../common';
|
import { styles as commonStyles } from '../common';
|
||||||
|
|
||||||
class History extends PureComponent {
|
class History extends PureComponent {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.props.fetchHistory();
|
this.props.fetchHistory();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ function buildDiff (diff, idx) {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const spadenClass = KLASSES[diff.kind];
|
const spadenClass = KLASSES[diff.kind];
|
||||||
const prefix = DIFF_PREFIXES[diff.kind];
|
const prefix = DIFF_PREFIXES[diff.kind];
|
||||||
|
|
||||||
change = (<div className={spadenClass}>{prefix} {key}: {JSON.stringify(diff.rhs || diff.item)}</div>);
|
change = (<div className={spadenClass}>{prefix} {key}: {JSON.stringify(diff.rhs || diff.item)}</div>);
|
||||||
}
|
}
|
||||||
@ -59,7 +59,6 @@ function buildDiff (diff, idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class HistoryItem extends PureComponent {
|
class HistoryItem extends PureComponent {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
entry: PropTypes.object,
|
entry: PropTypes.object,
|
||||||
|
@ -3,7 +3,6 @@ import React, { PropTypes, PureComponent } from 'react';
|
|||||||
import style from './history.scss';
|
import style from './history.scss';
|
||||||
|
|
||||||
class HistoryItem extends PureComponent {
|
class HistoryItem extends PureComponent {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
entry: PropTypes.object,
|
entry: PropTypes.object,
|
||||||
|
@ -8,7 +8,6 @@ import { formatFullDateTime } from '../common/util';
|
|||||||
import styles from './history.scss';
|
import styles from './history.scss';
|
||||||
|
|
||||||
class HistoryList extends Component {
|
class HistoryList extends Component {
|
||||||
|
|
||||||
toggleShowDiff () {
|
toggleShowDiff () {
|
||||||
this.props.updateSetting('showData', !this.props.settings.showData);
|
this.props.updateSetting('showData', !this.props.settings.showData);
|
||||||
}
|
}
|
||||||
@ -27,18 +26,18 @@ class HistoryList extends Component {
|
|||||||
let entries;
|
let entries;
|
||||||
|
|
||||||
if (showData) {
|
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 {
|
} else {
|
||||||
entries = (<Table
|
entries = (<Table
|
||||||
sortable
|
sortable
|
||||||
rows={
|
rows={
|
||||||
history.map((entry) => Object.assign({
|
history.map((entry) => Object.assign({
|
||||||
diff: (<HistoryItemDiff entry={entry} />),
|
diff: (<HistoryItemDiff entry={entry} />),
|
||||||
}, entry))
|
}, entry))
|
||||||
}
|
}
|
||||||
className={commonStyles.fullwidth}
|
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' }}>Type</TableHeader>
|
<TableHeader name="type" cellFormatter={truncateTableCell} style={{ width: '136px' }}>Type</TableHeader>
|
||||||
<TableHeader name="createdBy" cellFormatter={truncateTableCell} style={{ width: '115px' }}>User</TableHeader>
|
<TableHeader name="createdBy" cellFormatter={truncateTableCell} style={{ width: '115px' }}>User</TableHeader>
|
||||||
<TableHeader name="diff">Diff</TableHeader>
|
<TableHeader name="diff">Diff</TableHeader>
|
||||||
|
@ -2,7 +2,6 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
import HistoryList from './history-list-container';
|
import HistoryList from './history-list-container';
|
||||||
|
|
||||||
class HistoryListToggle extends Component {
|
class HistoryListToggle extends Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
toggleName: PropTypes.string.isRequired,
|
toggleName: PropTypes.string.isRequired,
|
||||||
@ -19,9 +18,9 @@ class HistoryListToggle extends Component {
|
|||||||
}
|
}
|
||||||
const { history } = this.props;
|
const { history } = this.props;
|
||||||
return (
|
return (
|
||||||
<HistoryList
|
<HistoryList
|
||||||
history={history}
|
history={history}
|
||||||
title="Change log"/>
|
title="Change log"/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ function gerArrayWithEntries (num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Parameter = ({ set, input = {}, index }) => (
|
const Parameter = ({ set, input = {}, index }) => (
|
||||||
<div style={{ background: '#f1f1f1', padding: '16px 20px', marginBottom: '20px' }}>
|
<div style={{ background: '#f1f1f1', padding: '16px 20px', marginBottom: '20px' }}>
|
||||||
<Textfield
|
<Textfield
|
||||||
style={{ width: '50%' }}
|
style={{ width: '50%' }}
|
||||||
floatingLabel
|
floatingLabel
|
||||||
@ -65,7 +65,7 @@ const Parameter = ({ set, input = {}, index }) => (
|
|||||||
const EditHeader = () => (
|
const EditHeader = () => (
|
||||||
<div>
|
<div>
|
||||||
<h4 style={{ marginTop: '16px' }}>Edit strategy</h4>
|
<h4 style={{ marginTop: '16px' }}>Edit strategy</h4>
|
||||||
<p style={{ background: '#ffb7b7', padding: '16px 20px' }}>
|
<p style={{ background: '#ffb7b7', padding: '16px 20px' }}>
|
||||||
Be carefull! Changing a strategy definition might also require changes to the
|
Be carefull! Changing a strategy definition might also require changes to the
|
||||||
implementation in the clients.
|
implementation in the clients.
|
||||||
</p>
|
</p>
|
||||||
@ -80,18 +80,17 @@ const CreateHeader = () => (
|
|||||||
|
|
||||||
|
|
||||||
const Parameters = ({ input = [], count = 0, updateInList }) => (
|
const Parameters = ({ input = [], count = 0, updateInList }) => (
|
||||||
<div>{
|
<div>{
|
||||||
gerArrayWithEntries(count)
|
gerArrayWithEntries(count)
|
||||||
.map((v, i) => <Parameter
|
.map((v, i) => (<Parameter
|
||||||
key={i}
|
key={i}
|
||||||
set={(v) => updateInList('parameters', i, v, true)}
|
set={(v) => updateInList('parameters', i, v, true)}
|
||||||
index={i}
|
index={i}
|
||||||
input={input[i]}
|
input={input[i]}
|
||||||
/>)
|
/>))
|
||||||
}</div>);
|
}</div>);
|
||||||
|
|
||||||
class AddStrategy extends Component {
|
class AddStrategy extends Component {
|
||||||
|
|
||||||
static propTypes () {
|
static propTypes () {
|
||||||
return {
|
return {
|
||||||
input: PropTypes.object,
|
input: PropTypes.object,
|
||||||
@ -142,7 +141,7 @@ class AddStrategy extends Component {
|
|||||||
pattern="^[0-9a-zA-Z\.\-]+$"
|
pattern="^[0-9a-zA-Z\.\-]+$"
|
||||||
onChange={({ target }) => setValue('name', trim(target.value))}
|
onChange={({ target }) => setValue('name', trim(target.value))}
|
||||||
value={input.name}
|
value={input.name}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Textfield
|
<Textfield
|
||||||
floatingLabel
|
floatingLabel
|
||||||
@ -152,7 +151,7 @@ class AddStrategy extends Component {
|
|||||||
name="description"
|
name="description"
|
||||||
onChange={({ target }) => setValue('description', target.value)}
|
onChange={({ target }) => setValue('description', target.value)}
|
||||||
value={input.description}
|
value={input.description}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
|
<Parameters input={input.parameters} count={input._params} updateInList={updateInList} />
|
||||||
|
@ -5,7 +5,6 @@ import { List, ListItem, ListItemContent, IconButton, Grid, Cell } from 'react-m
|
|||||||
import { HeaderTitle } from '../common';
|
import { HeaderTitle } from '../common';
|
||||||
|
|
||||||
class StrategiesListComponent extends Component {
|
class StrategiesListComponent extends Component {
|
||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
router: React.PropTypes.object,
|
router: React.PropTypes.object,
|
||||||
}
|
}
|
||||||
@ -28,15 +27,19 @@ class StrategiesListComponent extends Component {
|
|||||||
title="Add new strategy" />} />
|
title="Add new strategy" />} />
|
||||||
<List>
|
<List>
|
||||||
{strategies.length > 0 ? strategies.map((strategy, i) => (
|
{strategies.length > 0 ? strategies.map((strategy, i) => (
|
||||||
<ListItem key={i} twoLine>
|
<ListItem key={i} twoLine>
|
||||||
<ListItemContent icon="extension" subtitle={strategy.description}>
|
<ListItemContent icon="extension" subtitle={strategy.description}>
|
||||||
<Link to={`/strategies/view/${strategy.name}`}>
|
<Link to={`/strategies/view/${strategy.name}`}>
|
||||||
<strong>{strategy.name}</strong>
|
<strong>{strategy.name}</strong>
|
||||||
</Link>
|
</Link>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
<IconButton name="delete" onClick={() => removeStrategy(strategy)} />
|
{
|
||||||
</ListItem>
|
strategy.editable === false ?
|
||||||
)) : <ListItem>No entries</ListItem>}
|
'' :
|
||||||
|
<IconButton name="delete" onClick={() => removeStrategy(strategy)} />
|
||||||
|
}
|
||||||
|
</ListItem>
|
||||||
|
)) : <ListItem>No entries</ListItem>}
|
||||||
</List>
|
</List>
|
||||||
</Cell>
|
</Cell>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -12,7 +12,7 @@ const mapStateToProps = (state) => {
|
|||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
removeStrategy: (strategy) => {
|
removeStrategy: (strategy) => {
|
||||||
if (window.confirm('Are you sure you want to remove this strategy?')) { // eslint-disable-line no-alert
|
if (window.confirm('Are you sure you want to remove this strategy?')) { // eslint-disable-line no-alert
|
||||||
removeStrategy(strategy)(dispatch);
|
removeStrategy(strategy)(dispatch);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -60,21 +60,24 @@ export default class StrategyDetails extends Component {
|
|||||||
|
|
||||||
const tabContent = this.getTabContent(activeTabId);
|
const tabContent = this.getTabContent(activeTabId);
|
||||||
|
|
||||||
return (
|
return (<Grid className="mdl-color--white">
|
||||||
<Grid className="mdl-color--white">
|
<Cell col={12}>
|
||||||
<Cell col={12}>
|
<HeaderTitle title={strategy.name} subtitle={strategy.description} />
|
||||||
<HeaderTitle title={strategy.name} subtitle={strategy.description} />
|
{strategy.editable === false ? '' : <Tabs activeTab={activeTabId} ripple>
|
||||||
<Tabs activeTab={activeTabId} ripple>
|
<Tab onClick={() => this.goToTab('view')}>
|
||||||
<Tab onClick={() => this.goToTab('view')}>Details</Tab>
|
Details
|
||||||
<Tab onClick={() => this.goToTab('edit')}>Edit</Tab>
|
</Tab>
|
||||||
</Tabs>
|
<Tab onClick={() => this.goToTab('edit')}>
|
||||||
<section>
|
Edit
|
||||||
<div className="content">
|
</Tab>
|
||||||
{tabContent}
|
</Tabs>}
|
||||||
</div>
|
|
||||||
</section>
|
<section>
|
||||||
</Cell>
|
<div className="content">
|
||||||
</Grid>
|
{tabContent}
|
||||||
);
|
</div>
|
||||||
|
</section>
|
||||||
|
</Cell>
|
||||||
|
</Grid>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const mapDispatchToProps = {
|
|||||||
openEdit,
|
openEdit,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
user: state.user.toJS(),
|
user: state.user.toJS(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ const mapDispatchToProps = {
|
|||||||
save,
|
save,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
user: state.user.toJS(),
|
user: state.user.toJS(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ function toggle (name) {
|
|||||||
headers,
|
headers,
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
})
|
})
|
||||||
.then(throwIfNotSuccess);
|
.then(throwIfNotSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove (featureToggleName) {
|
function remove (featureToggleName) {
|
||||||
|
@ -61,7 +61,7 @@ ReactDOM.render(
|
|||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route pageTitle="Event History" link="/history">
|
<Route pageTitle="Event History" link="/history">
|
||||||
<Route pageTitle="Event history" path="/history" component={HistoryPage} />
|
<Route pageTitle="Event history" path="/history" component={HistoryPage} />
|
||||||
<Route pageTitle=":toggleName" path="/history/:toggleName" component={HistoryTogglePage} />
|
<Route pageTitle=":toggleName" path="/history/:toggleName" component={HistoryTogglePage} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import api from '../data/archive-api';
|
import api from '../data/archive-api';
|
||||||
|
|
||||||
export const REVIVE_TOGGLE = 'REVIVE_TOGGLE';
|
export const REVIVE_TOGGLE = 'REVIVE_TOGGLE';
|
||||||
export const RECEIVE_ARCHIVE = 'RECEIVE_ARCHIVE';
|
export const RECEIVE_ARCHIVE = 'RECEIVE_ARCHIVE';
|
||||||
export const ERROR_RECEIVE_ARCHIVE = 'ERROR_RECEIVE_ARCHIVE';
|
export const ERROR_RECEIVE_ARCHIVE = 'ERROR_RECEIVE_ARCHIVE';
|
||||||
|
|
||||||
const receiveArchive = (json) => ({
|
const receiveArchive = (json) => ({
|
||||||
type: RECEIVE_ARCHIVE,
|
type: RECEIVE_ARCHIVE,
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import api from '../data/feature-api';
|
import api from '../data/feature-api';
|
||||||
const debug = require('debug')('unleash:feature-actions');
|
const debug = require('debug')('unleash:feature-actions');
|
||||||
|
|
||||||
export const ADD_FEATURE_TOGGLE = 'ADD_FEATURE_TOGGLE';
|
export const ADD_FEATURE_TOGGLE = 'ADD_FEATURE_TOGGLE';
|
||||||
export const REMOVE_FEATURE_TOGGLE = 'REMOVE_FEATURE_TOGGLE';
|
export const REMOVE_FEATURE_TOGGLE = 'REMOVE_FEATURE_TOGGLE';
|
||||||
export const UPDATE_FEATURE_TOGGLE = 'UPDATE_FEATURE_TOGGLE';
|
export const UPDATE_FEATURE_TOGGLE = 'UPDATE_FEATURE_TOGGLE';
|
||||||
export const TOGGLE_FEATURE_TOGGLE = 'TOGGLE_FEATURE_TOGGLE';
|
export const TOGGLE_FEATURE_TOGGLE = 'TOGGLE_FEATURE_TOGGLE';
|
||||||
export const START_FETCH_FEATURE_TOGGLES = 'START_FETCH_FEATURE_TOGGLES';
|
export const START_FETCH_FEATURE_TOGGLES = 'START_FETCH_FEATURE_TOGGLES';
|
||||||
export const START_UPDATE_FEATURE_TOGGLE = 'START_UPDATE_FEATURE_TOGGLE';
|
export const START_UPDATE_FEATURE_TOGGLE = 'START_UPDATE_FEATURE_TOGGLE';
|
||||||
export const START_CREATE_FEATURE_TOGGLE = 'START_CREATE_FEATURE_TOGGLE';
|
export const START_CREATE_FEATURE_TOGGLE = 'START_CREATE_FEATURE_TOGGLE';
|
||||||
export const START_REMOVE_FEATURE_TOGGLE = 'START_REMOVE_FEATURE_TOGGLE';
|
export const START_REMOVE_FEATURE_TOGGLE = 'START_REMOVE_FEATURE_TOGGLE';
|
||||||
export const RECEIVE_FEATURE_TOGGLES = 'RECEIVE_FEATURE_TOGGLES';
|
export const RECEIVE_FEATURE_TOGGLES = 'RECEIVE_FEATURE_TOGGLES';
|
||||||
export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES';
|
export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES';
|
||||||
export const ERROR_CREATING_FEATURE_TOGGLE = 'ERROR_CREATING_FEATURE_TOGGLE';
|
export const ERROR_CREATING_FEATURE_TOGGLE = 'ERROR_CREATING_FEATURE_TOGGLE';
|
||||||
export const ERROR_UPDATE_FEATURE_TOGGLE = 'ERROR_UPDATE_FEATURE_TOGGLE';
|
export const ERROR_UPDATE_FEATURE_TOGGLE = 'ERROR_UPDATE_FEATURE_TOGGLE';
|
||||||
export const ERROR_REMOVE_FEATURE_TOGGLE = 'ERROR_REMOVE_FEATURE_TOGGLE';
|
export const ERROR_REMOVE_FEATURE_TOGGLE = 'ERROR_REMOVE_FEATURE_TOGGLE';
|
||||||
|
|
||||||
export function toggleFeature (name) {
|
export function toggleFeature (name) {
|
||||||
debug('Toggle feature toggle ', name);
|
debug('Toggle feature toggle ', name);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import api from '../data/feature-metrics-api';
|
import api from '../data/feature-metrics-api';
|
||||||
|
|
||||||
export const START_FETCH_FEATURE_METRICS = 'START_FETCH_FEATURE_METRICS';
|
export const START_FETCH_FEATURE_METRICS = 'START_FETCH_FEATURE_METRICS';
|
||||||
export const RECEIVE_FEATURE_METRICS = 'RECEIVE_FEATURE_METRICS';
|
export const RECEIVE_FEATURE_METRICS = 'RECEIVE_FEATURE_METRICS';
|
||||||
export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES';
|
export const ERROR_FETCH_FEATURE_TOGGLES = 'ERROR_FETCH_FEATURE_TOGGLES';
|
||||||
|
|
||||||
export const START_FETCH_SEEN_APP = 'START_FETCH_SEEN_APP';
|
export const START_FETCH_SEEN_APP = 'START_FETCH_SEEN_APP';
|
||||||
export const RECEIVE_SEEN_APPS = 'RECEIVE_SEEN_APPS';
|
export const RECEIVE_SEEN_APPS = 'RECEIVE_SEEN_APPS';
|
||||||
export const ERROR_FETCH_SEEN_APP = 'ERROR_FETCH_SEEN_APP';
|
export const ERROR_FETCH_SEEN_APP = 'ERROR_FETCH_SEEN_APP';
|
||||||
|
|
||||||
function receiveFeatureMetrics (json) {
|
function receiveFeatureMetrics (json) {
|
||||||
return {
|
return {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import api from '../data/history-api';
|
import api from '../data/history-api';
|
||||||
|
|
||||||
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
||||||
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
||||||
|
|
||||||
export const RECEIVE_HISTORY_FOR_TOGGLE = 'RECEIVE_HISTORY_FOR_TOGGLE';
|
export const RECEIVE_HISTORY_FOR_TOGGLE = 'RECEIVE_HISTORY_FOR_TOGGLE';
|
||||||
|
|
||||||
const receiveHistory = (json) => ({
|
const receiveHistory = (json) => ({
|
||||||
type: RECEIVE_HISTORY,
|
type: RECEIVE_HISTORY,
|
||||||
|
@ -31,7 +31,7 @@ function setKeyValue (state, { id, key, value }) {
|
|||||||
|
|
||||||
function increment (state, { id, key }) {
|
function increment (state, { id, key }) {
|
||||||
state = assertId(state, id);
|
state = assertId(state, id);
|
||||||
return state.updateIn(id.concat([key]), (value = 0) => value + 1);
|
return state.updateIn(id.concat([key]), (value = 0) => value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear (state, { id }) {
|
function clear (state, { id }) {
|
||||||
|
@ -78,8 +78,8 @@ export function updateStrategy (strategy) {
|
|||||||
|
|
||||||
export function removeStrategy (strategy) {
|
export function removeStrategy (strategy) {
|
||||||
return dispatch => api.remove(strategy)
|
return dispatch => api.remove(strategy)
|
||||||
.then(() => dispatch(createRemoveStrategy(strategy)))
|
.then(() => dispatch(createRemoveStrategy(strategy)))
|
||||||
.catch(error => dispatch(errorCreatingStrategy(error)));
|
.catch(error => dispatch(errorCreatingStrategy(error)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getApplicationsWithStrategy (strategyName) {
|
export function getApplicationsWithStrategy (strategyName) {
|
||||||
|
2776
frontend/yarn.lock
2776
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user