diff --git a/frontend/locales/en-us.json b/frontend/locales/en-us.json index b74f12f2..46f06db4 100644 --- a/frontend/locales/en-us.json +++ b/frontend/locales/en-us.json @@ -37,5 +37,21 @@ "title": "Apache HTTP requests", "description": "Number of website requests to apache if it is used." } + }, + "monitors": { + "conditions": "Conditions", + "conditions-subtitle": "Please define what changes you wish to be alerted of.", + "if": "If metric is", + "above": "Above", + "equal": "Equal", + "below": "Below", + "average": "on averga", + "during": "during", + "last5": "last 5 minutes", + "notification": "Notification", + "notification-subtitle": "Type in users or teams who you wish to be alerted.", + "submit": "Create", + "create": "Create monitor", + "manage": "Managing monitors" } } diff --git a/frontend/src/components/create-monitor/index.js b/frontend/src/components/create-monitor/index.js new file mode 100644 index 00000000..43637046 --- /dev/null +++ b/frontend/src/components/create-monitor/index.js @@ -0,0 +1,125 @@ +const React = require('react'); +const ReactIntl = require('react-intl'); +const Styled = require('styled-components'); + +const Button = require('@ui/components/button'); +const Column = require('@ui/components/column'); +const Input = require('@ui/components/input'); +const fns = require('@ui/shared/functions'); +const Row = require('@ui/components/row'); +const Select = require('@ui/components/select'); + +const { + FormattedMessage +} = ReactIntl; + +const { + default: styled +} = Styled; + +const { + remcalc +} = fns; + +const H4 = styled.h4` + margin-bottom: ${remcalc(5)} !important; +`; + +const P = styled.p` + margin-bottom: ${remcalc(20)} !important; +`; + +const ConditionsRow = styled(Row)` + margin-bottom: ${remcalc(33)}; +`; + +const TextColumn = styled(Column)` + display: flex; + flex-direction: column; + justify-content: center; +`; + +const Text = styled.p` + margin: 0 auto !important; +`; + +const RightText = styled(Text)` + margin: 0 0 0 auto !important; +`; + +const PeopleInput = styled(Input)` + margin-bottom: ${remcalc(24)} !important; +`; + +module.exports = () => { + return ( +
+

+ +

+

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+

+ +

+ + + + + + + + + + +
+ ); +}; diff --git a/frontend/src/components/manage-monitor/index.js b/frontend/src/components/manage-monitor/index.js new file mode 100644 index 00000000..c61bbf54 --- /dev/null +++ b/frontend/src/components/manage-monitor/index.js @@ -0,0 +1,5 @@ +const React = require('react'); + +module.exports = () => ( +

manage monitor

+); \ No newline at end of file diff --git a/frontend/src/components/monitors/index.js b/frontend/src/components/monitors/index.js new file mode 100644 index 00000000..ae60ceee --- /dev/null +++ b/frontend/src/components/monitors/index.js @@ -0,0 +1,130 @@ +const React = require('react'); +const ReactIntl = require('react-intl'); +const Styled = require('styled-components'); + +const constants = require('@ui/shared/constants'); +const Close = require('@ui/components/close'); +const CreateMonitor = require('@components/create-monitor'); +const fns = require('@ui/shared/functions'); +const Li = require('@ui/components/horizontal-list/li'); +const ManageMonitor = require('@components/manage-monitor'); +const Modal = require('@ui/components/modal'); +const PropTypes = require('@root/prop-types'); +const Ul = require('@ui/components/horizontal-list/ul'); + +const { + FormattedMessage +} = ReactIntl; + +const { + default: styled +} = Styled; + +const { + colors +} = constants; + +const { + remcalc +} = fns; + +const H1 = styled.h1` + font-size: ${remcalc(26)} !important; + font-weight: 600; + font-style: normal; + font-stretch: normal; + color: ${colors.brandSecondaryColor}; + margin: ${remcalc(24)} auto ${remcalc(9)} ${remcalc(24)} !important; +`; + +const H3 = styled.h3` + font-size: ${remcalc(16)} !important; + font-weight: 600; + font-style: normal; + font-stretch: normal; + color: ${colors.brandSecondaryColor}; + margin: ${remcalc(0)} auto ${remcalc(26)} ${remcalc(24)} !important; +`; + +const Header = styled.header` + overflow: hidden; + background: ${colors.brandPrimaryColor}; + border-bottom: solid ${remcalc(1)} ${colors.borderSecondary}; +`; + +const StyledModal = styled(Modal)` + background: ${colors.brandInactive} !important; + box-shadow: 0 ${remcalc(2)} 0 0 rgba(0, 0, 0, 0.05); + padding: 0 !important; +`; + +const View = styled.div` + margin: ${remcalc(18)} ${remcalc(24)} ${remcalc(49)} ${remcalc(24)}; + height: 100%; +`; + +const Monitors = ({ + active = false, + handleDismiss = () => null, + metricType = {}, + page = 'create', + submit = () => null, + togglePage = () => null +}) => { + const views = { + create: () => ( + + ), + manage: () => ( + + ) + }; + + const links = ['create', 'manage'].map((name) => { + const id = `monitors.${name}`; + const className = page === name ? 'active' : ''; + const onClick = (ev) => togglePage(name); + const href = `#${name}`; + + return ( +
  • + + + +
  • + ); + }); + + return ( + +
    +

    + +

    +

    for {metricType.name}

    +
    + +
      + {links} +
    + {views[page]()} +
    + +
    + ); +}; + +Monitors.propTypes = { + active: React.PropTypes.string, + handleDismiss: React.PropTypes.func.isRequired, + metricType: PropTypes.metricType, + page: React.PropTypes.string, + submit: React.PropTypes.func.isRequired, + togglePage: React.PropTypes.func.isRequired +}; + +module.exports = Monitors; diff --git a/frontend/src/containers/metrics/add-metrics.js b/frontend/src/containers/metrics/add-metrics.js index c1091361..adc9728f 100644 --- a/frontend/src/containers/metrics/add-metrics.js +++ b/frontend/src/containers/metrics/add-metrics.js @@ -57,7 +57,7 @@ const AddMetrics = ({ }; AddMetrics.propTypes = { - metricTypes: PropTypes.metricTypes.isRequired, + metricTypes: React.PropTypes.arrayOf(React.PropTypes.string), metrics: React.PropTypes.arrayOf(PropTypes.metric).isRequired, onAddMetric: React.PropTypes.func.isRequired, }; diff --git a/frontend/src/containers/metrics/index.js b/frontend/src/containers/metrics/index.js index e69de29b..2e42b111 100644 --- a/frontend/src/containers/metrics/index.js +++ b/frontend/src/containers/metrics/index.js @@ -0,0 +1,70 @@ +const React = require('react'); +const ReactRedux = require('react-redux'); + +const actions = require('@state/actions'); +const AddMetrics = require('./add-metrics'); +const Button = require('@ui/components/button'); +const Column = require('@ui/components/column'); +const Monitors = require('./monitors'); +const PropTypes = require('@root/prop-types'); +const Row = require('@ui/components/row'); + +const { + connect +} = ReactRedux; + +const { + toggleMonitorView +} = actions; + +const Metrics = ({ + addMetric, + metrics, + metricTypes, + metricTypeUuid = '', + service, + toggleMonitorView = () => null +}) => { + const onMonitorsClick = (ev) => toggleMonitorView(metricTypeUuid); + + return ( +
    + + + + + + + +
    + ); +}; + +Metrics.propTypes = { + addMetric: React.PropTypes.func.isRequired, + metricTypeUuid: React.PropTypes.string, + metricTypes: React.PropTypes.arrayOf(React.PropTypes.string), + metrics: React.PropTypes.arrayOf(PropTypes.metric), + service: PropTypes.service, + toggleMonitorView: React.PropTypes.func.isRequired +}; + +const mapStateToProps = (state) => ({ + // hardcoded now, but should be dynamic + // actually, the use for this prop is going to disapear + metricTypeUuid: 'dca08514-72e5-46ce-ad91-e68b3b0914d4', +}); + +const mapDispatchToProps = (dispatch) => ({ + toggleMonitorView: (metricTypeUuid) => + dispatch(toggleMonitorView(metricTypeUuid)) +}); + +module.exports = connect( + mapStateToProps, + mapDispatchToProps +)(Metrics); diff --git a/frontend/src/containers/metrics/monitors.js b/frontend/src/containers/metrics/monitors.js new file mode 100644 index 00000000..4e196513 --- /dev/null +++ b/frontend/src/containers/metrics/monitors.js @@ -0,0 +1,36 @@ +const ReactRedux = require('react-redux'); + +const actions = require('@state/actions'); +const Monitors = require('@components/monitors'); +const selectors = require('@state/selectors'); + +const { + connect +} = ReactRedux; + +const { + metricTypeByUuidSelector +} = selectors; + +const { + toggleMonitorView, + switchMonitorViewPage, + createMonitor +} = actions; + +const mapStateToProps = (state) => ({ + metricType: metricTypeByUuidSelector(state.monitors.ui.active)(state), + active: state.monitors.ui.active, + page: state.monitors.ui.page +}); + +const mapDispatchToProps = (dispatch) => ({ + handleDismiss: () => dispatch(toggleMonitorView()), + togglePage: (newPage) => dispatch(switchMonitorViewPage(newPage)), + submit: (meta) => dispatch(createMonitor(meta)) +}); + +module.exports = connect( + mapStateToProps, + mapDispatchToProps +)(Monitors); diff --git a/frontend/src/containers/service/metrics.js b/frontend/src/containers/service/metrics.js index c7ffa76e..c179be15 100644 --- a/frontend/src/containers/service/metrics.js +++ b/frontend/src/containers/service/metrics.js @@ -1,9 +1,8 @@ -const React = require('react'); const ReactRedux = require('react-redux'); -const PropTypes = require('@root/prop-types'); -const selectors = require('@state/selectors'); -const AddMetrics = require('../metrics/add-metrics'); + const actions = require('@state/actions'); +const Metrics = require('@containers/metrics'); +const selectors = require('@state/selectors'); const { connect @@ -18,41 +17,6 @@ const { addMetric } = actions; -const Metrics = ({ - addMetric, - metrics, - metricTypes, - service -}) => { - - const onAddMetric = (metric) => { - addMetric({ - id: metric, - service: service.uuid - }); - }; - - return ( -
    -

    metrics

    -
    - -
    -
    - ); -}; - -Metrics.propTypes = { - addMetric: React.PropTypes.func.isRequired, - metricTypes: PropTypes.metricTypes, - metrics: React.PropTypes.arrayOf(PropTypes.metric), - service: PropTypes.service -}; - const mapStateToProps = (state, { params = {} }) => ({ @@ -62,10 +26,21 @@ const mapStateToProps = (state, { }); const mapDispatchToProps = (dispatch) => ({ - addMetric: (payload) => dispatch(addMetric(payload)) + addMetric: (service) => (metric) => dispatch(addMetric({ + id: metric, + service: service + })) +}); + +const mergeProps = (stateProps, dispatchProps, ownProps) => ({ + ...stateProps, + ...dispatchProps, + ...ownProps, + addMetric: dispatchProps.addMetric(stateProps.service) }); module.exports = connect( mapStateToProps, - mapDispatchToProps + mapDispatchToProps, + mergeProps )(Metrics); diff --git a/frontend/src/mock-state.json b/frontend/src/mock-state.json index 70fa0434..937c0396 100644 --- a/frontend/src/mock-state.json +++ b/frontend/src/mock-state.json @@ -46,6 +46,12 @@ "location": "Amsterdam, Netherlands" }] }, + "monitors": { + "ui": { + "active": "dca08514-72e5-46ce-ad91-e68b3b0914d4", + "page": "create" + } + }, "metrics": { "ui": { "types": [ @@ -68,6 +74,7 @@ "data": { "types": [{ "uuid": "dca08514-72e5-46ce-ad91-e68b3b0914d4", + "name": "Aggregated CPU usage", "id": "agg-cpu-usage" }, { "uuid": "9e77b50e-42d7-425d-8daf-c0e98e2bdd6a", diff --git a/frontend/src/prop-types.js b/frontend/src/prop-types.js index 9908426d..f7baee89 100644 --- a/frontend/src/prop-types.js +++ b/frontend/src/prop-types.js @@ -39,6 +39,10 @@ const Metric = React.PropTypes.shape({ ...BaseObject }); +const MetricType = React.PropTypes.shape({ + ...BaseObject +}); + const Dataset = React.PropTypes.shape({ uuid: React.PropTypes.string, type: React.PropTypes.string, @@ -57,11 +61,6 @@ const Sections = React.PropTypes.arrayOf( React.PropTypes.string ); -// consinder renaming this to 'Types' as it could be used for any -const MetricTypes = React.PropTypes.arrayOf( - React.PropTypes.string -); - module.exports = { account: Account, link: Link, @@ -71,7 +70,6 @@ module.exports = { service: Service, instance: Instance, metric: Metric, - // consinder renaming this to 'Types' as it could be used for any - metricTypes: MetricTypes, + metricType: MetricType, dataset: Dataset }; diff --git a/frontend/src/state/actions.js b/frontend/src/state/actions.js index e0811e7c..7e5262ed 100644 --- a/frontend/src/state/actions.js +++ b/frontend/src/state/actions.js @@ -9,9 +9,12 @@ const APP = constantCase(process.env['APP_NAME']); module.exports = { ...require('@state/thunks'), - updateRouter: createAction(`${APP}/APP/UPDATE_ROUTER`), - toggleHeaderTooltip: createAction(`${APP}/APP/TOGGLE_HEADER_TOOLTIP`), - toggleServiceCollapsed: createAction(`${APP}/APP/TOGGLE_SERVICE_COLLAPSED`), - addMetric: createAction(`${APP}/APP/ADD_METRIC`), - toggleInstanceCollapsed: createAction(`${APP}/APP/TOGGLE_INSTANCE_COLLAPSED`) + updateRouter: createAction(`${APP}/UPDATE_ROUTER`), + toggleHeaderTooltip: createAction(`${APP}/TOGGLE_HEADER_TOOLTIP`), + toggleServiceCollapsed: createAction(`${APP}/TOGGLE_SERVICE_COLLAPSED`), + addMetric: createAction(`${APP}/ADD_METRIC`), + toggleInstanceCollapsed: createAction(`${APP}/TOGGLE_INSTANCE_COLLAPSED`), + toggleMonitorView: createAction(`${APP}/TOGGLE_MONITOR_VIEW`), + switchMonitorViewPage: createAction(`${APP}/SWITCH_MONITOR_VIEW_PAGE`), + createMonitor: createAction(`${APP}/CREATE_MONITOR`) }; diff --git a/frontend/src/state/reducers/index.js b/frontend/src/state/reducers/index.js index 9f428409..c87158f0 100644 --- a/frontend/src/state/reducers/index.js +++ b/frontend/src/state/reducers/index.js @@ -11,6 +11,7 @@ module.exports = () => { instances: require('@state/reducers/instances'), intl: require('@state/reducers/intl'), metrics: require('@state/reducers/metrics'), + monitors: require('@state/reducers/monitors'), orgs: require('@state/reducers/orgs'), projects: require('@state/reducers/projects'), services: require('@state/reducers/services') diff --git a/frontend/src/state/reducers/monitors.js b/frontend/src/state/reducers/monitors.js new file mode 100644 index 00000000..1c8a8204 --- /dev/null +++ b/frontend/src/state/reducers/monitors.js @@ -0,0 +1,30 @@ +const ReduxActions = require('redux-actions'); + +const actions = require('@state/actions'); + +const { + handleActions +} = ReduxActions; + +const { + toggleMonitorView, + switchMonitorViewPage + // createMonitor +} = actions; + +module.exports = handleActions({ + [toggleMonitorView.toString()]: (state, action) => ({ + ...state, + ui: { + ...state.ui, + active: action.payload + } + }), + [switchMonitorViewPage.toString()]: (state, action) => ({ + ...state, + ui: { + ...state.ui, + page: action.payload + } + }) +}, {}); diff --git a/frontend/src/state/selectors.js b/frontend/src/state/selectors.js index 7c154b3d..23a06af4 100644 --- a/frontend/src/state/selectors.js +++ b/frontend/src/state/selectors.js @@ -93,6 +93,12 @@ const metricsByServiceId = (serviceId) => createSelector( metricTypes.filter((i) => i.service === service.uuid) ); +const metricTypeByUuid = (metricTypeUuid) => createSelector( + [metricTypes], + (metricTypes) => find(metricTypes, ['uuid', metricTypeUuid]) +); + + const instancesByProjectId = (projectId) => createSelector( [instances, projectById(projectId), collapsedInstances, metricDatasets], (instances, project, collapsed, metrics) => @@ -119,5 +125,6 @@ module.exports = { servicesByProjectIdSelector: servicesByProjectId, instancesByServiceIdSelector: instancesByServiceId, metricsByServiceIdSelector: metricsByServiceId, - instancesByProjectIdSelector: instancesByProjectId + instancesByProjectIdSelector: instancesByProjectId, + metricTypeByUuidSelector: metricTypeByUuid };