diff --git a/Makefile b/Makefile index 96c84855..df647ef0 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,13 @@ check: @yarn install --prefer-offline -@./bin/setup +.PHONE: licence +licence: + ./node_modules/.bin/license-to-fail ./licence.js + make licence-check + SUBDIRS := $(dir $(wildcard */Makefile)) -TARGETS := install clean test test-ci lint lint-ci # whatever else, but must not contain '/' +TARGETS := install clean test test-ci lint lint-ci licence-check# whatever else, but must not contain '/' # foo/.all bar/.all foo/.clean bar/.clean SUBDIRS_TARGETS := \ diff --git a/circle.yml b/circle.yml index 0eceb64d..1074cfa7 100644 --- a/circle.yml +++ b/circle.yml @@ -32,8 +32,8 @@ deployment: commands: - ./bin/docker-login - ./bin/on-changes-publish-ui - - make -j2 build | sed '/NPM_TOKEN/d' - - make -j2 push | sed '/NPM_TOKEN/d' + - make -j2 build + - make -j2 push - ./bin/deploy ## Custom notifications diff --git a/cloudapi-graphql/Makefile b/cloudapi-graphql/Makefile index 8bdaf473..f4312ebe 100644 --- a/cloudapi-graphql/Makefile +++ b/cloudapi-graphql/Makefile @@ -48,3 +48,7 @@ lint: lint-ci: mkdir -p $(XUNIT_DIR) -$(bindir)/eslint . --format tap | $(XUNIT) $(XUNIT_OUTPUT)-lint.xml + +.PHONY: licence-check +licence-check: + ../node_modules/.bin/license-to-fail ../licence.js diff --git a/docker-compose.yml b/docker-compose.yml index a6f00d52..02ad5b0d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,7 +39,7 @@ cloudapi: ############################################################################# frontend: image: quay.io/yldio/joyent-dashboard-frontend:latest - mem_limit: 128m + mem_limit: 256m labels: - triton.cns.services=frontend - com.docker.swarm.affinities=["container!=~*frontend*"] diff --git a/frontend/Makefile b/frontend/Makefile index 97eab1ff..bf505633 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -63,3 +63,7 @@ lint: lint-ci: mkdir -p $(XUNIT_DIR) -$(bindir)/eslint . --format tap | $(XUNIT) $(XUNIT_OUTPUT)-lint.xml + +.PHONY: licence-check +licence-check: + ../node_modules/.bin/license-to-fail ../licence.js 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/package.json b/frontend/package.json index 9c0d54eb..159bb8a0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "joyent-portal-frontend", - "version": "1.0.0", + "version": "1.1.0", "private": true, "license": "private", "main": "server/index.js", @@ -33,23 +33,24 @@ "lodash.uniq": "^4.5.0", "param-case": "^2.1.0", "querystring": "^0.2.0", - "react": "^15.4.1", + "react": "^15.4.2", "react-a11y": "^0.3.3", - "react-dom": "^15.4.1", + "react-dom": "^15.4.2", "react-hot-loader": "^3.0.0-beta.6", - "react-intl": "^2.2.2", + "react-intl": "^2.2.3", "react-intl-redux": "^0.3.0", - "react-redux": "^5.0.1", - "react-router": "^4.0.0-alpha.4", + "react-redux": "^5.0.2", + "react-router": "4.0.0-alpha.6", "reduce-reducers": "^0.1.2", "redux": "^3.6.0", "redux-actions": "^1.2.0", "redux-batched-actions": "^0.1.5", + "redux-form": "^6.4.3", "redux-logger": "^2.7.4", "redux-promise-middleware": "^4.2.0", "redux-thunk": "^2.1.0", "reselect": "^2.5.4", - "styled-components": "^1.2.1", + "styled-components": "^1.3.0", "understood": "^1.0.1", "url-loader": "^0.5.7" }, @@ -66,26 +67,27 @@ "babel-plugin-transform-runtime": "^6.15.0", "babel-plugin-webpack-alias": "^2.1.2", "babel-plugin-webpack-loaders": "^0.8.0", - "babel-preset-env": "^1.1.4", + "babel-preset-env": "^1.1.8", "babel-preset-react": "^6.16.0", "babel-register": "^6.18.0", "enzyme": "^2.7.0", - "eslint": "^3.12.2", + "eslint": "^3.13.1", "eslint-config-semistandard": "^7.0.0", "eslint-config-standard": "^6.2.1", "eslint-plugin-babel": "^4.0.0", "eslint-plugin-jsx-a11y": "^3.0.2", "eslint-plugin-promise": "^3.4.0", - "eslint-plugin-react": "^6.8.0", + "eslint-plugin-react": "^6.9.0", "eslint-plugin-standard": "^2.0.1", "fast-async": "^6.2.0", + "file-loader": "^0.9.0", "jsdom": "^9.9.1", "json-loader": "^0.5.4", "ncp": "^2.0.0", "node-hook": "^0.4.0", "nyc": "^10.0.0", "pre-commit": "^1.2.2", - "react-addons-test-utils": "^15.4.1", + "react-addons-test-utils": "^15.4.2", "redux-ava": "^2.2.0", "simple-mock": "^0.7.3", "tap-xunit": "^1.5.1", diff --git a/frontend/server/index.js b/frontend/server/index.js index 64eed390..4dc5745c 100644 --- a/frontend/server/index.js +++ b/frontend/server/index.js @@ -50,6 +50,18 @@ server.register(plugins, (err) => { process.exit(1); } + server.route({ + method: 'GET', + path: '/static/images/{param*}', + handler: { + directory: { + path: './images/', + redirectToSlash: true, + index: false + } + } + }); + server.route({ method: 'GET', path: '/static/{param*}', diff --git a/frontend/src/components/article/index.js b/frontend/src/components/article/index.js index 123833b2..77e57f8a 100644 --- a/frontend/src/components/article/index.js +++ b/frontend/src/components/article/index.js @@ -6,4 +6,5 @@ const { // Main Contonent Wrapper Styles module.exports = styled.article` + background-color: #fafafa; `; diff --git a/frontend/src/components/create-monitor/index.js b/frontend/src/components/create-monitor/index.js new file mode 100644 index 00000000..58f60906 --- /dev/null +++ b/frontend/src/components/create-monitor/index.js @@ -0,0 +1,140 @@ +const ReduxForm = require('redux-form'); +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 { + Field +} = ReduxForm; + +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; +`; + +const CreateMonitor = ({ + handleSubmit, + pristine, + submitting +}) => ( +
+

