From d3ae347f159cfbb1b244462b2d1bde62e5150523 Mon Sep 17 00:00:00 2001 From: benstov Date: Mon, 29 Apr 2019 17:02:11 +0200 Subject: [PATCH] feat(dashboard): implement new overview page --- dashboard/package-lock.json | 5 + dashboard/package.json | 1 + dashboard/src/app.tsx | 19 +-- dashboard/src/assets/v.svg | 3 + dashboard/src/components/RefreshButton.tsx | 4 +- dashboard/src/components/card.tsx | 8 +- dashboard/src/components/checkbox.tsx | 4 +- dashboard/src/components/graph/index.tsx | 4 +- dashboard/src/components/header.tsx | 2 +- dashboard/src/components/info-pane.tsx | 21 +--- dashboard/src/components/ingresses.tsx | 80 ++++++++++++ dashboard/src/components/links.tsx | 4 +- dashboard/src/components/logs.tsx | 4 +- dashboard/src/components/module.tsx | 61 +++++++++ dashboard/src/components/notifications.tsx | 78 ++++++++++++ dashboard/src/components/overview.tsx | 110 ---------------- dashboard/src/components/page-error.tsx | 15 ++- dashboard/src/components/service.tsx | 139 +++++++++++++++++++++ dashboard/src/components/sidebar.tsx | 10 +- dashboard/src/components/table.tsx | 2 +- dashboard/src/components/tag.tsx | 43 +++---- dashboard/src/components/terminal.tsx | 4 +- dashboard/src/components/text.tsx | 2 +- dashboard/src/containers/graph.tsx | 2 +- dashboard/src/containers/logs.tsx | 8 +- dashboard/src/containers/node-info.tsx | 7 +- dashboard/src/containers/overview.tsx | 100 ++++++++++----- dashboard/src/context/data.tsx | 11 +- dashboard/src/styles/variables.ts | 26 +++- dashboard/src/util/helpers.ts | 8 ++ garden-service/package-lock.json | 106 ++++++++-------- garden-service/src/actions.ts | 4 + package-lock.json | 53 +++----- 33 files changed, 636 insertions(+), 312 deletions(-) create mode 100644 dashboard/src/assets/v.svg create mode 100644 dashboard/src/components/ingresses.tsx create mode 100644 dashboard/src/components/module.tsx create mode 100644 dashboard/src/components/notifications.tsx delete mode 100644 dashboard/src/components/overview.tsx create mode 100644 dashboard/src/components/service.tsx diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 71cf16f585..9b2d1e18cb 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -18248,6 +18248,11 @@ } } }, + "react-content-loader": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-4.2.1.tgz", + "integrity": "sha512-XA5irUvZpQAEavfUBo7kc4tdvAbWwVKJolz/+2Pkj/XU7pn78AweAUtn+AxEajN0Srg/mraJ8XMKlUsXOFiknw==" + }, "react-dev-utils": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-8.0.0.tgz", diff --git a/dashboard/package.json b/dashboard/package.json index f05d73bf30..98c24beb62 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -34,6 +34,7 @@ "node-sass": "^4.10.0", "normalize-url": "^4.3.0", "react": "^16.8.6", + "react-content-loader": "^4.2.1", "react-dom": "^16.8.6", "react-router-dom": "^5.0.0", "react-select": "^2.3.0", diff --git a/dashboard/src/app.tsx b/dashboard/src/app.tsx index a8235854d6..40745b6ac5 100644 --- a/dashboard/src/app.tsx +++ b/dashboard/src/app.tsx @@ -6,9 +6,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { css } from "emotion/macro" +import { css } from "emotion" import React, { useContext } from "react" -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import { Route } from "react-router-dom" import Graph from "./containers/graph" @@ -41,18 +41,23 @@ const Logo = styled.img` ` const SidebarWrapper = styled.div` - border-right: 1px solid ${colors.border} + border-right: 1px solid ${colors.border}; height: 100vh; position: relative; + background: ${colors.gardenWhite}; ` -const SidebarContainer = styled.div` + +type SidebarContainerProps = { + visible: boolean, +} +const SidebarContainer = styled.div` display: ${props => (props.visible ? `block` : "none")}; - width: ${props => (props.visible ? `10.5rem` : "0")}; + width: ${props => (props.visible ? `11.5rem` : "0")}; ` const SidebarToggleButton = styled.div` position: absolute; - right: -2.2rem; + right: -2.3rem; top: 2rem; width: 1.5rem; cursor: pointer; @@ -112,7 +117,7 @@ const App = () => { >
+ + diff --git a/dashboard/src/components/RefreshButton.tsx b/dashboard/src/components/RefreshButton.tsx index 71873d32e9..a57d8ee94d 100644 --- a/dashboard/src/components/RefreshButton.tsx +++ b/dashboard/src/components/RefreshButton.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import React from "react" import { colors } from "../styles/variables" @@ -37,7 +37,7 @@ const Icon = styled.i` ` const IconLoading = styled(Icon)` - animation spin 0.5s infinite linear; + animation: spin 0.5s infinite linear; @keyframes spin { from { transform:rotate(0deg); diff --git a/dashboard/src/components/card.tsx b/dashboard/src/components/card.tsx index 6aaa005d92..6d35968a35 100644 --- a/dashboard/src/components/card.tsx +++ b/dashboard/src/components/card.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import React from "react" import { colors, fontMedium } from "../styles/variables" @@ -17,7 +17,11 @@ interface CardProps { backgroundColor?: string } -const Wrapper = styled.div` +type WrapperProps = { + backgroundColor?: string, +} + +const Wrapper = styled.div` background-color: ${props => props.backgroundColor || colors.gardenWhite}; border-radius: 2px; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); diff --git a/dashboard/src/components/checkbox.tsx b/dashboard/src/components/checkbox.tsx index 4ec36f9d4a..5033e22ea0 100644 --- a/dashboard/src/components/checkbox.tsx +++ b/dashboard/src/components/checkbox.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import React, { ChangeEvent } from "react" import { colors } from "../styles/variables" @@ -18,7 +18,7 @@ const Label = styled.label` cursor: pointer; font-size: 1rem; user-select: none; - margin-bottom: 0.75rem; + margin-bottom: .75rem; height: 1rem; line-height: 1rem; ` diff --git a/dashboard/src/components/graph/index.tsx b/dashboard/src/components/graph/index.tsx index 3e1f65f6e7..c98daf82dd 100644 --- a/dashboard/src/components/graph/index.tsx +++ b/dashboard/src/components/graph/index.tsx @@ -7,7 +7,7 @@ */ import cls from "classnames" -import { css } from "emotion/macro" +import { css } from "emotion" import React, { Component, ChangeEvent } from "react" import styled from "@emotion/styled" import { capitalize, uniq } from "lodash" @@ -232,7 +232,7 @@ const Span = styled.span` const Status = styled.p` ${fontMedium} - colors: grey; + color: grey; ` const ProcessSpinner = styled(Spinner)` diff --git a/dashboard/src/components/header.tsx b/dashboard/src/components/header.tsx index c9e74ec933..d76c9e8a8f 100644 --- a/dashboard/src/components/header.tsx +++ b/dashboard/src/components/header.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import React from "react" import { H2 } from "./text" diff --git a/dashboard/src/components/info-pane.tsx b/dashboard/src/components/info-pane.tsx index 9ed74a7cc0..f7588748ce 100644 --- a/dashboard/src/components/info-pane.tsx +++ b/dashboard/src/components/info-pane.tsx @@ -9,22 +9,13 @@ import React from "react" import cls from "classnames" import { capitalize } from "lodash" -import { css } from "emotion/macro" -import styled from "@emotion/styled/macro" +import { css } from "emotion" +import styled from "@emotion/styled" import Card from "../components/card" import { colors } from "../styles/variables" import { RenderedNode } from "garden-cli/src/config-graph" import { RefreshButton } from "./RefreshButton" - -export const ErrorTxt = styled.div` - color: #721c24; - background-color: #f8d7da; - border-color: #f5c6cb; - position: relative; - padding: 0.75rem 1.25rem; - border: 1px solid transparent; - border-radius: 0.25rem; -` +import { ErrorNotification } from "./notifications" const Term = styled.div` background-color: ${colors.gardenBlack}; @@ -35,7 +26,7 @@ const Term = styled.div` padding: 1rem; ` const Code = styled.code` - font-size: 0.8rem; + font-size: .8rem; white-space: pre-wrap; ` @@ -103,7 +94,7 @@ export const InfoPane: React.FC = ({ ) } else if (output === null) { // Output explictly set to null means that the data was fetched but the result was empty - outputEl = No test output + outputEl = No test output } return ( @@ -115,7 +106,7 @@ export const InfoPane: React.FC = ({

+ * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import React from "react" +import styled from "@emotion/styled" +import { ExternalLink } from "./links" +import { ServiceIngress } from "garden-cli/src/types/service" +import { truncateMiddle } from "../util/helpers" +import normalizeUrl from "normalize-url" +import { format } from "url" + +const Ingresses = styled.div` + font-size: 1rem; + line-height: 1.4rem; + color: #4f4f4f; + height: 5rem; + overflow: hidden; + overflow-y: auto; + + ::-webkit-scrollbar { + -webkit-appearance: none; + width: 7px; + } + ::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba(0, 0, 0, 0.5); + box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); + } +` +const LinkContainer = styled.div` + padding-bottom: 1rem; + font-size: .75rem; + + &:last-of-type { + padding-bottom: 0; + } +` + +const NoIngresses = styled.div` + font-style: italic; + font-size: .75rem; +` + +const getIngressUrl = (ingress: ServiceIngress) => { + return normalizeUrl(format({ + protocol: ingress.protocol, + hostname: ingress.hostname, + port: ingress.port, + pathname: ingress.path, + })) +} + +interface IngressesProp { + ingresses: ServiceIngress[] | undefined +} + +export default ({ ingresses }: IngressesProp) => { + return ( + + {ingresses && ingresses.map(i => { + const url = getIngressUrl(i) + return + + {truncateMiddle(url)} + +
+
+ })} + {(!ingresses || !ingresses.length) && + + No ingresses found + } +
+ ) +} diff --git a/dashboard/src/components/links.tsx b/dashboard/src/components/links.tsx index 111089f637..5593cebc3c 100644 --- a/dashboard/src/components/links.tsx +++ b/dashboard/src/components/links.tsx @@ -7,7 +7,7 @@ */ import React from "react" -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import { NavLink as ReactRouterNavLink } from "react-router-dom" import { colors } from "../styles/variables" @@ -15,7 +15,7 @@ import { colors } from "../styles/variables" export const ExternalLink = styled.a` text-decoration: underline; &:visited { - color: ${colors.gardenGreen} + color: ${colors.gardenGreenDark} } &:hover { color: ${colors.gardenPink} diff --git a/dashboard/src/components/logs.tsx b/dashboard/src/components/logs.tsx index f09b9a32d4..cbd4095c80 100644 --- a/dashboard/src/components/logs.tsx +++ b/dashboard/src/components/logs.tsx @@ -7,8 +7,8 @@ */ import cls from "classnames" -import { css } from "emotion/macro" -import styled from "@emotion/styled/macro" +import { css } from "emotion" +import styled from "@emotion/styled" import { max } from "lodash" import React, { Component } from "react" import Select from "react-select" diff --git a/dashboard/src/components/module.tsx b/dashboard/src/components/module.tsx new file mode 100644 index 0000000000..713aedbab6 --- /dev/null +++ b/dashboard/src/components/module.tsx @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import React from "react" +import styled from "@emotion/styled" +import { ServiceModel, ModuleModel } from "../containers/overview" +import Service from "./service" + +const Module = styled.div` + padding: 0rem 2rem 1rem 0rem; +` + +const Services = styled.div` + border-top: solid #bcbcbc 1px; + padding-top: 1rem; + display: flex; + flex-wrap: wrap; + align-items: middle; +` +const Header = styled.div` + display: flex; + align-items: center; +` + +const Label = styled.div` + font-size: .75rem; + display: flex; + align-items: center; + color: #bcbcbc; +` +const Name = styled.div` + padding-right: .5rem; +` + +interface ModuleProp { + module: ModuleModel +} +export default ({ + module: { services = [], name }, +}: ModuleProp) => { + + return ( + +
+ {name} + + +
+ + {services.map(service => ( + + ))} + +
+ ) +} diff --git a/dashboard/src/components/notifications.tsx b/dashboard/src/components/notifications.tsx new file mode 100644 index 0000000000..0184a37650 --- /dev/null +++ b/dashboard/src/components/notifications.tsx @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import React from "react" +import styled from "@emotion/styled" +import { colors } from "../styles/variables" + +const Notification = styled.div` + border-radius: 3px 3px 3px 3px; + padding: .5rem; + margin-top: .5rem; + font-size: 0.75rem; + display: flex; + align-items: center; +` + +const NotificationIcon = styled.i` + padding-right: .5rem; +` + +export const Error = styled(Notification)` + color: ${colors.notifications.error.color}; + background-color: ${colors.notifications.error.backgroundColor}; +` + +export const ErrorNotification = ({ children }) => { + return ( + + + {children} + + ) +} + +export const Warning = styled(Notification)` + color: ${colors.notifications.warning.color}; + background-color: ${colors.notifications.warning.backgroundColor}; +` +export const WarningNotification = ({ children }) => { + return ( + + + {children} + + ) +} + +export const Success = styled(Notification)` + color: ${colors.notifications.success.color}; + background-color: ${colors.notifications.success.backgroundColor}; +` +export const SuccessNotification = ({ children }) => { + return ( + + + {children} + + ) +} + +export const Info = styled(Notification)` + color: ${colors.notifications.info.color}; + background-color: ${colors.notifications.info.backgroundColor}; +` + +export const InfoNotification = ({ children }) => { + return ( + + + {children} + + ) +} diff --git a/dashboard/src/components/overview.tsx b/dashboard/src/components/overview.tsx deleted file mode 100644 index 4a61684740..0000000000 --- a/dashboard/src/components/overview.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2018 Garden Technologies, Inc. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -import React from "react" -import styled from "@emotion/styled" -import { format } from "url" -import normalizeUrl from "normalize-url" - -import Table from "./table" -import { ExternalLink } from "./links" - -import { ModuleConfig } from "garden-cli/src/config/module" -import { ServiceStatus, ServiceIngress } from "garden-cli/src/types/service" - -export function getIngressUrl(ingress: ServiceIngress) { - return normalizeUrl(format({ - protocol: ingress.protocol, - hostname: ingress.hostname, - port: ingress.port, - pathname: ingress.path, - })) -} - -interface ServicesProps { - moduleConfigs: ModuleConfig[] - services: { [name: string]: ServiceStatus } -} - -interface ModulesProps { - moduleConfigs: ModuleConfig[] -} - -export const Modules: React.FC = ({ moduleConfigs }) => { - const rowHeaders = ["Name", "Type", "Services"] - const rows = moduleConfigs.map(moduleConfig => [ - moduleConfig.name, - moduleConfig.type, - moduleConfig.serviceConfigs.map(s => s.name).join("\n"), - ]) - return ( - - ) -} - -export const Services: React.FC = ({ moduleConfigs, services }) => { - const rowHeaders = ["Name", "Status", "Module", "Ingresses"] - const rows = Object.keys(services).map(serviceName => { - const service = services[serviceName] - const moduleConfig = moduleConfigs.find(m => m.serviceConfigs.map(s => s.name).includes(serviceName)) - const moduleName = moduleConfig ? moduleConfig.name : "" - return [ - serviceName, - service.state || "", - moduleName, - service.ingresses ? : null, - ] - }) - return ( -
- ) -} - -interface IngressesProp { - ingresses: ServiceIngress[] -} - -const truncateMiddle = (str) => { - if (str.length > 35) { - return str.substr(0, 16) + "..." + str.substr(str.length - 16, str.length) - } - return str -} - -const LinkContainer = styled.div` - padding-bottom: 1rem; - - &:last-of-type{ - padding-bottom: 0; - } -` -const Ingresses: React.FC = ({ ingresses }) => { - return ( -
- {ingresses.map(i => { - const url = getIngressUrl(i) - return ( - - - {truncateMiddle(url)} - -
-
- ) - })} -
- ) -} diff --git a/dashboard/src/components/page-error.tsx b/dashboard/src/components/page-error.tsx index 567fc0e61e..2146b9f382 100644 --- a/dashboard/src/components/page-error.tsx +++ b/dashboard/src/components/page-error.tsx @@ -7,17 +7,22 @@ */ import cls from "classnames" -import { css } from "emotion/macro" +import { css } from "emotion" import React from "react" import { H3 } from "../components/text" import { colors } from "../styles/variables" +import { AxiosError } from "axios" + +interface Props { + error?: AxiosError +} // TODO Style me + add prop interface -const PageError: React.FC = ({ error }) => { +const PageError: React.FC = ({ error }) => { let suggestion - const status = error.response && error.response.status + const status = error && error.response && error.response.status if (status === 500) { suggestion = (
@@ -39,7 +44,9 @@ const PageError: React.FC = ({ error }) => {

Whoops, something went wrong.

-

Messsage: {error.message}

+ {error && error.message && +

Messsage: {error.message}

+ } {suggestion}
) diff --git a/dashboard/src/components/service.tsx b/dashboard/src/components/service.tsx new file mode 100644 index 0000000000..e09362f55e --- /dev/null +++ b/dashboard/src/components/service.tsx @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 Garden Technologies, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import React from "react" +import { css } from "emotion" +import styled from "@emotion/styled" +import { ReactComponent as VIcon } from "./../assets/v.svg" +import Ingresses from "./ingresses" +import { ServiceModel } from "../containers/overview" +import { ServiceState } from "garden-cli/src/types/service" +import { colors } from "../styles/variables" +import { Facebook } from "react-content-loader" + +const Service = styled.div` + width: 17rem; + height: 13rem; + background-color: white; + margin-bottom: 1rem; + box-shadow: 0px 1px 5px rgba(0, 0, 0, .2), + 0px 3px 4px rgba(255, 255, 255, .12), 0px 2px 4px rgb(255, 255, 255); + margin-right: 1rem; + &:last-of-type { + margin-right: 0; + } +` +const Header = styled.div` + width: 100%; + padding: .4rem .75rem; + border-bottom: 1px solid #c4c4c4; + height: 3rem; +` + +const Fields = styled.div` + animation: fadein .75s; + + @keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } + } +` +const Field = styled.div` + padding-bottom: .5rem; +` +const Label = styled.div` + font-size: .75rem; + line-height: 1rem; + color: #878787; +` +const Value = styled.div` + font-size: 1rem; + line-height: 1.4rem; + color: #4f4f4f; +` + +const Content = styled.div` + width: 100%; + padding: .75rem .75rem .75rem .75rem; + position: relative; + height: 10rem; +` + +type StateProps = { + state?: ServiceState, +} +const State = styled.div` + width: 1.5rem; + height: 1.5rem; + border-radius: 2rem; + margin-left: auto; + background-color: ${props => (props && props.state && colors.status[props.state] || colors.gardenGrayLight)}; + display: flex; + align-items: center; +` + +const Tag = styled.div` + font-size: .56rem; + display: flex; + align-items: center; + color: #bcbcbc; +` +const Name = styled.div` + height: 1.5rem; + font-size: 1.25rem; + color: rgba(0, 0, 0, .87); +` + +const Row = styled.div` + display: flex; + align-items: center; +` + +interface ServiceProp { + service: ServiceModel +} +export default ({ + service: { name, ingresses, state, isLoading }, +}: ServiceProp) => { + + return ( + +
+ SERVICE + + {name} + + + + +
+ + {isLoading && ( + + )} + {!isLoading && ( + + + + {state} + + + + + + + )} + + +
+ ) +} diff --git a/dashboard/src/components/sidebar.tsx b/dashboard/src/components/sidebar.tsx index be2de08683..1ff49d4e5a 100644 --- a/dashboard/src/components/sidebar.tsx +++ b/dashboard/src/components/sidebar.tsx @@ -6,8 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { css } from "emotion/macro" -import styled from "@emotion/styled/macro" +import { css } from "emotion" +import styled from "@emotion/styled" import React, { Component } from "react" import { NavLink } from "./links" @@ -24,12 +24,12 @@ interface State { } const Button = styled.li` - ${fontMedium} + ${fontMedium}; border-radius: 2px; cursor: pointer; width: 100%; transition: all 0.3s ease; - &: hover { + &:hover { background-color: ${colors.gardenGreenLight}; border-color: ${colors.gardenGreenLight}; } @@ -81,7 +81,7 @@ class Sidebar extends Component { ) } return ( - ) diff --git a/dashboard/src/components/table.tsx b/dashboard/src/components/table.tsx index 926972ca8c..eefc414e58 100644 --- a/dashboard/src/components/table.tsx +++ b/dashboard/src/components/table.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import React from "react" import Card from "./card" diff --git a/dashboard/src/components/tag.tsx b/dashboard/src/components/tag.tsx index 73a4655930..3dded87996 100644 --- a/dashboard/src/components/tag.tsx +++ b/dashboard/src/components/tag.tsx @@ -7,6 +7,7 @@ */ import styled from "@emotion/styled" +import { colors } from "./../styles/variables" export const Tag = styled.a` background: #eee; @@ -20,26 +21,26 @@ export const Tag = styled.a` text-decoration: none; -webkit-transition: color 0.2s; -&:: before { - background: #fff; - border-radius: 10px; - box-shadow: inset 0 1px rgba(0, 0, 0, 0.25); - content: ''; - height: 6px; - left: 10px; - position: absolute; - width: 6px; - top: 10px; -} + &::before { + background: ${colors.gardenWhite}; + border-radius: 10px; + box-shadow: inset 0 1px rgba(0, 0, 0, 0.25); + content: ''; + height: 6px; + left: 10px; + position: absolute; + width: 6px; + top: 10px; + } -&:: after { - background: #fff; - border-bottom: 13px solid transparent; - border-left: 10px solid #eee; - border-top: 13px solid transparent; - content: ''; - position: absolute; - right: 0; - top: 0; -} + &::after { + background: ${colors.gardenWhite}; + border-bottom: 13px solid transparent; + border-left: 10px solid #eee; + border-top: 13px solid transparent; + content: ''; + position: absolute; + right: 0; + top: 0; + } ` diff --git a/dashboard/src/components/terminal.tsx b/dashboard/src/components/terminal.tsx index 5c3a12289f..97c6717b89 100644 --- a/dashboard/src/components/terminal.tsx +++ b/dashboard/src/components/terminal.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import { padEnd } from "lodash" import React from "react" @@ -29,7 +29,7 @@ const Term = styled.div` const P = styled.p` color: ${colors.gardenWhite}; - font-size: 0.8rem; + font-size: .8rem; ` const Service = styled.span` diff --git a/dashboard/src/components/text.tsx b/dashboard/src/components/text.tsx index 5f291806e9..05effce98c 100644 --- a/dashboard/src/components/text.tsx +++ b/dashboard/src/components/text.tsx @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import styled from "@emotion/styled/macro" +import styled from "@emotion/styled" import { colors, fontRegular } from "../styles/variables" export const H2 = styled.h2` diff --git a/dashboard/src/containers/graph.tsx b/dashboard/src/containers/graph.tsx index a20b12b1a1..c187c0315f 100644 --- a/dashboard/src/containers/graph.tsx +++ b/dashboard/src/containers/graph.tsx @@ -32,7 +32,7 @@ export default () => { } = useContext(UiStateContext) if (config.error || graph.error) { - return + return } if (!config.data || !graph.data || config.loading || graph.loading) { diff --git a/dashboard/src/containers/logs.tsx b/dashboard/src/containers/logs.tsx index 7ce19b1f78..8898fa4f1f 100644 --- a/dashboard/src/containers/logs.tsx +++ b/dashboard/src/containers/logs.tsx @@ -46,8 +46,12 @@ const LogsContainer = () => { } if (logs.error || config.error) { - return + return ( + + ) } - return + return ( + + ) } diff --git a/dashboard/src/containers/node-info.tsx b/dashboard/src/containers/node-info.tsx index 48beca6d9c..c712a12b05 100644 --- a/dashboard/src/containers/node-info.tsx +++ b/dashboard/src/containers/node-info.tsx @@ -11,14 +11,15 @@ import { DataContext } from "../context/data" import { timeConversion } from "../util/helpers" import { UiStateContext } from "../context/ui" import { RenderedNode } from "garden-cli/src/config-graph" -import { InfoPane, ErrorTxt } from "../components/info-pane" +import { InfoPane } from "../components/info-pane" import { TaskResultOutput } from "garden-cli/src/commands/get/get-task-result" import { TestResultOutput } from "garden-cli/src/commands/get/get-test-result" +import { ErrorNotification } from "../components/notifications" const ErrorMsg = ({ error, type }) => ( - + Error occured while trying to get {type} result: {error.message} - + ) export interface Props { diff --git a/dashboard/src/containers/overview.tsx b/dashboard/src/containers/overview.tsx index ccd16263dc..a6b07ba527 100644 --- a/dashboard/src/containers/overview.tsx +++ b/dashboard/src/containers/overview.tsx @@ -6,24 +6,37 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import cls from "classnames" -import { css } from "emotion/macro" import React, { useContext, useEffect } from "react" - import PageError from "../components/page-error" -import { Modules, Services } from "../components/overview" +import styled from "@emotion/styled" +import { ServiceIngress } from "garden-cli/src/types/service" +import Module from "../components/module" import { DataContext } from "../context/data" import Spinner from "../components/spinner" +import { ServiceState } from "garden-cli/src/types/service" + +export const overviewConfig = { + service: { + height: "14rem", + }, +} -const LoadingServices = () => ( -
-

