2016-12-09 14:02:36 +01:00
|
|
|
/* eslint react/no-multi-comp:off */
|
|
|
|
import React, { Component, PureComponent } from 'react';
|
2016-12-05 15:15:01 +01:00
|
|
|
|
|
|
|
import { Link } from 'react-router';
|
2016-12-13 20:54:53 +01:00
|
|
|
import {
|
2017-08-28 19:15:47 +02:00
|
|
|
Grid,
|
|
|
|
Cell,
|
|
|
|
Card,
|
|
|
|
CardTitle,
|
|
|
|
CardText,
|
|
|
|
CardMenu,
|
|
|
|
List,
|
|
|
|
ListItem,
|
|
|
|
ListItemContent,
|
|
|
|
Textfield,
|
|
|
|
Icon,
|
|
|
|
ProgressBar,
|
|
|
|
Tabs,
|
|
|
|
Tab,
|
2016-12-13 22:46:56 +01:00
|
|
|
Switch,
|
2016-12-13 20:54:53 +01:00
|
|
|
} from 'react-mdl';
|
2017-02-14 12:11:18 +01:00
|
|
|
import { IconLink, shorten, styles as commonStyles } from '../common';
|
2017-01-06 11:41:52 +01:00
|
|
|
import { formatFullDateTime } from '../common/util';
|
2016-12-05 15:15:01 +01:00
|
|
|
|
2016-12-09 14:02:36 +01:00
|
|
|
class StatefulTextfield extends Component {
|
2017-08-28 19:15:47 +02:00
|
|
|
constructor(props) {
|
2016-12-09 14:02:36 +01:00
|
|
|
super(props);
|
|
|
|
this.state = { value: props.value };
|
2017-08-28 19:15:47 +02:00
|
|
|
this.setValue = function setValue(e) {
|
2016-12-09 14:02:36 +01:00
|
|
|
this.setState({ value: e.target.value });
|
|
|
|
}.bind(this);
|
|
|
|
}
|
|
|
|
|
2017-08-28 19:15:47 +02:00
|
|
|
render() {
|
|
|
|
return (
|
|
|
|
<Textfield
|
|
|
|
style={{ width: '100%' }}
|
|
|
|
label={this.props.label}
|
|
|
|
floatingLabel
|
|
|
|
rows={this.props.rows}
|
|
|
|
value={this.state.value}
|
|
|
|
onChange={this.setValue}
|
|
|
|
onBlur={this.props.onBlur}
|
|
|
|
/>
|
2016-12-09 14:02:36 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 20:54:53 +01:00
|
|
|
class ClientApplications extends PureComponent {
|
2017-08-28 19:15:47 +02:00
|
|
|
constructor(props) {
|
2016-12-13 20:54:53 +01:00
|
|
|
super(props);
|
|
|
|
this.state = { activeTab: 0 };
|
|
|
|
}
|
|
|
|
|
2017-08-28 19:15:47 +02:00
|
|
|
componentDidMount() {
|
2016-12-05 15:15:01 +01:00
|
|
|
this.props.fetchApplication(this.props.appName);
|
|
|
|
}
|
|
|
|
|
2017-08-28 19:15:47 +02:00
|
|
|
render() {
|
2016-12-05 15:15:01 +01:00
|
|
|
if (!this.props.application) {
|
2016-12-10 14:19:52 +01:00
|
|
|
return <ProgressBar indeterminate />;
|
2016-12-05 15:15:01 +01:00
|
|
|
}
|
2017-08-28 19:15:47 +02:00
|
|
|
const { application, storeApplicationMetaData } = this.props;
|
2017-08-28 21:40:44 +02:00
|
|
|
const { appName, instances, strategies, seenToggles, url, description, icon = 'apps', color } = application;
|
2016-12-05 16:01:09 +01:00
|
|
|
|
2017-08-28 19:15:47 +02:00
|
|
|
const content =
|
|
|
|
this.state.activeTab === 0 ? (
|
|
|
|
<Grid style={{ margin: 0 }}>
|
|
|
|
<Cell col={6} tablet={4} phone={12}>
|
|
|
|
<h6> Toggles</h6>
|
|
|
|
<hr />
|
|
|
|
<List>
|
|
|
|
{seenToggles.map(
|
|
|
|
({ name, description, enabled, notFound }, i) =>
|
|
|
|
notFound ? (
|
|
|
|
<ListItem twoLine key={i}>
|
2017-08-28 21:40:44 +02:00
|
|
|
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
|
|
|
<Link to={`/features/create?name=${name}`}>{name}</Link>
|
2017-08-28 19:15:47 +02:00
|
|
|
</ListItemContent>
|
|
|
|
</ListItem>
|
|
|
|
) : (
|
|
|
|
<ListItem twoLine key={i}>
|
|
|
|
<ListItemContent
|
|
|
|
icon={
|
|
|
|
<span>
|
2017-08-28 21:40:44 +02:00
|
|
|
<Switch disabled checked={!!enabled} />
|
2017-08-28 19:15:47 +02:00
|
|
|
</span>
|
|
|
|
}
|
2017-08-28 21:40:44 +02:00
|
|
|
subtitle={shorten(description, 60)}
|
2017-08-28 19:15:47 +02:00
|
|
|
>
|
2017-08-28 21:40:44 +02:00
|
|
|
<Link to={`/features/view/${name}`}>{shorten(name, 50)}</Link>
|
2017-08-28 19:15:47 +02:00
|
|
|
</ListItemContent>
|
|
|
|
</ListItem>
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
</List>
|
|
|
|
</Cell>
|
|
|
|
<Cell col={6} tablet={4} phone={12}>
|
|
|
|
<h6>Implemented strategies</h6>
|
|
|
|
<hr />
|
|
|
|
<List>
|
|
|
|
{strategies.map(
|
|
|
|
({ name, description, notFound }, i) =>
|
|
|
|
notFound ? (
|
|
|
|
<ListItem twoLine key={`${name}-${i}`}>
|
2017-08-28 21:40:44 +02:00
|
|
|
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
|
|
|
<Link to={`/strategies/create?name=${name}`}>{name}</Link>
|
2017-08-28 19:15:47 +02:00
|
|
|
</ListItemContent>
|
|
|
|
</ListItem>
|
|
|
|
) : (
|
|
|
|
<ListItem twoLine key={`${name}-${i}`}>
|
2017-08-28 21:40:44 +02:00
|
|
|
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
|
|
|
|
<Link to={`/strategies/view/${name}`}>{shorten(name, 50)}</Link>
|
2017-08-28 19:15:47 +02:00
|
|
|
</ListItemContent>
|
|
|
|
</ListItem>
|
|
|
|
)
|
|
|
|
)}
|
|
|
|
</List>
|
|
|
|
</Cell>
|
|
|
|
<Cell col={12} tablet={12}>
|
|
|
|
<h6>{instances.length} Instances registered</h6>
|
|
|
|
<hr />
|
|
|
|
<List>
|
2017-08-28 21:40:44 +02:00
|
|
|
{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>
|
|
|
|
))}
|
2017-08-28 19:15:47 +02:00
|
|
|
</List>
|
|
|
|
</Cell>
|
|
|
|
</Grid>
|
|
|
|
) : (
|
|
|
|
<Grid>
|
|
|
|
<Cell col={12}>
|
|
|
|
<h5>Edit app meta data</h5>
|
|
|
|
</Cell>
|
|
|
|
<Cell col={6} tablet={12}>
|
|
|
|
<StatefulTextfield
|
|
|
|
value={url}
|
|
|
|
label="URL"
|
2017-08-28 21:40:44 +02:00
|
|
|
onBlur={e => storeApplicationMetaData(appName, 'url', e.target.value)}
|
2017-08-28 19:15:47 +02:00
|
|
|
/>
|
|
|
|
<br />
|
|
|
|
<StatefulTextfield
|
|
|
|
value={description}
|
|
|
|
label="Description"
|
|
|
|
rows={5}
|
2017-08-28 21:40:44 +02:00
|
|
|
onBlur={e => storeApplicationMetaData(appName, 'description', e.target.value)}
|
2017-08-28 19:15:47 +02:00
|
|
|
/>
|
|
|
|
</Cell>
|
|
|
|
<Cell col={6} tablet={12}>
|
|
|
|
<StatefulTextfield
|
|
|
|
value={icon}
|
|
|
|
label="Select icon"
|
2017-08-28 21:40:44 +02:00
|
|
|
onBlur={e => storeApplicationMetaData(appName, 'icon', e.target.value)}
|
2017-08-28 19:15:47 +02:00
|
|
|
/>
|
|
|
|
<StatefulTextfield
|
|
|
|
value={color}
|
|
|
|
label="Select color"
|
2017-08-28 21:40:44 +02:00
|
|
|
onBlur={e => storeApplicationMetaData(appName, 'color', e.target.value)}
|
2017-08-28 19:15:47 +02:00
|
|
|
/>
|
|
|
|
</Cell>
|
|
|
|
</Grid>
|
|
|
|
);
|
2016-12-13 20:54:53 +01:00
|
|
|
|
|
|
|
return (
|
2017-02-14 12:11:18 +01:00
|
|
|
<Card shadow={0} className={commonStyles.fullwidth}>
|
2017-08-28 21:40:44 +02:00
|
|
|
<CardTitle style={{ paddingTop: '24px', paddingRight: '64px', wordBreak: 'break-all' }}>
|
2017-02-14 12:11:18 +01:00
|
|
|
<Icon name={icon} /> {appName}
|
|
|
|
</CardTitle>
|
2017-08-28 19:15:47 +02:00
|
|
|
{description && <CardText>{description}</CardText>}
|
|
|
|
{url && (
|
|
|
|
<CardMenu>
|
|
|
|
<IconLink url={url} icon="link" />
|
|
|
|
</CardMenu>
|
|
|
|
)}
|
|
|
|
<hr />
|
|
|
|
<Tabs
|
|
|
|
activeTab={this.state.activeTab}
|
|
|
|
onChange={tabId => this.setState({ activeTab: tabId })}
|
|
|
|
ripple
|
|
|
|
tabBarProps={{ style: { width: '100%' } }}
|
|
|
|
className="mdl-color--grey-100"
|
|
|
|
>
|
2017-02-14 12:11:18 +01:00
|
|
|
<Tab>Details</Tab>
|
|
|
|
<Tab>Edit</Tab>
|
|
|
|
</Tabs>
|
2016-12-09 14:02:36 +01:00
|
|
|
|
2017-02-14 12:11:18 +01:00
|
|
|
{content}
|
|
|
|
</Card>
|
2016-12-05 15:15:01 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 20:54:53 +01:00
|
|
|
export default ClientApplications;
|