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" /> - -
-
- props.toggleShowTests()} + } + checkedIcon={} + checked={props.curState.showTests} + onChange={(e) => props.toggleShowTests()} + name="tests" + id="tests" + /> + } + label="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
    • resource9
      Completed in 12s, with issues
    • resource19
      Completed in 12s, with issues
    • resource29
      Completed in 12s, with issues
    • resource39
      Completed in 12s, with issues
    • resource49
      Completed in 12s, with issues
    • resource54
      Completed in 12s, with issues
      Update error
    • snack
      Update error
      Updating…
    • snack
      Updating…