Loading services...

-
-) +const Modules = styled.div` + padding-top: 1rem; + display: flex; + flex-wrap: wrap; +` + +export type ModuleModel = { + name: string; + services: ServiceModel[]; +} +export type ServiceModel = { + ingresses?: ServiceIngress[]; + name: string; + state?: ServiceState; + isLoading: boolean; +} // Note: We render the overview page components individually so we that we don't // have to wait for both API calls to return. @@ -38,30 +51,53 @@ export default () => { const isLoadingConfig = !config.data || config.loading - let modules: React.ReactNode = null - let services: React.ReactNode = null + let modulesContainerComponent: React.ReactNode = null + let modules: ModuleModel[] = [] - if (config.error) { - modules = + if (config.error || status.error) { + modulesContainerComponent = } else if (isLoadingConfig) { - modules = - } else if (config.data) { - modules = - } + modulesContainerComponent = + } else if (config.data && config.data.moduleConfigs) { + + // fill modules with services names + modules = config.data.moduleConfigs.map(moduleConfig => ({ + name: moduleConfig.name, + services: moduleConfig.serviceConfigs.map(service => ({ + name: service.name, + isLoading: true, + })), + })) + + // fill missing data from status + if (status.data && status.data.services) { + const servicesStatus = status.data.services + for (let currModule of modules) { + for (let serviceName of Object.keys(servicesStatus)) { + const index = currModule.services.findIndex(s => s.name === serviceName) + + if (index !== -1) { + currModule.services[index] = { + ...currModule.services[index], + state: servicesStatus[serviceName].state, + ingresses: servicesStatus[serviceName].ingresses, + isLoading: false, + } as ServiceModel + } + } + } + } - if (status.error) { - services = - } else if (!isLoadingConfig && (!status.data || status.loading)) { - // Only show when load component for Modules is no longer visible - services = - } else if (status.data && config.data) { - services = + modulesContainerComponent = ( + + {modules.map(module => ( + + ))} + + ) } return ( -
- {modules} - {services} -
+
{modulesContainerComponent}
) } diff --git a/dashboard/src/context/data.tsx b/dashboard/src/context/data.tsx index b5250a63c3..896c97a422 100644 --- a/dashboard/src/context/data.tsx +++ b/dashboard/src/context/data.tsx @@ -26,9 +26,10 @@ import { GraphOutput } from "garden-cli/src/commands/get/get-graph" import { TaskResultOutput } from "garden-cli/src/commands/get/get-task-result" import { EnvironmentStatus } from "garden-cli/src/actions" import { TestResultOutput } from "garden-cli/src/commands/get/get-test-result" +import { AxiosError } from "axios" interface StoreCommon { - error: Error | null + error?: AxiosError loading: boolean } @@ -85,7 +86,7 @@ interface ActionSuccess extends ActionBase { interface ActionError extends ActionBase { type: "fetchFailure" - error: Error + error: AxiosError } type Action = ActionStart | ActionError | ActionSuccess @@ -105,7 +106,7 @@ interface Actions { } const initialState: Store = storeKeys.reduce((acc, key) => { - const state = { loading: false, error: null } + const state = { loading: false } acc[key] = state return acc }, {} as Store) @@ -134,9 +135,9 @@ function updateSlice( function reducer(store: Store, action: Action) { switch (action.type) { case "fetchStart": - return updateSlice(store, action.key, { loading: true, error: null }) + return updateSlice(store, action.key, { loading: true, error: undefined }) case "fetchSuccess": - return updateSlice(store, action.key, { loading: false, data: action.data, error: null }) + return updateSlice(store, action.key, { loading: false, data: action.data, error: undefined }) case "fetchFailure": return updateSlice(store, action.key, { loading: false, error: action.error }) } diff --git a/dashboard/src/styles/variables.ts b/dashboard/src/styles/variables.ts index fd233404ef..5fc269cf71 100644 --- a/dashboard/src/styles/variables.ts +++ b/dashboard/src/styles/variables.ts @@ -28,7 +28,7 @@ export const colors = { grayLight: "#fafafa", gardenGray: "#555656", gardenGrayLight: "#cdcfd1", - gardenGrayLighter: "#f6f8f9", + gardenGrayLighter: "#FBFCFD", gardenBlack: "#010101", gardenBlue: "#00adef", gardenBlueDark: "#01569a", @@ -41,4 +41,28 @@ export const colors = { gardenPinkLighten, gardenPinkRgba: "rgba(237, 131, 204, 0)", gardenWhite: "#ffffff", + notifications: { + error: { + color: "#ce1126", + backgroundColor: "#FFBABA", + }, + warning: { + color: "#9F6000", + backgroundColor: "#FEEFB3", + }, + success: { + color: "#270", + backgroundColor: "#DFF2BF", + }, + info: { + color: "#059", + backgroundColor: "#BEF", + }, + }, + status: { + ready: "#2ED47A", + deploying: "#FFB946", + missing: "#F7685B", + unhealthy: "#F7685B", + }, } diff --git a/dashboard/src/util/helpers.ts b/dashboard/src/util/helpers.ts index 45f6dc2181..969868c0d2 100644 --- a/dashboard/src/util/helpers.ts +++ b/dashboard/src/util/helpers.ts @@ -32,3 +32,11 @@ export function timeConversion(millisec) { return timeFormatted } + +export const truncateMiddle = (str) => { + if (str.length > 35) { + return str.substr(0, 16) + "..." + str.substr(str.length - 16, str.length) + } + + return str +} diff --git a/garden-service/package-lock.json b/garden-service/package-lock.json index d46cb16efc..4bdcff6b27 100644 --- a/garden-service/package-lock.json +++ b/garden-service/package-lock.json @@ -412,7 +412,7 @@ }, "@types/accepts": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", + "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", "requires": { "@types/node": "*" @@ -1833,7 +1833,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "requires": { "readable-stream": "^2.3.5", @@ -3049,7 +3049,7 @@ }, "readable-stream": { "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "requires": { "core-util-is": "~1.0.0", @@ -3819,19 +3819,19 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "optional": true }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, @@ -3847,13 +3847,13 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "optional": true, "requires": { @@ -3869,25 +3869,25 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, @@ -3908,19 +3908,19 @@ }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { @@ -3929,13 +3929,13 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { @@ -3965,7 +3965,7 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, @@ -3980,7 +3980,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { @@ -3989,7 +3989,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { @@ -3999,19 +3999,19 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "optional": true }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "optional": true, "requires": { @@ -4020,13 +4020,13 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "optional": true, "requires": { @@ -4035,7 +4035,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "optional": true }, @@ -4060,7 +4060,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "optional": true, "requires": { @@ -4104,7 +4104,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { @@ -4130,7 +4130,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { @@ -4142,19 +4142,19 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "optional": true, "requires": { @@ -4163,19 +4163,19 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { @@ -4185,13 +4185,13 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, @@ -4209,7 +4209,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } @@ -4217,7 +4217,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { @@ -4247,13 +4247,13 @@ }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, @@ -4265,19 +4265,19 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "optional": true, "requires": { @@ -4288,7 +4288,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { @@ -4297,7 +4297,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "optional": true, "requires": { @@ -4306,7 +4306,7 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, @@ -4327,7 +4327,7 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, @@ -4342,7 +4342,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "optional": true }, @@ -5904,12 +5904,12 @@ }, "resolve": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" }, "source-map": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", "optional": true, "requires": { @@ -6917,7 +6917,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "mem": { @@ -11899,7 +11899,7 @@ "dependencies": { "bluebird": { "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=" }, "duplexer2": { diff --git a/garden-service/src/actions.ts b/garden-service/src/actions.ts index 1539513349..594e2cb53c 100644 --- a/garden-service/src/actions.ts +++ b/garden-service/src/actions.ts @@ -92,6 +92,10 @@ export interface EnvironmentStatus { services: { [name: string]: ServiceStatus } } +export interface EnvironmentOverview { + modules: { [name: string]: ServiceStatus }[] +} + export interface DeployServicesParams { log: LogEntry serviceNames?: string[] diff --git a/package-lock.json b/package-lock.json index 96b9186e89..de8788edac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2132,7 +2132,7 @@ "dependencies": { "callsites": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true } @@ -3741,7 +3741,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -4255,8 +4255,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -4280,15 +4279,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4305,22 +4302,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -4444,15 +4438,13 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4469,7 +4461,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4478,15 +4469,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4507,7 +4496,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4603,8 +4591,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4618,7 +4605,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4692,8 +4678,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -4735,7 +4720,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4757,7 +4741,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4799,15 +4782,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true, - "optional": true + "dev": true } } }, @@ -5410,7 +5391,7 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true } @@ -10119,7 +10100,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -10786,7 +10767,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -10935,7 +10916,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }