Skip to content

Commit

Permalink
feat(dashboard): expose provider links in sidebar
Browse files Browse the repository at this point in the history
This also moves the dashboard link definitions from the plugin schema
to the environment status output, in order to accommodate dynamic links.
  • Loading branch information
edvald committed Dec 17, 2018
1 parent aeffeaf commit 48c9e13
Show file tree
Hide file tree
Showing 25 changed files with 196 additions and 103 deletions.
2 changes: 2 additions & 0 deletions garden-dashboard/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link href="https://fonts.googleapis.com/css?family=Raleway:400,400i,500,700" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/solid.css" integrity="sha384-rdyFrfAIC05c5ph7BKz3l5NG5yEottvO/DQ0dCrwD8gzeQDjYBHNr1ucUpQuljos" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/fontawesome.css" integrity="sha384-u5J7JghGz0qUrmEsWzBQkfvc8nK3fUT7DCaQzNQ+q4oEXhGSx+P2OqjWsfIRB8QT" crossorigin="anonymous">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Expand Down
2 changes: 1 addition & 1 deletion garden-dashboard/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export interface DashboardPage {

export interface Provider {
name: string
dashboardPages: DashboardPage[]
}

export interface Service {
Expand Down Expand Up @@ -70,6 +69,7 @@ export interface ServiceStatus {
export interface EnvironmentStatus {
ready: boolean
needUserInput?: boolean
dashboardPages?: DashboardPage[]
detail?: any
}

Expand Down
51 changes: 27 additions & 24 deletions garden-dashboard/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import "flexboxgrid/dist/flexboxgrid.min.css"
import "./styles/padding-margin-mixin.scss"
import { EventProvider } from "./context/events"
import { ConfigProvider } from "./context/config"
import { StatusProvider } from "./context/status"

const SidebarWrapper = styled.div`
border-right: 1px solid ${colors.border};
Expand All @@ -35,36 +36,38 @@ const SidebarWrapper = styled.div`

const App = () => (
<div>
<ConfigProvider>
<EventProvider>
<div className={css`
display: flex;
height: 100vh;
max-height: 100vh;
overflow-y: hidden;
`}>
<SidebarWrapper>
<Sidebar />
</SidebarWrapper>
<StatusProvider>
<ConfigProvider>
<EventProvider>
<div className={css`
display: flex;
flex-direction: column;
flex-grow: 1;
overflow-y: auto;
height: 100vh;
max-height: 100vh;
overflow-y: hidden;
`}>
<div className={cls(css`
background-color: ${colors.lightGray};
<SidebarWrapper>
<Sidebar />
</SidebarWrapper>
<div className={css`
display: flex;
flex-direction: column;
flex-grow: 1;
`, "p-2")}>
<Route exact path="/" component={Overview} />
<Route path="/logs/" component={Logs} />
<Route path="/graph/" component={Graph} />
<Route path="/providers/:id" component={Provider} />
overflow-y: auto;
`}>
<div className={cls(css`
background-color: ${colors.lightGray};
flex-grow: 1;
`, "p-2")}>
<Route exact path="/" component={Overview} />
<Route path="/logs/" component={Logs} />
<Route path="/graph/" component={Graph} />
<Route path="/providers/:id" component={Provider} />
</div>
</div>
</div>
</div>
</EventProvider>
</ConfigProvider>
</EventProvider>
</ConfigProvider>
</StatusProvider>
</div>
)

Expand Down
34 changes: 21 additions & 13 deletions garden-dashboard/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { css } from "emotion/macro"
import styled from "@emotion/styled/macro"
import React, { Component } from "react"

Expand Down Expand Up @@ -36,14 +37,17 @@ const Button = styled.li`
}
`

const Link = styled(NavLink)`
const linkStyle = `
display: inline-block;
font-size: 1.025rem;
margin-left: 1.5rem;
padding: 0.5em 0.5em 0.5em 0;
width: 100%;
`

const A = styled.a(linkStyle)
const Link = styled(NavLink)(linkStyle)

// Style and align properly
const Logo = styled.img`
height: auto;
Expand All @@ -59,11 +63,6 @@ class Sidebar extends Component<Props, State> {
this.state = {
selectedTab: this.props.pages[0].path,
}
this.handleClick = this.handleClick.bind(this)
}

handleClick(event) {
this.setState({ selectedTab: event.target.path })
}

render() {
Expand All @@ -76,16 +75,25 @@ class Sidebar extends Component<Props, State> {
</div>
<nav>
<ul className="pt-2">
{this.props.pages.map(page => (
<Button tabName={name} onClick={this.handleClick} key={page.title}>
<Link
{this.props.pages.map(page => {
const link = page.url
? <A href={page.url} target="_blank" title={page.description}>
{page.title}
<i className={`${css("color: #ccc; margin-left: 0.5em;")} fas fa-external-link-alt`}></i>
</A>
: <Link
exact
to={{ pathname: page.path, state: page }}
title={page.description}>{page.title}
title={page.description}>
{page.title}
</Link>
</Button>
),
)}

return (
<Button tabName={name} key={page.title}>
{link}
</Button>
)
})}
</ul>
</nav>
</div>
Expand Down
16 changes: 5 additions & 11 deletions garden-dashboard/src/containers/overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,14 @@ import React from "react"

import { ConfigConsumer } from "../context/config"
import Overview from "../components/overview"
import FetchContainer from "./fetch-container"
import { fetchStatus } from "../api"
// tslint:disable-next-line:no-unused (https://github.com/palantir/tslint/issues/4022)
import { FetchStatusResponse } from "../api/types"
import PageError from "../components/page-error"
import { StatusConsumer } from "../context/status"

export default () => (
<FetchContainer<FetchStatusResponse> ErrorComponent={PageError} fetchFn={fetchStatus}>
{({ data: status }) => (
<StatusConsumer>
{({ status }) => (
<ConfigConsumer>
{({ config }) => {
return <Overview config={config} status={status} />
}}
{({ config }) => <Overview config={config} status={status} />}
</ConfigConsumer>
)}
</FetchContainer>
</StatusConsumer>
)
22 changes: 13 additions & 9 deletions garden-dashboard/src/containers/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

import { flatten, kebabCase } from "lodash"
import { kebabCase, flatten, entries } from "lodash"
import React from "react"

import { ConfigConsumer } from "../context/config"
import Sidebar from "../components/sidebar"
import { DashboardPage } from "../api/types"
import { StatusConsumer } from "../context/status"

export interface Page extends DashboardPage {
path: string
Expand Down Expand Up @@ -42,13 +42,17 @@ const builtinPages: Page[] = [
]

export default () => (
<ConfigConsumer>
{({ config }) => {
const pages = flatten(config.providers.map(p => p.dashboardPages)).map((p: Page) => {
p.path = `/provider/${kebabCase(p.title)}`
return p
})
<StatusConsumer>
{({ status }) => {
const pages: Page[] = flatten(entries(status.providers).map(([providerName, providerStatus]) => {
return providerStatus.dashboardPages.map(p => ({
...p,
path: `/provider/${providerName}/${kebabCase(p.title)}`,
description: p.description + ` (from provider ${providerName})`,
}))
}))

return <Sidebar pages={[...builtinPages, ...pages]} />
}}
</ConfigConsumer>
</StatusConsumer>
)
2 changes: 1 addition & 1 deletion garden-dashboard/src/context/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ConfigContext = React.createContext<Context | null>(null)

const ConfigConsumer = ConfigContext.Consumer

const Error = () => <p>Error loading sidebar</p>
const Error = () => <p>Error loading project configuration. Please try refreshing the page.</p>

const ConfigProvider = ({ children }) => (
<FetchContainer<FetchConfigResponse> ErrorComponent={Error} skipSpinner fetchFn={fetchConfig}>
Expand Down
32 changes: 32 additions & 0 deletions garden-dashboard/src/context/status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2018 Garden Technologies, Inc. <info@garden.io>
*
* 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 { fetchStatus } from "../api"
import { FetchStatusResponse } from "../api/types"
import FetchContainer from "../containers/fetch-container"

type Context = { status: FetchStatusResponse }
const StatusContext = React.createContext<Context | null>(null)

const StatusConsumer = StatusContext.Consumer

const Error = () => <p>Error retrieving status</p>

const StatusProvider = ({ children }) => (
<FetchContainer<FetchStatusResponse> ErrorComponent={Error} skipSpinner fetchFn={fetchStatus}>
{({ data: status }) => (
<StatusContext.Provider value={{ status }}>
{children}
</StatusContext.Provider>
)}
</FetchContainer>
)

export { StatusProvider, StatusConsumer }
1 change: 1 addition & 0 deletions garden-service/gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module.exports = (gulp) => {
"--declaration",
"-p", tsConfigPath,
"--outDir", destDir,
"--rootDir", resolve(__dirname, "src"),
"--preserveWatchOutput",
],
),
Expand Down
8 changes: 6 additions & 2 deletions garden-service/src/commands/get/get-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import * as yaml from "js-yaml"
import { highlightYaml } from "../../util/util"
import { highlightYaml, deepFilter } from "../../util/util"
import {
Command,
CommandResult,
Expand All @@ -21,7 +21,11 @@ export class GetStatusCommand extends Command {

async action({ garden, log }: CommandParams): Promise<CommandResult<EnvironmentStatus>> {
const status = await garden.actions.getStatus({ log })
const yamlStatus = yaml.safeDump(status, { noRefs: true, skipInvalid: true })

// TODO: we should change the status format because this will remove services called "detail"
const withoutDetail = deepFilter(status, (_, key) => key !== "detail")

const yamlStatus = yaml.safeDump(withoutDetail, { noRefs: true, skipInvalid: true })

// TODO: do a nicer print of this by default and use --yaml/--json options for exporting
log.info(highlightYaml(yamlStatus))
Expand Down
3 changes: 0 additions & 3 deletions garden-service/src/config/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
Primitive,
joiRepositoryUrl,
} from "./common"
import { DashboardPage } from "../config/dashboard"

export interface ProviderConfig {
name: string
Expand All @@ -33,7 +32,6 @@ export const providerConfigBaseSchema = Joi.object()

export interface Provider<T extends ProviderConfig = any> {
name: string
dashboardPages: DashboardPage[]
config: T
}

Expand Down Expand Up @@ -148,6 +146,5 @@ export const projectSchema = Joi.object()
// this is used for default handlers in the action handler
export const defaultProvider: Provider = {
name: "_default",
dashboardPages: [],
config: {},
}
1 change: 0 additions & 1 deletion garden-service/src/garden.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,6 @@ export class Garden {
} else {
const provider: Provider = {
name: pluginName,
dashboardPages: plugin.dashboardPages,
config: extend({ name: pluginName }, plugin.config, config),
}
this.environment.providers.push(provider)
Expand Down
2 changes: 0 additions & 2 deletions garden-service/src/plugin-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
import { joiIdentifier, joiIdentifierMap } from "./config/common"
import { PluginError } from "./exceptions"
import { defaultProvider } from "./config/project"
import { dashboardPagesSchema } from "./config/dashboard"

type WrappedFromGarden = Pick<Garden,
"projectName" |
Expand All @@ -35,7 +34,6 @@ const providerSchema = Joi.object()
.keys({
name: joiIdentifier()
.description("The name of the provider (plugin)."),
dashboardPages: dashboardPagesSchema,
config: providerConfigBaseSchema,
})

Expand Down
3 changes: 2 additions & 1 deletion garden-service/src/plugins/kubernetes/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ export async function getContainerServiceStatus(

// FIXME: [objects, matched] and ingresses can be run in parallel
const objects = await createContainerObjects(ctx, service, runtimeContext, enableHotReload)
const state = await compareDeployedObjects(ctx, objects)
const { state, remoteObjects } = await compareDeployedObjects(ctx, objects)
const ingresses = await getIngresses(service, api)

return {
ingresses,
state,
version: state === "ready" ? version.versionString : undefined,
detail: { remoteObjects },
}
}

Expand Down
11 changes: 8 additions & 3 deletions garden-service/src/plugins/kubernetes/helm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,11 @@ async function getServiceStatus(

// first check if the installed objects on the cluster match the current code
const objects = await getChartObjects(ctx, service, log)
let state = await compareDeployedObjects(ctx, objects)
let { state, remoteObjects } = await compareDeployedObjects(ctx, objects)
const detail = { remoteObjects }

if (state !== "ready") {
return { state }
return { state, detail }
}

// then check if the rollout is complete
Expand All @@ -329,7 +330,11 @@ async function getServiceStatus(
// TODO: set state to "unhealthy" if any status is "unhealthy"
state = ready ? "ready" : "deploying"

return { state, version: version.versionString }
return {
state,
version: version.versionString,
detail,
}
}

function getReleaseName(namespace: string, service: Service) {
Expand Down

0 comments on commit 48c9e13

Please sign in to comment.