+ +

+

+ +

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

+ +

+

+ +

+ + + + + + + + + + +
+); + +CreateMonitor.propTypes = { + handleSubmit: React.PropTypes.func, + pristine: React.PropTypes.bool, + submitting: React.PropTypes.bool +}; + +module.exports = CreateMonitor; diff --git a/frontend/src/components/header/index.js b/frontend/src/components/header/index.js index e34123b3..110c7683 100644 --- a/frontend/src/components/header/index.js +++ b/frontend/src/components/header/index.js @@ -6,7 +6,7 @@ const Column = require('@ui/components/column'); const Container = require('@ui/components/container'); const Avatar = require('@ui/components/avatar'); const fns = require('@ui/shared/functions'); -const logo = require('@resources/logo.png'); +const logo = require('@resources/logo.svg'); const PropTypes = require('@root/prop-types'); const Row = require('@ui/components/row'); const Tooltip = require('@ui/components/tooltip'); 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..62903e4a --- /dev/null +++ b/frontend/src/components/monitors/index.js @@ -0,0 +1,121 @@ +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 fns = require('@ui/shared/functions'); +const Li = require('@ui/components/horizontal-list/li'); +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, + children, + handleDismiss = () => null, + metricType = {}, + page = 'create', + submit = () => null, + togglePage = () => null +}) => { + 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}

    +
    + + + {children} + + +
    + ); +}; + +Monitors.propTypes = { + active: React.PropTypes.string, + children: React.PropTypes.node, + 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/components/navigation/index.js b/frontend/src/components/navigation/index.js new file mode 100644 index 00000000..6fd1406b --- /dev/null +++ b/frontend/src/components/navigation/index.js @@ -0,0 +1,8 @@ +const Styled = require('styled-components'); + +const { + default: styled +} = Styled; + +module.exports = styled.nav` +`; diff --git a/frontend/src/components/navigation/org.js b/frontend/src/components/navigation/org.js new file mode 100644 index 00000000..e8f493c5 --- /dev/null +++ b/frontend/src/components/navigation/org.js @@ -0,0 +1,139 @@ +const React = require('react'); +const ReactRouter = require('react-router'); +const ReactRedux = require('react-redux'); +const Styled = require('styled-components'); + +const Avatar = require('@ui/components/avatar'); +const Container = require('@ui/components/container'); +const PropTypes = require('@root/prop-types'); +const selectors = require('@state/selectors'); +const Ul = require('@ui/components/horizontal-list/ul'); +const fns = require('@ui/shared/functions'); + +const { + connect +} = ReactRedux; + +const { + Link, +} = ReactRouter; + +const { + default: styled +} = Styled; + +const { + orgsSelector +} = selectors; + +const { + remcalc +} = fns; + +const StyledNav = styled.div` + background-color: #f2f2f2; + border-bottom: ${remcalc(1)} solid #d8d8d8; + + & ul { + height: ${remcalc(60)}; + margin: 0px 0px 0px 0px !important; + } +`; + +// TODO: refactor colours into constants in UI +const NavigationLinkContainer = styled.div` + padding: ${remcalc(11)} ${remcalc(12)} ${remcalc(12)}; + color: #646464; + border: solid ${remcalc(1)} #d8d8d8; + height: ${remcalc(24)}; + background-color: #f2f2f2; + + &.active { + background-color: #fafafa; + border-bottom: solid ${remcalc(1)} #fafafa; + } +`; + +const OrgImage = styled.div` + float: left; +`; + +const OrgAvatar = styled(Avatar)` + display: block !important; +`; + +const OrgName = styled.span` + margin-left: ${remcalc(12)}; + margin-top: ${remcalc(3)}; +`; + +const NavLi = styled.li` + display: inline-block; + padding-top: ${remcalc(12)}; + padding-left: ${remcalc(3)}; + + & a { + text-decoration: none !important; + } +`; + +const OrgNavigation = ({ + orgs = [] +}) => { + const navLinks = orgs.map(({ + id, + name, + image, + }) => { + const to = `/${id}`; + + return ( + + + { + ({ + isActive, + href, + onClick, + }) => + + + + + + + {name} + + + + } + + + ); + }); + + return ( + + + + + + ); +}; + +OrgNavigation.propTypes = { + orgs: React.PropTypes.arrayOf(PropTypes.org) +}; + +const mapStateToProps = (state) => ({ + orgs: orgsSelector(state) +}); + +module.exports = connect(mapStateToProps)(OrgNavigation); diff --git a/frontend/src/components/people-item/index.js b/frontend/src/components/people-item/index.js new file mode 100644 index 00000000..8bff9fc2 --- /dev/null +++ b/frontend/src/components/people-item/index.js @@ -0,0 +1,31 @@ +const React = require('react'); + +const PropTypes = require('@root/prop-types'); +// const List = require('@ui/components/list'); + +// const { +// ListItem, +// ListItemView, +// ListItemMeta, +// ListItemTitle, +// ListItemOptions +// } = List; + +const PersonItem = ({ + person = {}, +}) => { + + return ( + + {person.uuid} + {person.uuid} + {person.uuid} + + ); +}; + +PersonItem.propTypes = { + person: PropTypes.person, +}; + +module.exports = PersonItem; \ No newline at end of file diff --git a/frontend/src/components/people-list/index.js b/frontend/src/components/people-list/index.js new file mode 100644 index 00000000..304314d0 --- /dev/null +++ b/frontend/src/components/people-list/index.js @@ -0,0 +1,39 @@ +const React = require('react'); + +const PersonItem = require('@components/people-item'); +const PropTypes = require('@root/prop-types'); + +const PeopleList = ({ + people = [] +}) => { + + const peopleList = people.map((person) => ( + + )); + + return ( +
    + + + + + + + + + + {peopleList} + +
    MemberStatusRole
    +
    + ); +}; + +PeopleList.propTypes = { + people: React.PropTypes.arrayOf(PropTypes.person), +}; + +module.exports = PeopleList; diff --git a/frontend/src/components/section/index.js b/frontend/src/components/section/index.js index a4579555..beae6895 100644 --- a/frontend/src/components/section/index.js +++ b/frontend/src/components/section/index.js @@ -1,12 +1,30 @@ const flatten = require('lodash.flatten'); const React = require('react'); const ReactIntl = require('react-intl'); +const Styled = require('styled-components'); const ReactRouter = require('react-router'); -const H1 = require('@ui/components/h1'); +const H1 = require('@ui/components/base-elements').H1; const Li = require('@ui/components/horizontal-list/li'); const PropTypes = require('@root/prop-types'); const Ul = require('@ui/components/horizontal-list/ul'); +const fns = require('@ui/shared/functions'); + +const { + default: styled +} = Styled; + +const BreadcrumbA = styled.a` + text-decoration: none !important; +`; + +const BreadcrumbSpan = styled.span` + color: #646464; +`; + +const { + remcalc +} = fns; const { FormattedMessage @@ -36,12 +54,20 @@ const Section = ({ const link = ( - {part.name} + { + ({ + href, + onClick, + }) => + + {part.name} + + } ); const slash = ( - / + / ); return (i === 0) ? link : [ @@ -52,7 +78,11 @@ const Section = ({ return (
    -

    +

    {nameLinks}