diff --git a/circle.yml b/circle.yml index d902f72f..0eceb64d 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,6 @@ machine: - git config --global user.email "circleci@joyent.zone" - git config --global user.name "circlebot" - curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0 - - curl -o- -L https://yarnpkg.com/install.sh | bash services: - docker diff --git a/frontend/Makefile b/frontend/Makefile index 561cc1cc..97eab1ff 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -7,11 +7,11 @@ UI := $(shell pwd)/../ui .PHONY: install-production install-production: compile - yarn install --production --prefer-offline + yarn install --production --no-lockfile .PHONY: install install: - NODE_ENV=development yarn install --prefer-offline + NODE_ENV=development yarn install --no-lockfile .PHONY: clean clean: diff --git a/frontend/src/components/header/index.js b/frontend/src/components/header/index.js index ebdc33d4..e34123b3 100644 --- a/frontend/src/components/header/index.js +++ b/frontend/src/components/header/index.js @@ -23,10 +23,15 @@ const { const { remcalc } = fns; + const { pseudoEl } = composers; +const borderSide = props => props.toggled + ? 'bottom' + : 'top'; + const StyledHeader = styled.header` background-color: #ffffff; padding-top: ${remcalc(21)}; @@ -34,7 +39,7 @@ const StyledHeader = styled.header` `; const StyledLogo = styled.img` - padding-top: ${remcalc(10)} + padding-top: ${remcalc(10)}; `; const StyledProfileWrapper = styled.div` @@ -43,26 +48,26 @@ const StyledProfileWrapper = styled.div` const StyledAvatarWrapper = styled.div` &:after { - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-${props => props.toggled ? 'bottom' : 'top'}: 5px solid black; + border-left: ${remcalc(5)} solid transparent; + border-right: ${remcalc(5)} solid transparent; + border-${borderSide}: ${remcalc(5)} solid black; ${pseudoEl({ top: '50%', - right: '10px' + right: remcalc(10) })} } `; const StyledTooltipWrapper = styled.div` position: absolute; - left: -40px; - bottom: -180px; + left: ${remcalc(-40)}; + bottom: ${remcalc(-180)}; `; const StyledName = styled.span` position: relative; - top: -12px; + top: ${remcalc(-12)}; `; const EmptyButton = styled.button` @@ -71,7 +76,7 @@ const EmptyButton = styled.button` `; const StyledAvatar = styled(Avatar)` - marginLeft: 12px; + marginLeft: ${remcalc(12)}; `; const arrowPosition = { diff --git a/frontend/src/components/instance-item/index.js b/frontend/src/components/instance-item/index.js new file mode 100644 index 00000000..c874ee1f --- /dev/null +++ b/frontend/src/components/instance-item/index.js @@ -0,0 +1,37 @@ +const React = require('react'); + +const MetricsOutlet = require('@components/metrics-outlet'); +const PropTypes = require('@root/prop-types'); +const List = require('@ui/components/list'); + +const { + ListItem, + ListItemView, + ListItemMeta, + ListItemTitle, + ListItemOptions +} = List; + +const InstanceItem = ({ + instance = {}, + toggleCollapsed = () => null +}) => ( + + + + {instance.name} + + + + + … + + +); + +InstanceItem.propTypes = { + instance: PropTypes.instance, + toggleCollapsed: React.PropTypes.func +}; + +module.exports = InstanceItem; \ No newline at end of file diff --git a/frontend/src/components/instance-list/index.js b/frontend/src/components/instance-list/index.js new file mode 100644 index 00000000..5662c827 --- /dev/null +++ b/frontend/src/components/instance-list/index.js @@ -0,0 +1,32 @@ +const React = require('react'); + +const InstanceItem = require('@components/instance-item'); +const PropTypes = require('@root/prop-types'); + +const InstanceList = ({ + instances = [], + toggleCollapsed = () => null +}) => { + const onClick = (uuid) => () => toggleCollapsed(uuid); + + const instanceList = instances.map((instance) => ( + + )); + + return ( +
+ {instanceList} +
+ ); +}; + +InstanceList.propTypes = { + instances: React.PropTypes.arrayOf(PropTypes.instance), + toggleCollapsed: React.PropTypes.func +}; + +module.exports = InstanceList; diff --git a/frontend/src/components/metrics-row/index.js b/frontend/src/components/metrics-outlet/index.js similarity index 70% rename from frontend/src/components/metrics-row/index.js rename to frontend/src/components/metrics-outlet/index.js index ff842e52..807f7a92 100644 --- a/frontend/src/components/metrics-row/index.js +++ b/frontend/src/components/metrics-outlet/index.js @@ -2,6 +2,7 @@ const React = require('react'); const Styled = require('styled-components'); const Column = require('@ui/components/column'); +const List = require('@ui/components/list'); const MiniMetric = require('@ui/components/mini-metric'); const PropTypes = require('@root/prop-types'); const Row = require('@ui/components/row'); @@ -18,6 +19,15 @@ const { MiniMetricView } = MiniMetric; +const { + ListItemOutlet +} = List; + +const StyledOutlet = styled(ListItemOutlet)` + padding-left: 0; + padding-right: 0; +`; + const StyledRow = styled(Row)` margin: 0; @@ -27,9 +37,11 @@ const StyledRow = styled(Row)` } `; -const MetricsRow = ({ - datasets = [] -}) => { +const MetricsOutlet = (props) => { + const { + datasets = [] + } = props; + const _datasets = datasets.map((metric, i) => ( @@ -43,14 +55,16 @@ const MetricsRow = ({ )); return ( - - {_datasets} - + + + {_datasets} + + ); }; -MetricsRow.propTypes = { +MetricsOutlet.propTypes = { datasets: React.PropTypes.arrayOf(PropTypes.dataset) }; -module.exports = MetricsRow; +module.exports = MetricsOutlet; diff --git a/frontend/src/components/service-item/index.js b/frontend/src/components/service-item/index.js index 3fe83741..6adb37c4 100644 --- a/frontend/src/components/service-item/index.js +++ b/frontend/src/components/service-item/index.js @@ -4,7 +4,7 @@ const ReactRouter = require('react-router'); const Anchor = require('@ui/components/anchor'); const List = require('@ui/components/list'); -const MetricsRow = require('@components/metrics-row'); +const MetricsOutlet = require('@components/metrics-outlet'); const PropTypes = require('@root/prop-types'); const { @@ -19,7 +19,6 @@ const { ListItemSubTitle, ListItemDescription, ListItemGroupView, - ListItemOutlet, ListItemOptions, ListItemHeader } = List; @@ -86,9 +85,7 @@ const ServiceItem = ({ {isChild && subtitle} {description} - - - + ); diff --git a/frontend/src/containers/project/instances.js b/frontend/src/containers/project/instances.js index dbb58acf..2909f1b5 100644 --- a/frontend/src/containers/project/instances.js +++ b/frontend/src/containers/project/instances.js @@ -1,9 +1,63 @@ const React = require('react'); +const ReactRedux = require('react-redux'); +const actions = require('@state/actions'); +const EmptyInstances = require('@components/empty/instances'); +const PropTypes = require('@root/prop-types'); const Section = require('./section'); +const InstanceList = require('@components/instance-list'); +const selectors = require('@state/selectors'); + +const { + toggleInstanceCollapsed +} = actions; + +const { + connect +} = ReactRedux; + +const { + instancesByProjectIdSelector +} = selectors; + +const Instances = (props) => { + const { + instances = [], + toggleCollapsed = () => null + } = props; + + const empty = instances.length ? null : ( + + ); + + return ( +
+ {empty} + +
+ ); +}; + +Instances.propTypes = { + instances: React.PropTypes.arrayOf(PropTypes.instance), + toggleCollapsed: React.PropTypes.func +}; + +const mapStateToProps = (state, { + params = {} +}) => ({ + instances: instancesByProjectIdSelector(params.projectId)(state) +}); + +const mapDispatchToProps = (dispatch) => ({ + toggleCollapsed: (uuid) => dispatch(toggleInstanceCollapsed(uuid)) +}); + +module.exports = connect( + mapStateToProps, + mapDispatchToProps +)(Instances); -module.exports = (props) => ( -
-

instances

-
-); diff --git a/frontend/src/containers/service/instances.js b/frontend/src/containers/service/instances.js index 6572c529..019d38d2 100644 --- a/frontend/src/containers/service/instances.js +++ b/frontend/src/containers/service/instances.js @@ -4,8 +4,7 @@ const ReactRedux = require('react-redux'); const actions = require('@state/actions'); const EmptyInstances = require('@components/empty/instances'); const PropTypes = require('@root/prop-types'); -const List = require('@ui/components/list'); -const DatasetsRow = require('@components/metrics-row'); +const InstanceList = require('@components/instance-list'); const selectors = require('@state/selectors'); const { @@ -20,45 +19,23 @@ const { instancesByServiceIdSelector } = selectors; -const { - ListItem, - ListItemView, - ListItemMeta, - ListItemTitle, - ListItemOptions, - ListItemOutlet -} = List; - -const Instances = ({ - instances = [], - toggleCollapsed = () => null -}) => { - const onClick = (uuid) => () => toggleCollapsed(uuid); +const Instances = (props) => { + const { + instances = [], + toggleCollapsed = () => null + } = props; const empty = instances.length ? null : ( ); - const instanceList = instances.map((instance) => ( - - - - {instance.name} - - - - - - - … - - - )); - return (
{empty} - {instanceList} +
); }; diff --git a/frontend/src/prop-types.js b/frontend/src/prop-types.js index c3422655..9908426d 100644 --- a/frontend/src/prop-types.js +++ b/frontend/src/prop-types.js @@ -44,11 +44,11 @@ const Dataset = React.PropTypes.shape({ type: React.PropTypes.string, data: React.PropTypes.arrayOf( React.PropTypes.shape({ - firstQuartile: React.PropTypes.string, - thirdQuartile: React.PropTypes.string, - median: React.PropTypes.string, - max: React.PropTypes.string, - min: React.PropTypes.string + firstQuartile: React.PropTypes.number, + thirdQuartile: React.PropTypes.number, + median: React.PropTypes.number, + max: React.PropTypes.number, + min: React.PropTypes.number }) ) }); diff --git a/frontend/src/state/selectors.js b/frontend/src/state/selectors.js index 27aa0201..7c154b3d 100644 --- a/frontend/src/state/selectors.js +++ b/frontend/src/state/selectors.js @@ -93,6 +93,16 @@ const metricsByServiceId = (serviceId) => createSelector( metricTypes.filter((i) => i.service === service.uuid) ); +const instancesByProjectId = (projectId) => createSelector( + [instances, projectById(projectId), collapsedInstances, metricDatasets], + (instances, project, collapsed, metrics) => + instances.filter((i) => i.project === project.uuid) + .map((instance) => ({ + ...instance, + metrics: datasets(metrics, instance.metrics), + collapsed: isCollapsed(collapsed, instance.uuid) + })) +); module.exports = { accountSelector: account, @@ -108,5 +118,6 @@ module.exports = { projectByIdSelector: projectById, servicesByProjectIdSelector: servicesByProjectId, instancesByServiceIdSelector: instancesByServiceId, - metricsByServiceIdSelector: metricsByServiceId + metricsByServiceIdSelector: metricsByServiceId, + instancesByProjectIdSelector: instancesByProjectId }; diff --git a/ui/.storybook/config.js b/ui/.storybook/config.js index 61c63a83..bb888c3a 100644 --- a/ui/.storybook/config.js +++ b/ui/.storybook/config.js @@ -6,11 +6,11 @@ function loadStories() { let stories = req.keys(); stories = stories.sort(); - stories.forEach( story => req(story)); + stories.forEach(story => req(story)); // Fallback to stories/index.js file for anything that // hasn't been moved require('../stories'); } -configure(loadStories, module); \ No newline at end of file +configure(loadStories, module); diff --git a/ui/package.json b/ui/package.json index 457f437a..99eaf728 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,8 +14,9 @@ "dependencies": { "build-array": "^1.0.0", "chart.js": "^2.4.0", - "chartjs-chart-box-plot": "^1.0.0-9", + "chartjs-chart-box-plot": "prerelease", "color": "^1.0.3", + "d3": "^4.4.1", "lodash.find": "^4.6.0", "lodash.first": "^3.0.0", "lodash.flatten": "^4.4.0", diff --git a/ui/src/components/add-metric/tile.js b/ui/src/components/add-metric/tile.js index 66e8e16d..50f60f39 100644 --- a/ui/src/components/add-metric/tile.js +++ b/ui/src/components/add-metric/tile.js @@ -28,7 +28,7 @@ const StyledTile = styled.div` width: ${remcalc(300)}; height: ${remcalc(247)}; box-shadow: ${boxes.bottomShaddow}; - border: 1px solid ${colors.borderSecondary}; + border: ${remcalc(1)} solid ${colors.borderSecondary}; background-color: ${colors.brandSecondary}; ${breakpoints.small` diff --git a/ui/src/components/base/index.js b/ui/src/components/base/index.js index efcc93e9..f0fd7f78 100644 --- a/ui/src/components/base/index.js +++ b/ui/src/components/base/index.js @@ -15,10 +15,10 @@ const { } = Styled; const { - generateFonts + generateFonts, + remcalc } = fncs; - // The name that will be used in the 'font-family' property const fontFamilies = [ 'LibreFranklin' @@ -156,7 +156,7 @@ module.exports = styled.div` } & figure { - margin: 1em 40px; + margin: 1em ${remcalc(40)}; } & hr { @@ -208,12 +208,12 @@ module.exports = styled.div` & [type="button"]:-moz-focusring, & [type="reset"]:-moz-focusring, & [type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; + outline: ${remcalc(1)} dotted ButtonText; } & fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; + border: ${remcalc(1)} solid #c0c0c0; + margin: 0 ${remcalc(2)}; padding: 0.35em 0.625em 0.75em; } @@ -245,7 +245,7 @@ module.exports = styled.div` & [type="search"] { -webkit-appearance: textfield; - outline-offset: -2px; + outline-offset: ${remcalc(-2)}; } & [type="search"]::-webkit-search-cancel-button, @@ -302,7 +302,7 @@ module.exports = styled.div` & abbr[title], & abbr[data-original-title] { cursor: help; - border-bottom: 1px dotted ${typography.abbrBorderColor}; + border-bottom: ${remcalc(1)} dotted ${typography.abbrBorderColor}; } & address { @@ -352,8 +352,8 @@ module.exports = styled.div` } &:focus { - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; + outline: ${remcalc(5)} auto -webkit-focus-ring-color; + outline-offset: ${remcalc(-2)}; } } @@ -444,8 +444,8 @@ module.exports = styled.div` } & button:focus { - outline: 1px dotted; - outline: 5px auto -webkit-focus-ring-color; + outline: ${remcalc(1)} dotted; + outline: ${remcalc(5)} auto -webkit-focus-ring-color; } & input, diff --git a/ui/src/components/button/index.js b/ui/src/components/button/index.js index cf45c79d..7fa255d2 100644 --- a/ui/src/components/button/index.js +++ b/ui/src/components/button/index.js @@ -56,7 +56,7 @@ const color = match({ const borderRadius = match({ rect: 0 -}, remcalc(boxes.borderRadius)); +}, boxes.borderRadius); // based on bootstrap 4 const style = css` @@ -96,7 +96,7 @@ const style = css` background-image: none; background-color: ${background}; border-radius: ${borderRadius}; - border: solid 1px ${border}; + border: solid ${remcalc(1)} ${border}; box-shadow: ${boxes.bottomShaddow}; @@ -104,12 +104,12 @@ const style = css` outline: 0; text-decoration: none; background-color: ${background}; - border: solid 1px ${border}; + border: solid ${remcalc(1)} ${border}; } &:hover { background-color: ${backgroundHover}; - border: solid 1px ${borderHover}; + border: solid ${remcalc(1)} ${borderHover}; } &:active, @@ -119,7 +119,7 @@ const style = css` outline: 0; background-color: ${backgroundActive}; - border: solid 1px ${borderActive}; + border: solid ${remcalc(1)} ${borderActive}; } &[disabled] { diff --git a/ui/src/components/checkbox/index.js b/ui/src/components/checkbox/index.js index 311c4960..15b0ce48 100644 --- a/ui/src/components/checkbox/index.js +++ b/ui/src/components/checkbox/index.js @@ -1,11 +1,16 @@ -const React = require('react'); const constants = require('../../shared/constants'); +const fns = require('../../shared/functions'); +const React = require('react'); const Styled = require('styled-components'); const { boxes } = constants; +const { + remcalc +} = fns; + const { default: styled, } = Styled; @@ -26,8 +31,8 @@ const StyledInput = styled.input` const StyledLabel = styled.label` color: rgb(100, 100, 100); position: absolute; - width: 24px; - height: 24px; + width: ${remcalc(24)}; + height: ${remcalc(24)}; top: 0; border-radius: ${boxes.borderRadius}; background-color: rgb(255, 255, 255); @@ -38,12 +43,12 @@ const StyledLabel = styled.label` opacity: 0; content: ''; position: absolute; - width: 9px; - height: 4px; + width: ${remcalc(9)}; + height: ${remcalc(4)}; background: transparent; - top: 7px; - left: 7px; - border: 3px solid #333; + top: ${remcalc(7)}; + left: ${remcalc(7)}; + border: ${remcalc(3)} solid #333; border-top: none; border-right: none; transform: rotate(-45deg); @@ -57,8 +62,8 @@ const StyledLabel = styled.label` `; const StyledDiv = styled.div` - width: 24px; - height: 24px; + width: ${remcalc(24)}; + height: ${remcalc(24)}; position: relative; `; diff --git a/ui/src/components/close/index.js b/ui/src/components/close/index.js index bc955fe9..07658740 100644 --- a/ui/src/components/close/index.js +++ b/ui/src/components/close/index.js @@ -17,14 +17,18 @@ const StyledButton = styled.button` position: absolute; top: ${remcalc(16)}; right: ${remcalc(16)}; + + ${props => props.customStyles ? props.customStyles : null} `; const Close = ({ style, - onClick + onClick, + customStyles = '' }) => { return ( @@ -37,6 +41,7 @@ const Close = ({ }; Close.propTypes = { + customStyles: React.PropTypes.string, onClick: React.PropTypes.func, style: React.PropTypes.object }; diff --git a/ui/src/components/h1/index.js b/ui/src/components/h1/index.js index 1d0a3319..bd216017 100644 --- a/ui/src/components/h1/index.js +++ b/ui/src/components/h1/index.js @@ -15,5 +15,5 @@ module.exports = styled.h1` font-style: normal; font-stretch: normal; color: #364acd; - border-bottom: 1px solid #d8d8d8; + border-bottom: ${remcalc(1)} solid #d8d8d8; `; diff --git a/ui/src/components/input/index.js b/ui/src/components/input/index.js index 81b89968..d9120564 100644 --- a/ui/src/components/input/index.js +++ b/ui/src/components/input/index.js @@ -25,9 +25,9 @@ const { const successBakcground = css` background-color: ${colors.brandSecondary}; - background-image: url("./input-confirm.svg"); + background-image: url('./input-confirm.svg'); background-repeat: no-repeat; - background-position: 98% 20px; + background-position: 98% ${remcalc(20)}; `; const defaultBackground = css` @@ -40,17 +40,17 @@ const Label = styled.label` const InputField = styled.input` ${baseBox()}; - + ${props => props.success ? successBakcground : defaultBackground } - + border-color: ${props => props.error ? colors.alert : 'auto'} color: ${props => props.error ? colors.alert : colors.fonts.semibold} display: block; - font-size: 16px; + font-size: ${remcalc(16)}; padding: ${remcalc('15 18')}; visibility: visible; width: 100%; - + &:focus { border-color: ${boxes.border.checked}; outline: none; diff --git a/ui/src/components/list/header.js b/ui/src/components/list/header.js index 3d022475..c59a6f39 100644 --- a/ui/src/components/list/header.js +++ b/ui/src/components/list/header.js @@ -20,7 +20,7 @@ const StyledItem = styled(Item)` position: absolute; background-color: ${colors.brandPrimary}; - border: solid 1px ${colors.borderPrimary}; + border: solid ${remcalc(1)} ${colors.borderPrimary}; box-shadow: none; width: calc(100% + ${remcalc(2)}); diff --git a/ui/src/components/list/item.js b/ui/src/components/list/item.js index 28d3563c..d11b6d52 100644 --- a/ui/src/components/list/item.js +++ b/ui/src/components/list/item.js @@ -19,10 +19,10 @@ const { } = Styled; const paper = ` - 0 8px 0 -5px #fafafa, - 0 8px 1px -4px ${colors.borderSecondary}, - 0 16px 0 -10px #fafafa, - 0 16px 1px -9px ${colors.borderSecondary}; + 0 ${remcalc(8)} 0 ${remcalc(-5)} #fafafa, + 0 ${remcalc(8)} ${remcalc(1)} ${remcalc(-4)} ${colors.borderSecondary}, + 0 ${remcalc(16)} 0 ${remcalc(-10)} #fafafa, + 0 ${remcalc(16)} ${remcalc(1)} ${remcalc(-9)} ${colors.borderSecondary}; `; const height = (props) => props.collapsed @@ -52,7 +52,7 @@ const Item = styled(Row)` height: ${height}; min-height: ${minHeight}; box-shadow: ${shadow}; - border: 1px solid ${colors.borderSecondary}; + border: ${remcalc(1)} solid ${colors.borderSecondary}; background-color: ${colors.brandSecondary}; margin-bottom: ${marginBottom}; `; diff --git a/ui/src/components/list/options.js b/ui/src/components/list/options.js index 6f8f0f90..39807a72 100644 --- a/ui/src/components/list/options.js +++ b/ui/src/components/list/options.js @@ -27,7 +27,7 @@ const borderLeftColor = (props) => !props.fromHeader const Nav = styled.nav` flex: 0 0 ${remcalc(47)}; - border-left: 1px solid ${borderLeftColor}; + border-left: ${remcalc(1)} solid ${borderLeftColor}; `; const StyledButton = styled(Button)` diff --git a/ui/src/components/list/subtitle.js b/ui/src/components/list/subtitle.js index dda0c90c..99cb05b2 100644 --- a/ui/src/components/list/subtitle.js +++ b/ui/src/components/list/subtitle.js @@ -35,7 +35,7 @@ const Span = styled.span` font-weight: normal; font-style: normal; font-stretch: normal; - font-size: 14px; + font-size: ${remcalc(14)}; color: ${color}; justify-content: flex-end; diff --git a/ui/src/components/modal/index.js b/ui/src/components/modal/index.js index 9649e705..66eeb0f6 100644 --- a/ui/src/components/modal/index.js +++ b/ui/src/components/modal/index.js @@ -1,11 +1,19 @@ +const fns = require('../../shared/functions'); + const constants = require('../../shared/constants'); const React = require('react'); const Styled = require('styled-components'); +const Close = require('../close'); + const { colors } = constants; +const { + remcalc +} = fns; + const { default: styled } = Styled; @@ -15,31 +23,17 @@ const StyledModal = styled.div` display: block; left: 50%; margin: 0 auto; - padding: 20px; + padding: ${remcalc(20)}; position: absolute; top: 50%; transform: translate(-50%, -50%); z-index: 1; -`; - -const StyledClose = styled.button` - background-color: #FFFFFF; - border: solid 1px #D8D8D8; - border-radius: 4px; - box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.05); - color: black; - cursor: #000000; - font-size: 20px; - padding: 0 10px; - position: absolute; - right: -20px; - text-align: center; - text-decoration: none; - top: -15px; + max-width: 80%; + min-width: 50%; `; const StyledOverlay = styled.div` - background: rgba(0, 0, 0, 0.4); + background: rgba(74, 73, 74, 0.46); height: 100%; left: 0; position: absolute; @@ -52,6 +46,7 @@ const Modal = ({ active = true, children, className, + customCloseStyle, handleDismiss, name, style @@ -68,11 +63,10 @@ const Modal = ({ tabIndex={-2} /> - X + /> {children} @@ -83,6 +77,7 @@ Modal.propTypes = { active: React.PropTypes.bool, children: React.PropTypes.node, className: React.PropTypes.string, + customCloseStyle: React.PropTypes.string, handleDismiss: React.PropTypes.func, name: React.PropTypes.string, style: React.PropTypes.object diff --git a/ui/src/components/modal/story.js b/ui/src/components/modal/story.js index 74a142fc..c1f586c9 100644 --- a/ui/src/components/modal/story.js +++ b/ui/src/components/modal/story.js @@ -1,5 +1,15 @@ +const constants = require('../../shared/constants'); +const fns = require('../../shared/functions'); const React = require('react'); +const { + colors +} = constants; + +const { + remcalc +} = fns; + const { storiesOf } = require('@kadira/storybook'); @@ -7,6 +17,11 @@ const { const Base= require('../base'); const Modal = require('./'); +const _customCloseStyle = ` + border: solid ${colors.alert} ${remcalc(5)}; + border-radius: 50%; +`; + storiesOf('Modal', module) .add('Default', () => ( @@ -14,4 +29,18 @@ storiesOf('Modal', module)

