From 442685674bee04e2aa9f929f4d339c86008b0366 Mon Sep 17 00:00:00 2001 From: Risha Mars Date: Wed, 5 Dec 2018 15:08:10 -0800 Subject: [PATCH] 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. --- .../js/components/ConfigureProfilesMsg.jsx | 115 +++++++++++++++++- web/app/js/components/util/ApiHelpers.jsx | 11 ++ 2 files changed, 123 insertions(+), 3 deletions(-) diff --git a/web/app/js/components/ConfigureProfilesMsg.jsx b/web/app/js/components/ConfigureProfilesMsg.jsx index 7dbbd2cd5..3572ff63c 100644 --- a/web/app/js/components/ConfigureProfilesMsg.jsx +++ b/web/app/js/components/ConfigureProfilesMsg.jsx @@ -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 ( + + + + + New service profile + + + To create a service profile, download a profile and then apply it with `kubectl apply`. + + + + + + + + + + + + + + ); + } + render() { const { classes } = this.props; + return ( - - No traffic found. Does the service have a service profile? You can create one with the `linkerd profile` command. + + No traffic found. Does the service have a service profile? + {this.renderDownloadProfileForm()} @@ -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)); diff --git a/web/app/js/components/util/ApiHelpers.jsx b/web/app/js/components/util/ApiHelpers.jsx index 75bdd295f..2bb438094 100644 --- a/web/app/js/components/util/ApiHelpers.jsx +++ b/web/app/js/components/util/ApiHelpers.jsx @@ -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,