diff --git a/web/src/OverviewResourceSidebar.stories.tsx b/web/src/OverviewResourceSidebar.stories.tsx index 98e3a035f2..9c3ffccc25 100644 --- a/web/src/OverviewResourceSidebar.stories.tsx +++ b/web/src/OverviewResourceSidebar.stories.tsx @@ -11,6 +11,7 @@ import { tiltfileResource, twoResourceView, } from "./testdata" +import { UpdateStatus } from "./types" type Resource = Proto.webviewResource let pathBuilder = PathBuilder.forTesting("localhost", "/") @@ -53,3 +54,18 @@ export function TwoResourcesTwoTests() { let view = { resources: all, tiltfileKey: "test" } return } + +export function TestsWithErrors() { + let all: Resource[] = [tiltfileResource()] + for (let i = 0; i < 8; i++) { + let test = oneResourceTest() + test.name = "test_" + i + if (i % 2 === 0) { + test.buildHistory![0].error = "egads!" + test.updateStatus = UpdateStatus.Error + } + all.push(test) + } + let view = { resources: all, tiltfileKey: "test" } + return +} diff --git a/web/src/OverviewSidebarOptions.tsx b/web/src/OverviewSidebarOptions.tsx index 50f34c738d..51e5d3be2a 100644 --- a/web/src/OverviewSidebarOptions.tsx +++ b/web/src/OverviewSidebarOptions.tsx @@ -1,42 +1,112 @@ +import Checkbox from "@material-ui/core/Checkbox" +import FormControlLabel from "@material-ui/core/FormControlLabel" +import { makeStyles } from "@material-ui/core/styles" +import CheckBoxIcon from "@material-ui/icons/CheckBox" +import CheckBoxOutlineBlankIcon from "@material-ui/icons/CheckBoxOutlineBlank" import React from "react" import styled from "styled-components" +import { + Color, + Font, + FontSize, + mixinResetButtonStyle, + mixinResetListStyle, + SizeUnit, +} from "./style-helpers" import { SidebarOptions } from "./types" const OverviewSidebarOptionsRoot = styled.div` display: flex; + justify-content: space-between; + align-items: center; + font-family: ${Font.sansSerif}; + font-size: ${FontSize.smallester}; + padding-left: ${SizeUnit(0.5)}; + padding-right: ${SizeUnit(0.5)}; + color: ${Color.offWhite}; +` + +const FilterOptionList = styled.ul` + ${mixinResetListStyle} + display: flex; + user-select: none; // Prevent unsightly highlighting on the label +` + +const useStyles = makeStyles({ + root: { + color: Color.offWhite, + }, +}) + +const AlertsOnTopToggle = styled.button` + ${mixinResetButtonStyle} + color: ${Color.grayLightest}; + background-color: ${Color.gray}; + padding: ${SizeUnit(0.125)} ${SizeUnit(0.25)}; + border-radius: 3px; + font-size: ${FontSize.smallester}; + + &.is-enabled { + color: ${Color.grayDarkest}; + background-color: ${Color.offWhite}; + } ` type OverviewSidebarOptionsProps = { curState: SidebarOptions toggleShowResources: () => void toggleShowTests: () => void + toggleAlertsOnTop: () => void } export function OverviewSidebarOptions( props: OverviewSidebarOptionsProps ): JSX.Element { + const classes = useStyles() + return ( - - - props.toggleShowResources()} + + + } + checkedIcon={} + checked={props.curState.showResources} + onChange={(e) => props.toggleShowResources()} + name="resources" + id="resources" + /> + } + label="Resources" /> - Resources - - - props.toggleShowTests()} + } + checkedIcon={} + checked={props.curState.showTests} + onChange={(e) => props.toggleShowTests()} + name="tests" + id="tests" + /> + } + label="Tests" /> - Tests - + + + props.toggleAlertsOnTop()} + > + Alerts on Top + ) } diff --git a/web/src/SidebarResources.tsx b/web/src/SidebarResources.tsx index 3bdab37a7e..22e5666097 100644 --- a/web/src/SidebarResources.tsx +++ b/web/src/SidebarResources.tsx @@ -58,9 +58,10 @@ type SidebarProps = { type SidebarState = SidebarOptions -let defaultFilters: SidebarOptions = { +let defaultOptions: SidebarOptions = { showResources: true, showTests: true, + alertsOnTop: false, } function PinnedItems(props: SidebarProps) { @@ -86,6 +87,14 @@ function PinnedItems(props: SidebarProps) { return {pinnedItems} } +function hasAlerts(item: SidebarItem): boolean { + return item.buildAlertCount > 0 || item.runtimeAlertCount > 0 +} + +function sortByHasAlerts(itemA: SidebarItem, itemB: SidebarItem): number { + return Number(hasAlerts(itemB)) - Number(hasAlerts(itemA)) +} + export class SidebarResources extends React.Component< SidebarProps, SidebarState @@ -95,7 +104,8 @@ export class SidebarResources extends React.Component< this.triggerSelected = this.triggerSelected.bind(this) this.toggleShowResources = this.toggleShowResources.bind(this) this.toggleShowTests = this.toggleShowTests.bind(this) - this.state = defaultFilters + this.toggleAlertsOnTop = this.toggleAlertsOnTop.bind(this) + this.state = defaultOptions } triggerSelected(action: string) { @@ -120,6 +130,14 @@ export class SidebarResources extends React.Component< }) } + toggleAlertsOnTop() { + this.setState((prevState: SidebarOptions) => { + return { + alertsOnTop: !prevState.alertsOnTop, + } + }) + } + render() { let pb = this.props.pathBuilder let totalAlerts = this.props.items // Open Q: do we include alert totals for hidden elems? @@ -137,6 +155,10 @@ export class SidebarResources extends React.Component< item.isTiltfile ) + if (this.state.alertsOnTop) { + filteredItems.sort(sortByHasAlerts) + } + let listItems = filteredItems.map((item) => ( - {testsPresent ? ( - // TODO: if this vanishes because no tests present, reset it to show everything - ) : null} + {testsPresent && ( + // TODO: if this vanishes because no tests present, reset it to show everything + )} {listItems} checkmark-small.svg All @@ -43,29 +43,29 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resources resource4 Completed in 12s, with issues pin.svg @@ -152,21 +152,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource9 Completed in 12s, with issues pin.svg @@ -253,21 +253,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource19 Completed in 12s, with issues pin.svg @@ -354,21 +354,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource29 Completed in 12s, with issues pin.svg @@ -455,21 +455,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource39 Completed in 12s, with issues pin.svg @@ -556,21 +556,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource49 Completed in 12s, with issues pin.svg @@ -657,21 +657,21 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` resource54 Completed in 12s, with issues pin.svg @@ -766,38 +766,38 @@ exports[`sidebar abbreviates durations under a minute 1`] = ` exports[`sidebar renders empty resource list without crashing 1`] = ` checkmark-small.svg All @@ -807,12 +807,12 @@ exports[`sidebar renders empty resource list without crashing 1`] = ` resources @@ -822,38 +822,38 @@ exports[`sidebar renders empty resource list without crashing 1`] = ` exports[`sidebar renders list of resources 1`] = ` checkmark-small.svg All @@ -863,29 +863,29 @@ exports[`sidebar renders list of resources 1`] = ` resources vigoda Update error pin.svg @@ -974,21 +974,21 @@ exports[`sidebar renders list of resources 1`] = ` snack Update error pin.svg @@ -1085,38 +1085,38 @@ exports[`sidebar renders list of resources 1`] = ` exports[`sidebar renders resources that haven't been built yet 1`] = ` checkmark-small.svg All @@ -1126,29 +1126,29 @@ exports[`sidebar renders resources that haven't been built yet 1`] = ` resources vigoda — Updating… pin.svg @@ -1230,21 +1230,21 @@ exports[`sidebar renders resources that haven't been built yet 1`] = ` snack — Updating… pin.svg diff --git a/web/src/style-helpers.ts b/web/src/style-helpers.ts index 8f6ca3c023..b5bb7154de 100644 --- a/web/src/style-helpers.ts +++ b/web/src/style-helpers.ts @@ -111,5 +111,6 @@ export const mixinResetButtonStyle = ` border: 0 none; padding: 0; margin: 0; + font-family: inherit; cursor: pointer; ` diff --git a/web/src/types.ts b/web/src/types.ts index f9e54c9342..40308fe63d 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -142,6 +142,10 @@ export enum ResourceName { } export type SidebarOptions = { - showResources: boolean // TODO: namessss + // Which cards to show in sidebar + showResources: boolean showTests: boolean + + // Sorting options + alertsOnTop: boolean }