This is the Modal

+ )) + .add('Custom Styles on Close', () => ( + + +

This is the Modal

+
+ + )) + .add('Dismiss Function', () => ( + + +

This has a handleDismiss (noop) function

+
+ )); \ No newline at end of file diff --git a/ui/src/components/pagination/index.js b/ui/src/components/pagination/index.js index 352efc37..ca69b1fb 100644 --- a/ui/src/components/pagination/index.js +++ b/ui/src/components/pagination/index.js @@ -13,7 +13,8 @@ const { } = constants; const { - rndId + rndId, + remcalc } = fns; const { @@ -36,12 +37,12 @@ const StyledLi = styled.li` cursor: pointer; display: flex; float: left; - height: 50px; + height: ${remcalc(50)}; justify-content: center; - margin-right: 10px; - min-width: 50px; - padding-left: 15px; - padding-right: 15px; + margin-right: ${remcalc(10)}; + min-width: ${remcalc(50)}; + padding-left: ${remcalc(15)}; + padding-right: ${remcalc(15)}; position: relative; ${baseBox()} diff --git a/ui/src/components/radio-group/item.js b/ui/src/components/radio-group/item.js index 565048d5..98177329 100644 --- a/ui/src/components/radio-group/item.js +++ b/ui/src/components/radio-group/item.js @@ -35,7 +35,7 @@ const RadioItem = styled.div` &[aria-checked="true"] { border: ${boxes.border.checked}; - box-shadow: ${remcalc(boxes.borderRadius)}; + box-shadow: ${boxes.borderRadius}; } &.disabled { diff --git a/ui/src/components/radio/index.js b/ui/src/components/radio/index.js index 62154afe..8c57492c 100644 --- a/ui/src/components/radio/index.js +++ b/ui/src/components/radio/index.js @@ -46,12 +46,12 @@ const StyledSpan = styled.span` &::before { content: ''; position: absolute; - width: 10px; - height: 10px; - box-shadow: 0 0 0 1px #646464; - border: 8px solid ${colors.brandInactive}; - top: 5px; - left: 5px; + width: ${remcalc(10)}; + height: ${remcalc(10)}; + box-shadow: 0 0 0 ${remcalc(1)} #646464; + border: ${remcalc(8)} solid ${colors.brandInactive}; + top: ${remcalc(5)}; + left: ${remcalc(5)}; border-radius: 100%; } diff --git a/ui/src/components/range-slider/index.js b/ui/src/components/range-slider/index.js index 8a2a7104..0373bb59 100644 --- a/ui/src/components/range-slider/index.js +++ b/ui/src/components/range-slider/index.js @@ -38,7 +38,7 @@ const rangeThumb = css` cursor: pointer; height: ${remcalc(24)}; position: relative; - top: -10px; + top: ${remcalc(-10)}; width: ${remcalc(36)}; ${baseBox()} @@ -46,7 +46,7 @@ const rangeThumb = css` const rangeLower = css` background: ${colors.brandPrimary}; - height: 6px; + height: ${remcalc(6)}; ${baseBox({ radius: remcalc(50), @@ -56,7 +56,7 @@ const rangeLower = css` const rangeUpper = css` background: #E6E6E6; - height: 6px; + height: ${remcalc(6)}; ${baseBox({ radius: remcalc(50) diff --git a/ui/src/components/select/index.js b/ui/src/components/select/index.js index 5f33b49a..f9d4dde5 100644 --- a/ui/src/components/select/index.js +++ b/ui/src/components/select/index.js @@ -26,27 +26,27 @@ const SelectWrapper = styled.div` display: inline-block; &:after { - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-bottom: 5px solid black; + border-left: ${remcalc(5)} solid transparent; + border-right: ${remcalc(5)} solid transparent; + border-bottom: ${remcalc(5)} solid black; ${pseudoEl({ - top: '25px', - right: '20px' + top: remcalc(25), + right: remcalc(20) })} } `; const StyledSelect = styled.select` - font-size:16px; + font-size: ${remcalc(16)}; min-width: ${remcalc(288)}; min-height: ${remcalc(54)}; - border-radius: 4px; + border-radius: ${remcalc(4)}; padding-left: ${remcalc(20)}; background-color: #FFFFFF; - box-shadow: inset 0 3px 0 0 rgba(0, 0, 0, 0.05); - border: solid 1px #D8D8D8; + box-shadow: inset 0 ${remcalc(3)} 0 0 rgba(0, 0, 0, 0.05); + border: solid ${remcalc(1)} #D8D8D8; -webkit-appearance: none; &:before { diff --git a/ui/src/components/tabs/tab/index.js b/ui/src/components/tabs/tab/index.js index ab417de1..2aa1e567 100644 --- a/ui/src/components/tabs/tab/index.js +++ b/ui/src/components/tabs/tab/index.js @@ -34,9 +34,9 @@ const StyledTab = styled.div` const StyledRadio = styled.input` clip: rect(0 0 0 0); - height: 1px; + height: ${remcalc(1)}; opacity: 0; - width: 1px; + width: ${remcalc(1)}; ${moveZ({ position: 'fixed', @@ -61,7 +61,7 @@ const StyledRadio = styled.input` const StyledLabel = styled.label` background: transparent; - border: 1px solid #D8D8D8; + border: ${remcalc(1)} solid #D8D8D8; display: inline-block; font-size: ${remcalc(20)}; padding: ${remcalc('12 25')}; @@ -81,7 +81,7 @@ const StyledContent = styled.div` background: ${colors.brandInactive}; border: ${boxes.border.unchecked}; box-sizing: border-box; - box-shadow: 0 -1px 26px 0 rgba(0, 0, 0, 0.2); + box-shadow: 0 ${remcalc(-1)} ${remcalc(26)} 0 rgba(0, 0, 0, 0.2); display: block; float: left; font-size: ${remcalc(16)}; diff --git a/ui/src/components/textarea/index.js b/ui/src/components/textarea/index.js index b7b0f0ad..f11d8aaa 100644 --- a/ui/src/components/textarea/index.js +++ b/ui/src/components/textarea/index.js @@ -30,14 +30,14 @@ const InputField = styled.textarea` background: ${colors.brandSecondary}; color: ${props => props.error ? colors.alert : colors.fonts.semibold} display: block; - font-size: 16px; + font-size: ${remcalc(16)}; padding: ${remcalc('15 18')}; visibility: visible; width: 100%; min-height: ${remcalc(96)}; ${baseBox()}; border-color: ${props => props.error ? colors.alert : ''}; - + &:focus { border-color: ${boxes.border.checked}; outline: none; diff --git a/ui/src/components/toggle/index.js b/ui/src/components/toggle/index.js index d50bc992..b32b9de9 100644 --- a/ui/src/components/toggle/index.js +++ b/ui/src/components/toggle/index.js @@ -30,7 +30,7 @@ const StyledText = styled.span` const StyledDiv = styled.div` display: inline-block; background-color: ${colors.brandInactive}; - + ${baseBox()} `; @@ -46,17 +46,18 @@ const StyledInput0 = styled.input` display: none; & + span { - background: linear-gradient(to right, - transparent 50%, + background: linear-gradient(to right, + transparent 50%, ${colors.brandSecondary} 50%); background-position: left bottom; - box-shadow: inset -7px 0 9px -7px rgba(0,0,0,0.4); - + box-shadow: inset + ${remcalc(-7)} 0 ${remcalc(9)} ${remcalc(-7)} + rgba(0,0,0,0.4); + ${inputStyled} } - + &:checked { - & + span { background-position: right bottom; } @@ -66,17 +67,16 @@ const StyledInput0 = styled.input` const StyledInput1 = styled.input` display: none; - & + span { - background: linear-gradient(to right, - ${colors.brandSecondary} 50%, + & + span { + background: linear-gradient(to right, + ${colors.brandSecondary} 50%, transparent 50%); background-position: right bottom; - + ${inputStyled} } - + &:checked { - & + span { background-position: left bottom; } diff --git a/ui/src/components/tooltip/index.js b/ui/src/components/tooltip/index.js index 7d0c40bd..cb4ab090 100644 --- a/ui/src/components/tooltip/index.js +++ b/ui/src/components/tooltip/index.js @@ -56,14 +56,14 @@ const StyledList = styled.ul` &:after { border-color: rgba(255, 255, 255, 0); border-bottom-color: #fff; - border-width: 10px; - margin-left: -10px; + border-width: ${remcalc(10)}; + margin-left: ${remcalc(-10)}; } &:before { border-color: rgba(216, 216, 216, 0); border-bottom-color: #d8d8d8; - border-width: 12px; - margin-left: -12px; + border-width: ${remcalc(12)}; + margin-left: ${remcalc(-12)}; } `; module.exports = ({ diff --git a/ui/src/components/topology/index.js b/ui/src/components/topology/index.js new file mode 100644 index 00000000..5a8114e8 --- /dev/null +++ b/ui/src/components/topology/index.js @@ -0,0 +1,425 @@ +const constants = require('../../shared/constants'); +const d3 = require('d3'); +const fns = require('../../shared/functions'); +const React = require('react'); +const Styled = require('styled-components'); + +const { + colors +} = constants; + +const { + remcalc +} = fns; + +const { + default: styled +} = Styled; + +/* eslint-disable */ +function rightRoundedRect(x, y, width, height, radius) { + return 'M' + x + ',' + y // Move to top left (absolute) + + 'h ' + (width - 2 * radius) // Horizontal line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + radius + ',' + radius // Relative arc + + 'v ' + (height - 2 * radius) // Vertical line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + -radius + ',' + radius // Relative arch + + 'h ' + (2 * radius - width) // Horizontal lint to (relative) + + 'z '; // path back to start +} +/* eslint-enable */ + +/* eslint-disable */ +function leftRoundedRect(x, y, width, height, radius) { + return 'M' + (x + width) + ',' + y // Move to (absolute) start at top-right + + 'v ' + height // Vertical line to (relative) + + 'h ' + (2 * radius - width) // Horizontal line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + -radius + ',' + -radius // Relative arc + + 'v ' + -(height - 2 * radius) // Vertical line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + radius + ',' + -radius // Relative arch + + 'z '; // path back to start +} +/* eslint-enable */ + +function topRoundedRect(x, y, width, height, radius) { + return 'M' + x + ',' + -(y - height) // Move to (absolute) start at bottom-left + + 'v ' + -(height - radius) // Vertical line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + radius + ',' + -radius // Relative arc + + 'h ' + -(2 * radius - width) // Horizontal line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + radius + ',' + radius // Relative arc + + 'v ' + (height - radius) // Vertical line to (relative) + + 'h ' + (2 * radius - width) // Horizontal line to (relative) + + 'z '; // path back to start +} + +function bottomRoundedRect(x, y, width, height, radius) { + return 'M' + x + ',' + -(y - (height - 2 * radius)) // Move to (absolute) start at bottom-right + + 'v ' + -(height - 2 * radius) // Vertical line to (relative) + + 'h ' + (width) // Horizontal line to (relative) + + 'v ' + (height - 2 * radius) // Vertical line to (relative) + + 'a ' + -radius + ',' + radius + ' 0 0 1 ' + -radius + ',' + radius // Relative arc + + 'h ' + (2 * radius - width) // Horizontal line to (relative) + + 'a ' + radius + ',' + radius + ' 0 0 1 ' + -radius + ',' + -radius // Relative arc + + 'z '; // path back to start +} + +/* eslint-disable */ +function rect(x, y, width, height) { + return 'M' + x + ',' + -(y - height) // Move to (absolute) start at bottom-right + + 'v ' + -(height) // Vertical line to (relative) + + 'h ' + width // Horizontal line to (relative) + + 'v ' + height // Vertical line to (relative) + + 'h ' + -(width) // Horizontal line to (relative) + + 'z '; // path back to start +} +/* eslint-enable */ + +const StyledSVGContainer = styled.svg` + & { + .links line { + stroke: #343434; + stroke-opacity: 1; + } + + .health, .health_warn { + font-family: "Libre Franklin"; + font-size: ${remcalc(12)}; + font-weight: bold; + font-style: normal; + font-stretch: normal; + text-align: center; + } + + .health_warn { + font-size: ${remcalc(15)}; + } + + .stat { + font-family: "Libre Franklin"; + font-size: ${remcalc(12)}; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: 1.5; + } + + .node_statistics { + font-family: "Libre Franklin"; + font-size: ${remcalc(12)}; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: 1.5; + } + + .node_statistics p { + margin: 0 0 0 0; + color: rgba(255, 255, 255, 0.8); + } + + .primary, .secondary { + font-family: "Libre Franklin"; + font-size: ${remcalc(12)}; + font-weight: normal; + font-style: normal; + font-stretch: normal; + line-height: 1.5; + } + + .info_text { + font-family: "Libre Franklin"; + font-size: ${remcalc(16)}; + font-weight: 600; + font-style: normal; + font-stretch: normal; + line-height: 1.5; + } + } +`; + +class TopologyGraph extends React.Component { + constructor(props) { + super(props); + + this.svg = null; + + const { + width, + height, + } = props; + + this.simulation = d3.forceSimulation() + .force('charge', d3.forceManyBody() + .strength(() => -50) + .distanceMin(() => 30)) + .force('link', d3.forceLink().distance(() => 200).id((d) => d.id)) + // TODO manually handle looking for collisions in the tick, we then get the BBox + // and keep moving things for a while to try to get a fit. + .force('collide', + d3.forceCollide().radius((d) => 220 + 0.5).iterations(15)) + .force('center', d3.forceCenter(width * 1/3, height * 1/3)); + } + + componentDidMount() { + const component = this; + + const { + simulation, + } = this; + + const svg = d3.select(this._refs.svg); + const { + width, + height, + graph = { + nodes: [], + links: [] + }, + } = this.props; + + // Drawing the links between nodes + const link = svg.append('g') + .attr('class', 'links') + .selectAll('line') + .data(graph.links) + .enter().append('line') + .attr('stroke-width', remcalc(12)); + + // And svg group, to contain all of the attributes in @antonas' first prototype + svg.selectAll('.node') + .data(graph.nodes) + .enter() + .append('g') + .attr('class', 'node_group'); + + svg.selectAll('.node_group').each(function(d) { + // Create different type of node for services with Primaries + Secondaries + // We could extend this further to allow us to have as many nested services + // as wanted. + // TODO handle this per prop + // if (d.id === 'Percona') { + // createExtendedNode(d3.select(this)); + // } else { + component.createServiceNodes(d, d3.select(this)); + // } + }); + + simulation + .nodes(graph.nodes) + .on('tick', ticked); + + simulation.force('link') + .links(graph.links); + + function contrain(dimension, r, z) { + return Math.max(0, Math.min(dimension - r, z)); + } + + function ticked() { + // TODO: Think of a common way of extracting the bounding boxes for each + // item and to grab the x{1,2} and y{1,2} values. + link + .attr('x1', function(d) { + let x; + svg.selectAll('.node_group').each(function(_, i) { + if (i !== d.source.index) return; + x = d3.select(this).node().getBBox().width; + }); + return contrain(width, x, d.source.x) + 80; + }) + .attr('y1', function(d) { + let y; + svg.selectAll('.node_group').each(function(_, i) { + if (i !== d.source.index) return; + y = d3.select(this).node().getBBox().height; + }); + return contrain(height, y, d.source.y) + 24; + }) + .attr('x2', function(d) { + let x; + svg.selectAll('.node_group').each(function(_, i) { + if (i !== d.target.index) return; + x = d3.select(this).node().getBBox().width; + }); + return contrain(width, x, d.target.x) + 80; + }) + .attr('y2', function(d) { + let y; + svg.selectAll('.node_group').each(function(_, i) { + if (i !== d.target.index) return; + y = d3.select(this).node().getBBox().height; + }); + return contrain(height, y, d.target.y) + 24; + }); + + svg.selectAll('.node_group') + .attr('transform', function(d) { + const x = d3.select(this).node().getBBox().width; + const y = d3.select(this).node().getBBox().height; + return 'translate(' + contrain(width, x, d.x) + ',' + + contrain(height, y, d.y) + ')'; + }); + } + } + + createHealthCheckBadge(element, x, y) { + const paddingLeft = 30; + const health = element.append('g'); + + // TODO: replace these element with the designed SVG elements from + // @antonasdeduchovas' designs with full svg elements. + + health.append('circle') + .attr('class', 'alert') + .attr('cx', function() { + return element + .node() + .getBBox() + .width + paddingLeft; + }) + .attr('cy', '24') + .attr('stroke-width', 0) + .attr('fill', (d) => + d.id === 'Memcached' ? 'rgb(217, 77, 68)' : 'rgb(0,175,102)') + .attr('r', remcalc(9)); + + // An icon or label that exists within the circle, inside the infobox + health.append('text') + .attr('class', 'health') + .attr('x', function() { + return element + .node() + .getBBox() + .width + 3; + }) + .attr('y', '29') + .attr('text-anchor', 'middle') + .attr('fill', colors.brandPrimaryColor) + .text((d) => d.id === 'Memcached' ? '!' : '❤'); + } + + createServiceNodeBody(data, element, d) { + const stats = element.append('g'); + stats.append('path') + .attr('class', 'node') + .attr('d', d) + .attr('stroke', '#343434') + .attr('stroke-width', remcalc(1)) + .attr('fill', '#464646'); + + const html = stats + .append('switch') + .append('foreignObject') + .attr('requiredFeatures', + 'http://www.w3.org/TR/SVG11/feature#Extensibility') + .attr('x', 12) + .attr('y', 57) + .attr('width', 160) + .attr('height', 70) + // From here everything will be rendered with react using a ref. + // However for now these values are hard-coded. + .append('xhtml:div') + .attr('class', 'node_statistics'); + // Remove with react + dyanmic data. + + html.selectAll('.node_statistics').data(data.metrics).enter() + .append('p') + .text((d) => `${d.name}: ${d.stat}`); + } + + createServiceNodes(data, elm) { + const component = this; + + const { + dragged, + dragstarted, + dragended, + } = this; + + const width = 170; + const topHeight = 47; + const radius = 4; + + // Box where label will live + elm.append('path') + .attr('class', 'node') + .attr('d', topRoundedRect('0', '0', width, topHeight, radius)) + .attr('stroke', colors.topologyBackground) + .attr('stroke-width', remcalc(1)) + .attr('fill', colors.brandSecondaryColor); + + const text = elm.append('g'); + + text.append('text') + .attr('class', 'info_text') + .attr('x', '12') + .attr('y', '30') + .attr('text-anchor', 'start') + .attr('fill', colors.brandPrimaryColor) + .text(d => d.id); + + // if (service is registered twice in the scheduler) { + // Do not show healthcheck in the header + // } else { + this.createHealthCheckBadge(text); + // } + + // if (service is registered twice in the scheduler) { + // this.createServiceNodeBody(data, elm, rect('0',`-${topHeight}`, width, 78, 4)); + // } else { + this.createServiceNodeBody(data, elm, + bottomRoundedRect('0', `-${topHeight}`, width, 78, 4)); + // } + + // <==== END ====> + + // Set up movement for service nodes + elm.call(d3.drag() + .on('start', dragstarted.bind(component)) + .on('drag', dragged.bind(component)) + .on('end', dragended.bind(component))); + } + + + dragstarted(d) { + if (!d3.event.active) this.simulation.alphaTarget(0.3).restart(); + d.fx = d.x; + d.fy = d.y; + } + + dragged(d) { + d.fx = d3.event.x; + d.fy = d3.event.y; + } + + dragended(d) { + if (!d3.event.active) this.simulation.alphaTarget(0); + d.fx = null; + d.fy = null; + } + + ref(name) { + this._refs = this._refs || {}; + + return (el) => { + this._refs[name] = el; + }; + } + + render() { + return ( + + ); + } + +} + +TopologyGraph.propTypes = { + graph: React.PropTypes.object, + height: React.PropTypes.number, + width: React.PropTypes.number, +}; + +module.exports = TopologyGraph; diff --git a/ui/src/components/topology/story.js b/ui/src/components/topology/story.js new file mode 100644 index 00000000..f6710b78 --- /dev/null +++ b/ui/src/components/topology/story.js @@ -0,0 +1,154 @@ +const React = require('react'); + +const { + storiesOf +} = require('@kadira/storybook'); + +const Base = require('../base'); +const Topology = require('./'); +const TopologyView = require('./view'); +const services = { + nodes: [ + { + id: 'Nginx', + attrs: { + dcs: 1, + instances: 2, + healthy: true, + }, + metrics: [ + { + name: 'CPU', + stat: '50%', + }, + { + name: 'Memory', + stat: '20%', + }, + { + name: 'Network', + stat: '5.9KB/sec', + }, + ] + }, + { + id: 'WordPress', + attrs: { + dcs: 1, + instances: 2, + healthy: true, + }, + metrics: [ + { + name: 'CPU', + stat: '50%', + }, + { + name: 'Memory', + stat: '20%', + }, + { + name: 'Network', + stat: '5.9KB/sec', + }, + ] + }, + { + id: 'Memcached', + attrs: { + dcs: 1, + instances: 2, + healthy: true, + }, + metrics: [ + { + name: 'CPU', + stat: '50%', + }, + { + name: 'Memory', + stat: '20%', + }, + { + name: 'Network', + stat: '5.9KB/sec', + }, + ] + }, + { + id: 'Percona', + attrs: { + dcs: 1, + instances: 2, + healthy: true, + }, + metrics: [ + { + name: 'CPU', + stat: '50%', + }, + { + name: 'Memory', + stat: '20%', + }, + { + name: 'Network', + stat: '5.9KB/sec', + }, + ] + }, + { + id: 'NFS', + attrs: { + dcs: 1, + instances: 2, + healthy: true, + }, + metrics: [ + { + name: 'CPU', + stat: '50%', + }, + { + name: 'Memory', + stat: '20%', + }, + { + name: 'Network', + stat: '5.9KB/sec', + }, + ] + } + ], + links: [ + { + source: 'Nginx', + target: 'WordPress', + }, + { + source: 'WordPress', + target: 'Memcached', + }, + { + source: 'WordPress', + target: 'NFS', + }, + { + source: 'WordPress', + target: 'Percona', + } + ] +}; + +storiesOf('Topology', module) + .add('5 services', () => ( + + + + + + )); diff --git a/ui/src/components/topology/view.js b/ui/src/components/topology/view.js new file mode 100644 index 00000000..83aba5b5 --- /dev/null +++ b/ui/src/components/topology/view.js @@ -0,0 +1,33 @@ +const constants = require('../../shared/constants'); +const fns = require('../../shared/functions'); +const React = require('react'); +const Styled = require('styled-components'); + +const { + colors +} = constants; + +const { + remcalc +} = fns; + +const { + default: styled +} = Styled; + +const TopologyView = styled.div` + border: ${remcalc(1)} solid ${colors.borderSecondary}; + background-color: ${colors.brandSecondary}; +`; + +const Topology = (props) => ( + + {props.children} + +); + +Topology.propTypes = { + children: React.PropTypes.node, +}; + +module.exports = Topology; diff --git a/ui/src/components/widget/index.js b/ui/src/components/widget/index.js index cedf32d9..377619d4 100644 --- a/ui/src/components/widget/index.js +++ b/ui/src/components/widget/index.js @@ -8,7 +8,8 @@ const { } = constants; const { - rndId + rndId, + remcalc } = fns; const { @@ -40,7 +41,7 @@ const StyledInput = styled.input` const StyledContent = styled.div` border: ${boxes.border.unchecked}; - border-radius: 4px; + border-radius: ${remcalc(4)}; cursor: pointer; padding: remcalc(36); diff --git a/ui/src/index.js b/ui/src/index.js index 89758ed4..bd8efb81 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -23,6 +23,7 @@ module.exports = { Tab: require('./components/tabs/tab'), Tabs: require('./components/tabs'), Toggle: require('./components/toggle'), + Topology: require('./components/topology'), Tooltip: require('./components/tooltip'), Textarea: require('./components/textarea'), Widget: require('./components/widget'), diff --git a/ui/src/shared/constants/baseunits.js b/ui/src/shared/constants/baseunits.js new file mode 100644 index 00000000..4b8e9765 --- /dev/null +++ b/ui/src/shared/constants/baseunits.js @@ -0,0 +1,12 @@ +// WIP - possibly create a function like spacerXL, spacerS, spacerM for things lik +// padding, margins, widths + +const baseunit = { + xs: 3, + s: 6, + m: 12, + l: 18, + xl: 24 +}; + +module.exports = baseunit; diff --git a/ui/src/shared/constants/boxes.js b/ui/src/shared/constants/boxes.js index ca0852c6..532d1f43 100644 --- a/ui/src/shared/constants/boxes.js +++ b/ui/src/shared/constants/boxes.js @@ -1,15 +1,18 @@ const colors = require('./colors'); +const fns = require('../functions'); -const boxes = { - borderRadius: '4px', - bottomShaddow: '0 2px 0 0 rgba(0, 0, 0, 0.05)', - bottomShaddowDarker: '0 2px 0 0 rgba(0, 0, 0, 0.1)', - insetShaddow: 'inset 0 3px 0 0 rgba(0, 0, 0, 0.05)', +const { + remcalc +} = fns; + +module.exports = { + borderRadius: remcalc(4), + bottomShaddow: `0 ${remcalc(2)} 0 0 rgba(0, 0, 0, 0.05)`, + bottomShaddowDarker: `0 ${remcalc(2)} 0 0 rgba(0, 0, 0, 0.1)`, + insetShaddow: `inset 0 ${remcalc(3)} 0 0 rgba(0, 0, 0, 0.05)`, border: { - checked: `1px solid ${colors.brandPrimary}`, - unchecked: `1px solid ${colors.borderSecondary}`, - confirmed: `1px solid ${colors.confirmation}` + checked: `${remcalc(1)} solid ${colors.brandPrimary}`, + unchecked: `${remcalc(1)} solid ${colors.borderSecondary}`, + confirmed: `${remcalc(1)} solid ${colors.confirmation}` } }; - -module.exports = boxes; diff --git a/ui/src/shared/constants/colors.js b/ui/src/shared/constants/colors.js index 6ce75c50..380ff3a5 100644 --- a/ui/src/shared/constants/colors.js +++ b/ui/src/shared/constants/colors.js @@ -45,13 +45,18 @@ const metrics = { seperator: '#D9DEF3' }; +const topology = { + topologyBackground: '#343434', +}; + const colors = { ...brandPrimary, ...brandSecondary, ...brandInactive, ...notifications, ...metrics, - fonts + ...topology, + fonts, }; module.exports = colors; diff --git a/ui/src/shared/constants/index.js b/ui/src/shared/constants/index.js index 2368e31d..d43f03bd 100644 --- a/ui/src/shared/constants/index.js +++ b/ui/src/shared/constants/index.js @@ -6,6 +6,7 @@ const boxes = require('./boxes'); const typography = require('./typography'); const sizes = require('./sizes'); const breakpoints = require('./breakpoints'); +const baseunit = require('./baseunits'); const tables = { bg: 'transparent', @@ -22,7 +23,8 @@ const constants = traverse({ forms, sizes, tables, - typography + typography, + baseunit }).map(function(x) { return isFunction(x) ? x(this.parent.node) : x; }); diff --git a/ui/stories/index.js b/ui/stories/index.js index f0739a4f..39fe5594 100644 --- a/ui/stories/index.js +++ b/ui/stories/index.js @@ -7,9 +7,8 @@ const { const { Base, - Container, - Row, Column, + Container, MiniMetric: { MiniMetricGraph, MiniMetricMeta, @@ -17,6 +16,7 @@ const { MiniMetricSubtitle, MiniMetricView }, + Row, } = require('../src/'); const MiniMetricData = require('../src/components/list/mini-metric-data'); diff --git a/ui/yarn.lock b/ui/yarn.lock index 8e64b4d7..0316ccc2 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -162,8 +162,8 @@ ajv-keywords@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" ajv@^4.7.0: - version "4.10.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.3.tgz#3e4fea9675b157de7888b80dd0ed735b83f28e11" + version "4.10.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.4.tgz#c0974dd00b3464984892d6010aa9c2c945933254" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -293,6 +293,13 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +array.prototype.find@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.1.tgz#1557f888df6c57e4d1256f20852d687a25b51fde" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -1296,8 +1303,8 @@ babel-types@^6.13.0, babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18 to-fast-properties "^1.0.1" babylon@^6.1.0, babylon@^6.11.0, babylon@^6.12.0, babylon@^6.13.0: - version "6.14.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.14.1.tgz#956275fab72753ad9b3435d7afe58f8bf0a29815" + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" babylon@~5.8.3: version "5.8.38" @@ -1396,11 +1403,11 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^1.1.1, browserslist@^1.1.3, browserslist@^1.4.0, browserslist@~1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.1.tgz#67c3f2a1a6ad174cd01d25d2362e6e6083b26986" +browserslist@^1.0.1, browserslist@^1.1.1, browserslist@^1.1.3, browserslist@^1.4.0, browserslist@^1.5.2, browserslist@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.2.tgz#1c82fde0ee8693e6d15c49b7bff209dc06298c56" dependencies: - caniuse-db "^1.0.30000601" + caniuse-db "^1.0.30000604" buf-compare@^1.0.0: version "1.0.1" @@ -1435,9 +1442,9 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -builtin-status-codes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-2.0.0.tgz#6f22003baacf003ccd287afe6872151fddc58579" +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" caching-transform@^1.0.0: version "1.0.1" @@ -1489,9 +1496,19 @@ camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" -caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000601, caniuse-db@^1.0.30000604: - version "1.0.30000604" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000604.tgz#bc139270a777564d19c0aadcd832b491d093bda5" +caniuse-api@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.2.tgz#8f393c682f661c0a997b77bba6e826483fb3600e" + dependencies: + browserslist "^1.0.1" + caniuse-db "^1.0.30000346" + lodash.memoize "^4.1.0" + lodash.uniq "^4.3.0" + shelljs "^0.7.0" + +caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000604: + version "1.0.30000607" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000607.tgz#f9d5b542f30d064c305544ff8938b217c67b88e9" capture-stack-trace@^1.0.0: version "1.0.0" @@ -1537,12 +1554,9 @@ chart.js@^2.4.0: chartjs-color "^2.0.0" moment "^2.10.6" -chartjs-chart-box-plot@^1.0.0-9: - version "1.0.0-9" - resolved "https://registry.yarnpkg.com/chartjs-chart-box-plot/-/chartjs-chart-box-plot-1.0.0-9.tgz#bd392c689301e71b13f602818629f5a0965eaddb" - dependencies: - react "^15.4.1" - react-dom "^15.4.1" +chartjs-chart-box-plot@prerelease: + version "1.0.0-16" + resolved "https://registry.yarnpkg.com/chartjs-chart-box-plot/-/chartjs-chart-box-plot-1.0.0-16.tgz#2544012ae84b04fa9922fe528017f5b748346497" chartjs-color-string@^0.4.0: version "0.4.0" @@ -1774,7 +1788,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@^2.8.1, commander@^2.9.0: +commander@2, commander@^2.8.1, commander@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -2076,6 +2090,216 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +d3-array@1, d3-array@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.0.2.tgz#174237bf356a852fadd6af87743d928631de7655" + +d3-axis@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.4.tgz#bdfdcf5e859824062e0f17ad920f76236e72512c" + +d3-brush@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.0.3.tgz#4fa5374cc3b755d0990bf76b71b7a66417751c74" + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3-chord@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.3.tgz#a398bae7cb632a3c4ea687a555a6b9ee4609d990" + dependencies: + d3-array "1" + d3-path "1" + +d3-collection@1, d3-collection@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.2.tgz#df5acb5400443e9eabe9c1379896c67e52426b39" + +d3-color@1, d3-color@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.2.tgz#83cb4b3a9474e40795f009d97e97a15649830bbc" + +d3-dispatch@1, d3-dispatch@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.2.tgz#5b511e79a46a1f89492841c0a8f656687d5daa0a" + +d3-drag@1, d3-drag@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.0.2.tgz#d634cc3f7689f99dd03fd7eb1af2945c0f4339ad" + dependencies: + d3-dispatch "1" + d3-selection "1" + +d3-dsv@1, d3-dsv@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.0.3.tgz#049fe43c0f5f60c7ff7d376616bc76d6fc9d378f" + dependencies: + commander "2" + iconv-lite "0.4" + rw "1" + +d3-ease@1, d3-ease@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.2.tgz#b486f8f3ca308ca7be38197d65622b6e30983377" + +d3-force@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.0.4.tgz#f84dcbb3200be41de7bc30fa71923143156758bf" + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-quadtree "1" + d3-timer "1" + +d3-format@1, d3-format@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.0.2.tgz#138618320b4bbeb43b5c0ff30519079fbbd7375e" + +d3-geo@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.4.0.tgz#15e58c414b5bafa1a960eeeb29059c94a60d8408" + dependencies: + d3-array "1" + +d3-hierarchy@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.0.3.tgz#986b4925e81f1e0b4087e9442850f950cf27d338" + +d3-interpolate@1, d3-interpolate@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.2.tgz#b52e6927a04fe1fe2a4cffc139e5389ed3e5e790" + dependencies: + d3-color "1" + +d3-path@1, d3-path@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.3.tgz#60103d0dea9a6cd6ca58de86c6d56724002d3fde" + +d3-polygon@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.2.tgz#6552c0fb03aa2d05023351da6e0e8adc4df0202b" + +d3-quadtree@1, d3-quadtree@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.2.tgz#e7e873af06aaa427eaa4af094cc4cbfb350b9e38" + +d3-queue@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/d3-queue/-/d3-queue-3.0.3.tgz#10ee4dd0574a1affaabfb931d0ba4f117926edc6" + +d3-random@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.0.2.tgz#83ff6a391206209c30565299e43c6549866db269" + +d3-request@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-request/-/d3-request-1.0.3.tgz#63fc7dfd784607db0df5d535d7cb898fceba755a" + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-dsv "1" + xmlhttprequest "1" + +d3-scale@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.4.tgz#50e28bf6a193b706745528515ed9b3d44205a033" + dependencies: + d3-array "1" + d3-collection "1" + d3-color "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-selection@1, d3-selection@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.0.3.tgz#e63e51416172427854c1bcdfa066eb5fe872c108" + +d3-shape@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.0.4.tgz#145ee100ccbec42f8e3f1996cd05c786f79fe1c6" + dependencies: + d3-path "1" + +d3-time-format@2, d3-time-format@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.0.3.tgz#3241569b74ddc9c42e0689c0e8a903579fd6280a" + dependencies: + d3-time "1" + +d3-time@1, d3-time@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.4.tgz#2ceba09a76b7450c992a1ded4e10fc6195e69649" + +d3-timer@1, d3-timer@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.3.tgz#7a308a10c8524778e6b32d1d6c1c329209ae0ebf" + +d3-transition@1, d3-transition@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.0.3.tgz#91dc986bddb30973639320a85db72ce4ab1a27bb" + dependencies: + d3-color "1" + d3-dispatch "1" + d3-ease "1" + d3-interpolate "1" + d3-selection "1" + d3-timer "1" + +d3-voronoi@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.1.tgz#998544dca98ef0e89a6c40c0bac3510d1bc1b8b9" + +d3-zoom@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.1.1.tgz#d2362d8f7043c1fc5d96a438de69f4e02ef1e67b" + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/d3/-/d3-4.4.1.tgz#2cbb08f92970364076ffe91ab83ef66b80610785" + dependencies: + d3-array "1.0.2" + d3-axis "1.0.4" + d3-brush "1.0.3" + d3-chord "1.0.3" + d3-collection "1.0.2" + d3-color "1.0.2" + d3-dispatch "1.0.2" + d3-drag "1.0.2" + d3-dsv "1.0.3" + d3-ease "1.0.2" + d3-force "1.0.4" + d3-format "1.0.2" + d3-geo "1.4.0" + d3-hierarchy "1.0.3" + d3-interpolate "1.1.2" + d3-path "1.0.3" + d3-polygon "1.0.2" + d3-quadtree "1.0.2" + d3-queue "3.0.3" + d3-random "1.0.2" + d3-request "1.0.3" + d3-scale "1.0.4" + d3-selection "1.0.3" + d3-shape "1.0.4" + d3-time "1.0.4" + d3-time-format "2.0.3" + d3-timer "1.0.3" + d3-transition "1.0.3" + d3-voronoi "1.1.1" + d3-zoom "1.1.1" + d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" @@ -2487,9 +2711,10 @@ eslint-plugin-promise@^3.4.0: resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.0.tgz#6ba9048c2df57be77d036e0c68918bc9b4fc4195" eslint-plugin-react@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.8.0.tgz#741ab5438a094532e5ce1bbb935d6832356f492d" + version "6.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.9.0.tgz#54c2e9906b76f9d10142030bdc34e9d6840a0bb2" dependencies: + array.prototype.find "^2.0.1" doctrine "^1.2.2" jsx-ast-utils "^1.3.4" @@ -2498,8 +2723,8 @@ eslint-plugin-standard@^2.0.1: resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3" eslint@^3.12.2: - version "3.12.2" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.12.2.tgz#6be5a9aa29658252abd7f91e9132bab1f26f3c34" + version "3.13.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.13.1.tgz#564d2646b5efded85df96985332edd91a23bff25" dependencies: babel-code-frame "^6.16.0" chalk "^1.1.3" @@ -2531,7 +2756,7 @@ eslint@^3.12.2: require-uncached "^1.0.2" shelljs "^0.7.5" strip-bom "^3.0.0" - strip-json-comments "~1.0.1" + strip-json-comments "~2.0.1" table "^3.7.8" text-table "~0.2.0" user-home "^2.0.0" @@ -3019,7 +3244,7 @@ got@^5.0.0: unzip-response "^1.0.2" url-parse-lax "^1.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@~4.1.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@~4.1.4: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3155,14 +3380,14 @@ hyphenate-style-name@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" +iconv-lite@0.4, iconv-lite@^0.4.13, iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -iconv-lite@^0.4.13, iconv-lite@~0.4.13: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - icss-replace-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5" @@ -3856,8 +4081,8 @@ lodash.isarray@^3.0.0: resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isequal@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.4.0.tgz#6295768e98e14dc15ce8d362ef6340db82852031" + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" lodash.isfunction@^3.0.8: version "3.0.8" @@ -3883,6 +4108,10 @@ lodash.map@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" +lodash.memoize@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + lodash.merge@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" @@ -3907,6 +4136,10 @@ lodash.some@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" +lodash.uniq@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + lodash@4.x.x, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.10.0, lodash@^4.12.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4255,8 +4488,8 @@ normalize-selector@^0.2.0: resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" normalize-url@^1.4.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.8.0.tgz#a9550b079aa3523c85d78df24eef1959fce359ab" + version "1.9.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.0.tgz#c2bb50035edee62cd81edb2d45da68dc25e3423e" dependencies: object-assign "^4.0.1" prepend-http "^1.0.0" @@ -4705,24 +4938,24 @@ postcss-less@^0.14.0: postcss "^5.0.21" postcss-load-config@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.0.0.tgz#1399f60dcd6bd9c3124b2eb22960f77f9dc08b3d" + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.1.0.tgz#1c3c217608642448c03bebf3c32b1b28985293f9" dependencies: cosmiconfig "^2.1.0" object-assign "^4.1.0" - postcss-load-options "^1.0.2" - postcss-load-plugins "^2.0.0" + postcss-load-options "^1.1.0" + postcss-load-plugins "^2.2.0" -postcss-load-options@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.0.2.tgz#b99eb5759a588f4b2dd8b6471c6985f72060e7b0" +postcss-load-options@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.1.0.tgz#e39215d154a19f69f9cb6052bffad4a82f09f354" dependencies: cosmiconfig "^2.1.0" object-assign "^4.1.0" -postcss-load-plugins@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.1.0.tgz#dbb6f46271df8d16e19b5d691ebda5175ce424a0" +postcss-load-plugins@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.2.0.tgz#84ef9cf36e637810ac5265e03f6d4c48ead83314" dependencies: cosmiconfig "^2.1.1" object-assign "^4.1.0" @@ -4755,10 +4988,13 @@ postcss-merge-longhand@^2.0.1: postcss "^5.0.4" postcss-merge-rules@^2.0.3: - version "2.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.0.11.tgz#c5d7c8de5056a7377aea0dff2fd83f92cafb9b8a" + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.1.tgz#5e5640020ce43cddd343c73bba91c9a358d1fe0f" dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" postcss "^5.0.4" + postcss-selector-parser "^2.2.2" vendors "^1.0.0" postcss-message-helpers@^2.0.0: @@ -4841,8 +5077,8 @@ postcss-normalize-url@^3.0.7: postcss-value-parser "^3.2.3" postcss-ordered-values@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.2.tgz#be8b511741fab2dac8e614a2302e9d10267b0771" + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" dependencies: postcss "^5.0.4" postcss-value-parser "^3.0.1" @@ -4896,7 +5132,7 @@ postcss-scss@^0.4.0: dependencies: postcss "^5.2.5" -postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.1.1: +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.1.1, postcss-selector-parser@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.2.tgz#3d70f5adda130da51c7c0c2fc023f56b1374fe08" dependencies: @@ -4934,8 +5170,8 @@ postcss-zindex@^2.0.1: uniqs "^2.0.0" postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.18, postcss@^5.0.2, postcss@^5.0.20, postcss@^5.0.21, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.4, postcss@^5.2.5, postcss@^5.2.8: - version "5.2.8" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.8.tgz#05720c49df23c79bda51fd01daeb1e9222e94390" + version "5.2.10" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945" dependencies: chalk "^1.1.3" js-base64 "^2.1.9" @@ -5142,8 +5378,11 @@ rc@^1.0.1, rc@^1.1.6, rc@~1.1.6: strip-json-comments "~1.0.4" react-addons-test-utils@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.1.tgz#1e4caab151bf27cce26df5f9cb714f4fd8359ae1" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.4.2.tgz#93bcaa718fcae7360d42e8fb1c09756cc36302a2" + dependencies: + fbjs "^0.8.4" + object-assign "^4.1.0" react-docgen@^2.12.1: version "2.13.0" @@ -5158,8 +5397,8 @@ react-docgen@^2.12.1: recast "^0.11.5" react-dom@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.1.tgz#d54c913261aaedb17adc20410d029dcc18a1344a" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f" dependencies: fbjs "^0.8.1" loose-envify "^1.1.0" @@ -5212,7 +5451,7 @@ react-modal@^1.2.0, react-modal@^1.2.1: exenv "1.2.0" lodash.assign "^4.2.0" -react-select: +react-select@^1.0.0-rc.2: version "1.0.0-rc.2" resolved "https://registry.yarnpkg.com/react-select/-/react-select-1.0.0-rc.2.tgz#9fc11b149a3dc1ac831289d21b40a59742f82f8d" dependencies: @@ -5233,8 +5472,8 @@ react-stubber@^1.0.0: babel-runtime "^6.5.0" react@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/react/-/react-15.4.1.tgz#498e918602677a3983cd0fd206dfe700389a0dd6" + version "15.4.2" + resolved "https://registry.yarnpkg.com/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef" dependencies: fbjs "^0.8.4" loose-envify "^1.1.0" @@ -5553,6 +5792,10 @@ run-async@^0.1.0: dependencies: once "^1.3.0" +rw@1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.2.tgz#14ef5137ff7547c73ecf0e0af1f0aee07e5401ee" + rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" @@ -5643,9 +5886,9 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -shelljs@^0.7.4, shelljs@^0.7.5: - version "0.7.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675" +shelljs@^0.7.0, shelljs@^0.7.4, shelljs@^0.7.5: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" dependencies: glob "^7.0.0" interpret "^1.0.0" @@ -5690,8 +5933,8 @@ sort-keys@^1.0.0, sort-keys@^1.1.1: is-plain-obj "^1.0.0" source-list-map@^0.1.4, source-list-map@~0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.7.tgz#d4b5ce2a46535c72c7e8527c71a77d250618172e" + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" source-map-support@^0.4.0, source-map-support@^0.4.2: version "0.4.8" @@ -5811,10 +6054,10 @@ stream-combiner@^0.2.1: through "~2.3.4" stream-http@^2.3.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.5.0.tgz#585eee513217ed98fe199817e7313b6f772a6802" + version "2.6.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.1.tgz#7d20fcdfebc16b16e4174e31dd94cd9c70f10e89" dependencies: - builtin-status-codes "^2.0.0" + builtin-status-codes "^3.0.0" inherits "^2.0.1" readable-stream "^2.1.0" to-arraybuffer "^1.0.0" @@ -5897,10 +6140,14 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: +strip-json-comments@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + style-loader@0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.13.1.tgz#468280efbc0473023cd3a6cd56e33b5a1d7fc3a9" @@ -6295,8 +6542,8 @@ uniq@^1.0.1: resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" uniqid@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.0.tgz#33d9679f65022f48988a03fd24e7dcaf8f109eca" + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" dependencies: macaddress "^0.2.8" @@ -6486,8 +6733,8 @@ whatwg-fetch@>=0.10.0: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.1.tgz#078b9461bbe91cea73cbce8bb122a05f9e92b772" whatwg-url@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.2.0.tgz#abf1a3f5ff4bc2005b3f0c2119382631789d8e44" + version "4.3.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.3.0.tgz#92aaee21f4f2a642074357d70ef8500a7cbb171a" dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -6550,10 +6797,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2, write-file-atomic@^1.1.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" dependencies: - graceful-fs "^4.1.2" + graceful-fs "^4.1.11" imurmurhash "^0.1.4" slide "^1.1.5" @@ -6608,6 +6855,10 @@ xmlbuilder@^4.1.0, xmlbuilder@~4.1.0: dependencies: lodash "^3.5.0" +xmlhttprequest@1: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"