mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
fix: cleanup edit application a bit
This commit is contained in:
parent
130110f5a4
commit
987fce309c
@ -92,6 +92,7 @@ exports[`renders correctly with permissions 1`] = `
|
||||
>
|
||||
<react-mdl-Cell
|
||||
col={6}
|
||||
hidePhone={true}
|
||||
phone={12}
|
||||
tablet={4}
|
||||
>
|
||||
@ -199,8 +200,7 @@ exports[`renders correctly with permissions 1`] = `
|
||||
subtitle={
|
||||
<span>
|
||||
123.123.123.123
|
||||
last seen at
|
||||
|
||||
last seen at
|
||||
<small>
|
||||
02/23/2017, 03:56:49 PM
|
||||
</small>
|
||||
@ -263,6 +263,7 @@ exports[`renders correctly without permission 1`] = `
|
||||
>
|
||||
<react-mdl-Cell
|
||||
col={6}
|
||||
hidePhone={true}
|
||||
phone={12}
|
||||
tablet={4}
|
||||
>
|
||||
@ -360,8 +361,7 @@ exports[`renders correctly without permission 1`] = `
|
||||
subtitle={
|
||||
<span>
|
||||
123.123.123.123
|
||||
last seen at
|
||||
|
||||
last seen at
|
||||
<small>
|
||||
02/23/2017, 03:56:49 PM
|
||||
</small>
|
||||
|
@ -1,63 +1,13 @@
|
||||
/* eslint react/no-multi-comp:off */
|
||||
import React, { Component, PureComponent } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
Cell,
|
||||
Card,
|
||||
CardActions,
|
||||
CardTitle,
|
||||
CardText,
|
||||
CardMenu,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemContent,
|
||||
Textfield,
|
||||
Icon,
|
||||
ProgressBar,
|
||||
Tabs,
|
||||
Tab,
|
||||
Switch,
|
||||
} from 'react-mdl';
|
||||
import { IconLink, shorten, styles as commonStyles } from '../common';
|
||||
import { Button, Card, CardActions, CardTitle, CardText, CardMenu, Icon, ProgressBar, Tabs, Tab } from 'react-mdl';
|
||||
import { IconLink, styles as commonStyles } from '../common';
|
||||
import { formatFullDateTimeWithLocale } from '../common/util';
|
||||
import { CREATE_FEATURE, CREATE_STRATEGY, UPDATE_APPLICATION } from '../../permissions';
|
||||
import icons from './icon-names';
|
||||
import MySelect from '../common/select';
|
||||
|
||||
class StatefulTextfield extends Component {
|
||||
static propTypes = {
|
||||
value: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
rows: PropTypes.number,
|
||||
onBlur: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { value: props.value };
|
||||
this.setValue = function setValue(e) {
|
||||
this.setState({ value: e.target.value });
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
import { UPDATE_APPLICATION } from '../../permissions';
|
||||
import ApplicationView from './application-view';
|
||||
import ApplicationUpdate from './application-update';
|
||||
|
||||
class ClientApplications extends PureComponent {
|
||||
static propTypes = {
|
||||
@ -71,17 +21,15 @@ class ClientApplications extends PureComponent {
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
constructor() {
|
||||
super();
|
||||
this.state = { activeTab: 0 };
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchApplication(this.props.appName);
|
||||
}
|
||||
formatFullDateTime(v) {
|
||||
return formatFullDateTimeWithLocale(v, this.props.location.locale);
|
||||
}
|
||||
formatFullDateTime = v => formatFullDateTimeWithLocale(v, this.props.location.locale);
|
||||
|
||||
deleteApplication = async evt => {
|
||||
evt.preventDefault();
|
||||
@ -95,126 +43,19 @@ class ClientApplications extends PureComponent {
|
||||
return <ProgressBar indeterminate />;
|
||||
}
|
||||
const { application, storeApplicationMetaData, hasPermission } = this.props;
|
||||
const { appName, instances, strategies, seenToggles, url, description, icon = 'apps', color } = application;
|
||||
const { appName, instances, strategies, seenToggles, url, description, icon = 'apps' } = application;
|
||||
|
||||
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}>
|
||||
{hasPermission(CREATE_FEATURE) ? (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||
<Link to={`/features/create?name=${name}`}>{name}</Link>
|
||||
</ListItemContent>
|
||||
) : (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing'}>
|
||||
{name}
|
||||
</ListItemContent>
|
||||
)}
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem twoLine key={i}>
|
||||
<ListItemContent
|
||||
icon={
|
||||
<span>
|
||||
<Switch disabled checked={!!enabled} />
|
||||
</span>
|
||||
}
|
||||
subtitle={shorten(description, 60)}
|
||||
>
|
||||
<Link to={`/features/view/${name}`}>{shorten(name, 50)}</Link>
|
||||
</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}`}>
|
||||
{hasPermission(CREATE_STRATEGY) ? (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||
<Link to={`/strategies/create?name=${name}`}>{name}</Link>
|
||||
</ListItemContent>
|
||||
) : (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing'}>
|
||||
{name}
|
||||
</ListItemContent>
|
||||
)}
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem twoLine key={`${name}-${i}`}>
|
||||
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
|
||||
<Link to={`/strategies/view/${name}`}>{shorten(name, 50)}</Link>
|
||||
</ListItemContent>
|
||||
</ListItem>
|
||||
)
|
||||
)}
|
||||
</List>
|
||||
</Cell>
|
||||
<Cell col={12} tablet={12}>
|
||||
<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>{this.formatFullDateTime(lastSeen)}</small>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
{instanceId} {sdkVersion ? `(${sdkVersion})` : ''}
|
||||
</ListItemContent>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Cell>
|
||||
</Grid>
|
||||
<ApplicationView
|
||||
strategies={strategies}
|
||||
instances={instances}
|
||||
seenToggles={seenToggles}
|
||||
hasPermission={hasPermission}
|
||||
formatFullDateTime={this.formatFullDateTime}
|
||||
/>
|
||||
) : (
|
||||
<Grid>
|
||||
<Cell col={6} tablet={12}>
|
||||
<StatefulTextfield
|
||||
value={url}
|
||||
label="URL"
|
||||
type="url"
|
||||
onBlur={e => storeApplicationMetaData(appName, 'url', e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<StatefulTextfield
|
||||
value={description}
|
||||
label="Description"
|
||||
rows={5}
|
||||
onBlur={e => storeApplicationMetaData(appName, 'description', e.target.value)}
|
||||
/>
|
||||
</Cell>
|
||||
<Cell col={6} tablet={12}>
|
||||
<MySelect
|
||||
label="Icon"
|
||||
options={icons.map(v => ({ key: v, label: v }))}
|
||||
value={icon}
|
||||
onChange={e => storeApplicationMetaData(appName, 'icon', e.target.value)}
|
||||
filled
|
||||
/>
|
||||
<StatefulTextfield
|
||||
value={color}
|
||||
label="Color"
|
||||
onBlur={e => storeApplicationMetaData(appName, 'color', e.target.value)}
|
||||
/>
|
||||
</Cell>
|
||||
</Grid>
|
||||
<ApplicationUpdate application={application} storeApplicationMetaData={storeApplicationMetaData} />
|
||||
);
|
||||
|
||||
return (
|
||||
|
46
frontend/src/component/application/application-update.jsx
Normal file
46
frontend/src/component/application/application-update.jsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Grid, Cell } from 'react-mdl';
|
||||
import StatefulTextfield from './stateful-textfield';
|
||||
import icons from './icon-names';
|
||||
import MySelect from '../common/select';
|
||||
|
||||
function ApplicationUpdate({ application, storeApplicationMetaData }) {
|
||||
const { appName, icon, url, description } = application;
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Cell col={12}>
|
||||
<MySelect
|
||||
label="Icon"
|
||||
options={icons.map(v => ({ key: v, label: v }))}
|
||||
value={icon || 'apps'}
|
||||
onChange={e => storeApplicationMetaData(appName, 'icon', e.target.value)}
|
||||
filled
|
||||
/>
|
||||
<StatefulTextfield
|
||||
value={url}
|
||||
label="Application URL"
|
||||
placeholder="https://example.com"
|
||||
type="url"
|
||||
onBlur={e => storeApplicationMetaData(appName, 'url', e.target.value)}
|
||||
/>
|
||||
|
||||
<br />
|
||||
<StatefulTextfield
|
||||
value={description}
|
||||
label="Description"
|
||||
rows={2}
|
||||
onBlur={e => storeApplicationMetaData(appName, 'description', e.target.value)}
|
||||
/>
|
||||
</Cell>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
ApplicationUpdate.propTypes = {
|
||||
application: PropTypes.object.isRequired,
|
||||
storeApplicationMetaData: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ApplicationUpdate;
|
104
frontend/src/component/application/application-view.jsx
Normal file
104
frontend/src/component/application/application-view.jsx
Normal file
@ -0,0 +1,104 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Grid, Cell, List, ListItem, ListItemContent, Switch } from 'react-mdl';
|
||||
import { shorten } from '../common';
|
||||
import { CREATE_FEATURE, CREATE_STRATEGY } from '../../permissions';
|
||||
|
||||
function ApplicationView({ seenToggles, hasPermission, strategies, instances, formatFullDateTime }) {
|
||||
return (
|
||||
<Grid style={{ margin: 0 }}>
|
||||
<Cell col={6} tablet={4} phone={12} hidePhone>
|
||||
<h6> Toggles</h6>
|
||||
<hr />
|
||||
<List>
|
||||
{seenToggles.map(({ name, description, enabled, notFound }, i) =>
|
||||
notFound ? (
|
||||
<ListItem twoLine key={i}>
|
||||
{hasPermission(CREATE_FEATURE) ? (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||
<Link to={`/features/create?name=${name}`}>{name}</Link>
|
||||
</ListItemContent>
|
||||
) : (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing'}>
|
||||
{name}
|
||||
</ListItemContent>
|
||||
)}
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem twoLine key={i}>
|
||||
<ListItemContent
|
||||
icon={
|
||||
<span>
|
||||
<Switch disabled checked={!!enabled} />
|
||||
</span>
|
||||
}
|
||||
subtitle={shorten(description, 60)}
|
||||
>
|
||||
<Link to={`/features/view/${name}`}>{shorten(name, 50)}</Link>
|
||||
</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}`}>
|
||||
{hasPermission(CREATE_STRATEGY) ? (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing, want to create?'}>
|
||||
<Link to={`/strategies/create?name=${name}`}>{name}</Link>
|
||||
</ListItemContent>
|
||||
) : (
|
||||
<ListItemContent icon={'report'} subtitle={'Missing'}>
|
||||
{name}
|
||||
</ListItemContent>
|
||||
)}
|
||||
</ListItem>
|
||||
) : (
|
||||
<ListItem twoLine key={`${name}-${i}`}>
|
||||
<ListItemContent icon={'extension'} subtitle={shorten(description, 60)}>
|
||||
<Link to={`/strategies/view/${name}`}>{shorten(name, 50)}</Link>
|
||||
</ListItemContent>
|
||||
</ListItem>
|
||||
)
|
||||
)}
|
||||
</List>
|
||||
</Cell>
|
||||
<Cell col={12} tablet={12}>
|
||||
<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>
|
||||
))}
|
||||
</List>
|
||||
</Cell>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
ApplicationView.propTypes = {
|
||||
instances: PropTypes.array.isRequired,
|
||||
seenToggles: PropTypes.array.isRequired,
|
||||
strategies: PropTypes.array.isRequired,
|
||||
hasPermission: PropTypes.func.isRequired,
|
||||
formatFullDateTime: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ApplicationView;
|
35
frontend/src/component/application/stateful-textfield.js
Normal file
35
frontend/src/component/application/stateful-textfield.js
Normal file
@ -0,0 +1,35 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Textfield } from 'react-mdl';
|
||||
|
||||
function StatefulTextfield({ value, label, placeholder, rows, onBlur }) {
|
||||
const [localValue, setLocalValue] = useState(value);
|
||||
|
||||
const onChange = e => {
|
||||
e.preventDefault();
|
||||
setLocalValue(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Textfield
|
||||
style={{ width: '100%' }}
|
||||
label={label}
|
||||
placeholder={placeholder}
|
||||
floatingLabel
|
||||
rows={rows}
|
||||
value={localValue}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
StatefulTextfield.propTypes = {
|
||||
value: PropTypes.string,
|
||||
label: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
rows: PropTypes.number,
|
||||
onBlur: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default StatefulTextfield;
|
@ -6,7 +6,6 @@ import { Icon, FABButton, Menu, MenuItem, Card, CardActions, List } from 'react-
|
||||
import Feature from './feature-list-item-component';
|
||||
import { MenuItemWithIcon, DropdownButton, styles as commonStyles } from '../common';
|
||||
import SearchField from '../common/search-field';
|
||||
import styles from './feature.scss';
|
||||
import { CREATE_FEATURE } from '../../permissions';
|
||||
|
||||
export default class FeatureListComponent extends React.Component {
|
||||
|
Loading…
Reference in New Issue
Block a user