@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
22import { RequestHistory } from "../panels/RequestHistory" ;
33import "./Dashboard.css" ;
44import { Panel , PanelType } from "@fluentui/react" ;
5- import { Tab , TabList , Accordion , AccordionHeader , AccordionItem , AccordionPanel , ToggleButton , CounterBadge } from "@fluentui/react-components" ;
5+ import { Tab , TabList , Accordion , AccordionHeader , AccordionItem , AccordionPanel , ToggleButton , CounterBadge , Button } from "@fluentui/react-components" ;
66import * as svg from "./icons" ;
77import { DocumentOnePageMultiple24Regular , Link24Regular } from "@fluentui/react-icons" ;
88import type { SelectTabData , SelectTabEvent } from "@fluentui/react-components" ;
@@ -46,6 +46,8 @@ export const Dashboard = () => {
4646 const [ showPanel , setShowPanel ] = useState ( false ) ;
4747 const [ clientConnectionStatus , setClientConnectionStatus ] = useState ( ConnectionStatus . Disconnected ) ;
4848 const { data, dataFetcher } = useDataContext ( ) ;
49+ const isManual = dataFetcher . kind === "manual" ;
50+ const [ isFullscreen , setIsFullscreen ] = useState < boolean > ( isManual ) ;
4951 const [ tunnelUnread , setTunnelUnread ] = useState ( 0 ) ;
5052 const onStartUpstream = async ( start : boolean ) => {
5153 return start ? await dataFetcher . invoke ( "startEmbeddedUpstream" ) : await dataFetcher . invoke ( "stopEmbeddedUpstream" ) ;
@@ -127,13 +129,29 @@ export const Dashboard = () => {
127129 // read current tab from local storage
128130 const [ selectedValue , setSelectedValue ] = React . useState < string > ( loadCurrentTab ( ) ) ;
129131
132+ useEffect ( ( ) => {
133+ if ( isManual && selectedValue !== "client" ) {
134+ setSelectedValue ( "client" ) ;
135+ }
136+ } , [ isManual , selectedValue ] ) ;
137+
138+ useEffect ( ( ) => {
139+ const previousTitle = document . title ;
140+ document . title = isManual ? "Azure Web PubSub Quick Try" : "Azure Web PubSub Local Development Dashboard" ;
141+ return ( ) => {
142+ document . title = previousTitle ;
143+ } ;
144+ } , [ isManual ] ) ;
145+
130146 useEffect ( ( ) => {
131147 setCurrentTab ( selectedValue ) ;
132148 } , [ selectedValue ] ) ;
133149
150+ const visibleWorkflows = isManual ? workflows . filter ( ( w ) => w . key === "client" ) : workflows ;
151+
134152 const workflow = ( ) => (
135153 < div className = "workflow d-flex flex-row justify-content-center align-items-center m-2" >
136- { workflows . map ( ( w , i ) => (
154+ { visibleWorkflows . map ( ( w , i ) => (
137155 < React . Fragment key = { i } >
138156 < WorkflowStep checked = { selectedValue === w . key } unread = { w . unread } onClick = { ( ) => setSelectedValue ( w . key ) } icon = { w . icon ( true ) } text = { w . title } />
139157 { w . status && < Connector status = { w . status } /> }
@@ -147,17 +165,21 @@ export const Dashboard = () => {
147165 setSelectedValue ( data . value as string ) ;
148166 } ;
149167
168+ const tabList = (
169+ < TabList size = "large" className = "m-2" selectedValue = { selectedValue } onTabSelect = { onTabSelect } vertical = { ! isFullscreen } >
170+ { visibleWorkflows . map ( ( w , i ) => (
171+ < React . Fragment key = { i } >
172+ < Tab id = { w . key } icon = { < span > { w . icon ( ) } </ span > } value = { w . key } >
173+ { w . title } { w . unread > 0 && < CounterBadge size = "small" count = { w . unread } > </ CounterBadge > }
174+ </ Tab >
175+ </ React . Fragment >
176+ ) ) }
177+ </ TabList >
178+ ) ;
179+
150180 const tabSidebar = (
151181 < >
152- < TabList size = "large" className = "m-2" selectedValue = { selectedValue } onTabSelect = { onTabSelect } vertical >
153- { workflows . map ( ( w , i ) => (
154- < React . Fragment key = { i } >
155- < Tab id = { w . key } icon = { < span > { w . icon ( ) } </ span > } value = { w . key } >
156- { w . title } { w . unread > 0 && < CounterBadge size = "small" count = { w . unread } > </ CounterBadge > }
157- </ Tab >
158- </ React . Fragment >
159- ) ) }
160- </ TabList >
182+ { tabList }
161183 < Accordion collapsible >
162184 < AccordionItem value = "1" >
163185 < AccordionHeader > Help center</ AccordionHeader >
@@ -189,29 +211,51 @@ export const Dashboard = () => {
189211 ) ;
190212 const connectPane = (
191213 < >
192- { workflows . map ( ( w , i ) => (
214+ { visibleWorkflows . map ( ( w , i ) => (
193215 // Use hidden to prevent re-rendering
194216 < div key = { i } hidden = { selectedValue !== w . key } className = "d-flex flex-column flex-fill overflow-auto" >
195- < Accordion className = "" collapsible defaultOpenItems = { "1" } >
196- < AccordionItem value = "1" >
197- < AccordionHeader size = "large" > { w . title } </ AccordionHeader >
198- < AccordionPanel > { paneOverview ( w ) } </ AccordionPanel >
199- </ AccordionItem >
200- </ Accordion >
201- < hr />
217+ { ! isManual && (
218+ < >
219+ < Accordion className = "" collapsible defaultOpenItems = { "1" } >
220+ < AccordionItem value = "1" >
221+ < AccordionHeader size = "large" > { w . title } </ AccordionHeader >
222+ < AccordionPanel > { paneOverview ( w ) } </ AccordionPanel >
223+ </ AccordionItem >
224+ </ Accordion >
225+ < hr />
226+ </ >
227+ ) }
202228 { w . content }
203229 </ div >
204230 ) ) }
205231 </ >
206232 ) ;
207233
234+ const fullscreenNav = visibleWorkflows . length > 1 ? (
235+ < div className = "d-flex flex-row align-items-center justify-content-start mx-2" > { tabList } </ div >
236+ ) : null ;
237+
208238 return (
209239 < div className = "d-flex flex-column flex-fill overflow-auto" >
210240 < Panel type = { PanelType . medium } className = "logPanel" isLightDismiss isOpen = { showPanel } onDismiss = { ( ) => setShowPanel ( false ) } closeButtonAriaLabel = "Close" headerText = "Logs" >
211241 < textarea className = "flex-fill" disabled value = { data . logs . map ( ( log ) => `${ log . time . toISOString ( ) } [${ LogLevel [ log . level ] } ] ${ log . message } ` ) . join ( "\n" ) } />
212242 </ Panel >
213- { workflow ( ) }
214- < ResizablePanel className = "flex-fill" left = { tabSidebar } right = { connectPane } initialLeftWidth = "200px" > </ ResizablePanel >
243+ { ! isManual && (
244+ < div className = "d-flex flex-row justify-content-end align-items-center mx-2 my-1" >
245+ < Button size = "small" appearance = { isFullscreen ? "secondary" : "primary" } onClick = { ( ) => setIsFullscreen ( ( f ) => ! f ) } >
246+ { isFullscreen ? "Exit fullscreen" : "Enter fullscreen" }
247+ </ Button >
248+ </ div >
249+ ) }
250+ { ! isFullscreen && workflow ( ) }
251+ { isFullscreen ? (
252+ < div className = "d-flex flex-column flex-fill overflow-auto" >
253+ { fullscreenNav }
254+ { connectPane }
255+ </ div >
256+ ) : (
257+ < ResizablePanel className = "flex-fill" left = { tabSidebar } right = { connectPane } initialLeftWidth = "200px" > </ ResizablePanel >
258+ ) }
215259 </ div >
216260 ) ;
217261} ;
0 commit comments