github.com/tilt-dev/tilt@v0.36.0/web/src/OverviewResourcePane.tsx (about) 1 import React, { useEffect, useState } from "react" 2 import SplitPane from "react-split-pane" 3 import styled from "styled-components" 4 import { Alert, combinedAlerts } from "./alerts" 5 import { ApiButtonType, buttonsForComponent } from "./ApiButton" 6 import HeaderBar, { HeaderBarPage } from "./HeaderBar" 7 import { LogUpdateAction, LogUpdateEvent, useLogStore } from "./LogStore" 8 import OverviewResourceDetails from "./OverviewResourceDetails" 9 import OverviewResourceSidebar from "./OverviewResourceSidebar" 10 import "./Resizer.scss" 11 import { useResourceNav } from "./ResourceNav" 12 import { useSidebarContext } from "./SidebarContext" 13 import StarredResourceBar, { 14 starredResourcePropsFromView, 15 } from "./StarredResourceBar" 16 import { Color, Width } from "./style-helpers" 17 import { ResourceName, UIResource } from "./types" 18 19 type OverviewResourcePaneProps = { 20 view: Proto.webviewView 21 isSocketConnected: boolean 22 } 23 24 let OverviewResourcePaneRoot = styled.div` 25 display: flex; 26 flex-direction: column; 27 width: 100%; 28 height: 100vh; 29 background-color: ${Color.gray20}; 30 max-height: 100%; 31 ` 32 let Main = styled.div` 33 display: flex; 34 width: 100%; 35 // In Safari, flex-basis "auto" squishes OverviewTabBar + OverviewResourceBar 36 flex: 1 1 100%; 37 overflow: hidden; 38 position: relative; 39 40 .SplitPane { 41 position: relative !important; 42 } 43 .Pane { 44 display: flex; 45 } 46 ` 47 48 export default function OverviewResourcePane(props: OverviewResourcePaneProps) { 49 let nav = useResourceNav() 50 const logStore = useLogStore() 51 let resources = props.view?.uiResources || [] 52 let name = nav.invalidResource || nav.selectedResource || "" 53 let r: UIResource | undefined 54 let all = name === "" || name === ResourceName.all 55 let starred = name === ResourceName.starred 56 if (!all) { 57 r = resources.find((r) => r.metadata?.name === name) 58 } 59 let selectedTab = "" 60 if (all) { 61 selectedTab = ResourceName.all 62 } else if (starred) { 63 selectedTab = ResourceName.starred 64 } else if (r?.metadata?.name) { 65 selectedTab = r.metadata.name 66 } 67 68 const { isSidebarOpen, setSidebarOpen, setSidebarClosed } = 69 useSidebarContext() 70 71 const [paneSize, setPaneSize] = useState<number>( 72 isSidebarOpen ? Width.sidebarDefault : Width.sidebarMinimum 73 ) 74 75 // listen for changes from sidebar context in case it was toggled instead 76 // being dragged past a breakpoint. 77 useEffect(() => { 78 setPaneSize( 79 isSidebarOpen ? Width.sidebarDefault : Width.sidebarMinimum + 0.01 80 // adds 0.01 so there's still a state diff when the user releases after dragging 81 ) 82 }, [isSidebarOpen]) 83 84 const [truncateCount, setTruncateCount] = useState<number>(0) 85 86 // add a listener to rebuild alerts whenever a truncation event occurs 87 // truncateCount is a dummy state variable to trigger a re-render to 88 // simplify logic vs reconciliation between logStore + props 89 useEffect(() => { 90 const rebuildAlertsOnLogClear = (e: LogUpdateEvent) => { 91 if (e.action === LogUpdateAction.truncate) { 92 setTruncateCount(truncateCount + 1) 93 } 94 } 95 96 logStore.addUpdateListener(rebuildAlertsOnLogClear) 97 return () => logStore.removeUpdateListener(rebuildAlertsOnLogClear) 98 }, [truncateCount]) 99 100 let alerts: Alert[] = [] 101 if (r) { 102 alerts = combinedAlerts(r, logStore) 103 } else if (all) { 104 resources.forEach((r) => alerts.push(...combinedAlerts(r, logStore))) 105 } 106 107 const buttons = buttonsForComponent( 108 props.view.uiButtons, 109 ApiButtonType.Resource, 110 name 111 ) 112 113 const handleSplitPaneResize = (newSize: number) => { 114 if (newSize < Width.sidebarBreakpoint && isSidebarOpen) { 115 setSidebarClosed() 116 } else if (newSize >= Width.sidebarBreakpoint && !isSidebarOpen) { 117 setSidebarOpen() 118 } 119 } 120 121 return ( 122 <OverviewResourcePaneRoot> 123 <HeaderBar 124 view={props.view} 125 currentPage={HeaderBarPage.Detail} 126 isSocketConnected={props.isSocketConnected} 127 /> 128 <StarredResourceBar 129 {...starredResourcePropsFromView(props.view, selectedTab)} 130 /> 131 <Main> 132 <SplitPane 133 split="vertical" 134 size={paneSize} 135 minSize={Width.sidebarMinimum} 136 onChange={handleSplitPaneResize} 137 onDragFinished={() => 138 setPaneSize( 139 isSidebarOpen ? Width.sidebarDefault : Width.sidebarMinimum 140 ) 141 } 142 > 143 <OverviewResourceSidebar {...props} name={name} /> 144 <OverviewResourceDetails 145 resource={r} 146 name={name} 147 alerts={alerts} 148 buttons={buttons} 149 /> 150 </SplitPane> 151 </Main> 152 </OverviewResourcePaneRoot> 153 ) 154 }