mirror of https://github.com/linkerd/linkerd2.git
Add a Create Service Profile dialog (#1933)
Add the ability to create and download a service profile from the web UI. This form will be displayed in the call to action if no route metrics are found.
This commit is contained in:
parent
7169eaef27
commit
442685674b
|
@ -1,24 +1,130 @@
|
|||
import Button from '@material-ui/core/Button';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import _ from 'lodash';
|
||||
import { withContext } from './util/AppContext.jsx';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
|
||||
const styles = theme => ({
|
||||
button: {
|
||||
margin: theme.spacing.unit,
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
},
|
||||
textField: {
|
||||
marginLeft: theme.spacing.unit,
|
||||
marginRight: theme.spacing.unit,
|
||||
width: 200,
|
||||
},
|
||||
root: {
|
||||
marginTop: theme.spacing.unit * 3,
|
||||
marginBottom: theme.spacing.unit * 3,
|
||||
},
|
||||
});
|
||||
class ConfigureProfilesMsg extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
open: false,
|
||||
query: {
|
||||
service: "",
|
||||
namespace: ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
handleClickOpen = () => {
|
||||
this.setState({ open: true });
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.setState({ open: false });
|
||||
};
|
||||
|
||||
handleChange = name => {
|
||||
let state = this.state;
|
||||
|
||||
return e => {
|
||||
state.query[name] = e.target.value;
|
||||
this.setState(state);
|
||||
};
|
||||
}
|
||||
|
||||
renderDownloadProfileForm = () => {
|
||||
const { api, classes } = this.props;
|
||||
let { query } = this.state;
|
||||
|
||||
let downloadUrl = api.prefixedUrl(`/profiles/new?service=${query.service}&namespace=${query.namespace}`);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Button
|
||||
className={classes.button}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={this.handleClickOpen}>Create Service Profile
|
||||
</Button>
|
||||
|
||||
<Dialog
|
||||
open={this.state.open}
|
||||
onClose={this.handleClose}
|
||||
aria-labelledby="form-dialog-title">
|
||||
<DialogTitle id="form-dialog-title">New service profile</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
To create a service profile, download a profile and then apply it with `kubectl apply`.
|
||||
</DialogContentText>
|
||||
<TextField
|
||||
id="service"
|
||||
label="Service"
|
||||
className={classes.textField}
|
||||
value={this.state.service}
|
||||
onChange={this.handleChange('service')}
|
||||
margin="normal" />
|
||||
<TextField
|
||||
id="namespace"
|
||||
label="Namespace"
|
||||
className={classes.textField}
|
||||
value={this.state.name}
|
||||
onChange={this.handleChange('namespace')}
|
||||
margin="normal" />
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={this.handleClose} color="primary">Cancel</Button>
|
||||
<a href={downloadUrl} style={{ textDecoration: 'none' }}>
|
||||
<Button
|
||||
disabled={_.isEmpty(query.service) || _.isEmpty(query.namespace)}
|
||||
onClick={this.handleClose}
|
||||
color="primary">Download
|
||||
</Button>
|
||||
</a>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
|
||||
return (
|
||||
<Card className={classes.root}>
|
||||
<CardContent>
|
||||
<Typography>
|
||||
No traffic found. Does the service have a service profile? You can create one with the `linkerd profile` command.
|
||||
<Typography component="div">
|
||||
No traffic found. Does the service have a service profile?
|
||||
{this.renderDownloadProfileForm()}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
@ -27,7 +133,10 @@ class ConfigureProfilesMsg extends React.Component {
|
|||
}
|
||||
|
||||
ConfigureProfilesMsg.propTypes = {
|
||||
api: PropTypes.shape({
|
||||
prefixedFetch: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
classes: PropTypes.shape({}).isRequired
|
||||
};
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(ConfigureProfilesMsg);
|
||||
export default withContext(withStyles(styles, { withTheme: true })(ConfigureProfilesMsg));
|
||||
|
|
|
@ -64,6 +64,7 @@ const ApiHelpers = (pathPrefix, defaultMetricsWindow = '1m') => {
|
|||
"1h": "1 hour"
|
||||
};
|
||||
|
||||
// for getting json api results
|
||||
const apiFetch = path => {
|
||||
if (!_.isEmpty(pathPrefix)) {
|
||||
path = `${pathPrefix}${path}`;
|
||||
|
@ -72,6 +73,15 @@ const ApiHelpers = (pathPrefix, defaultMetricsWindow = '1m') => {
|
|||
return makeCancelable(fetch(path), r => r.json());
|
||||
};
|
||||
|
||||
// for getting non-json results
|
||||
const prefixedUrl = path => {
|
||||
if (!_.isEmpty(pathPrefix)) {
|
||||
path = `${pathPrefix}${path}`;
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
const fetchMetrics = path => {
|
||||
if (path.indexOf("window") === -1) {
|
||||
if (path.indexOf("?") === -1) {
|
||||
|
@ -193,6 +203,7 @@ const ApiHelpers = (pathPrefix, defaultMetricsWindow = '1m') => {
|
|||
|
||||
return {
|
||||
fetch: apiFetch,
|
||||
prefixedUrl,
|
||||
fetchMetrics,
|
||||
fetchPods,
|
||||
fetchServices,
|
||||
|
|
Loading…
Reference in New Issue