Skip to content

Commit

Permalink
add fullscreen option to stack state (#1130)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsladerman authored Jul 1, 2024
1 parent ebc6af6 commit b52f3e8
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 61 deletions.
21 changes: 14 additions & 7 deletions assets/src/components/stacks/run/state/State.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import { EmptyState } from '@pluralsh/design-system'
import { ReactNode } from 'react'
import { useOutletContext } from 'react-router-dom'
import { CodeEditor } from '@pluralsh/design-system'

import { StackStateGraph } from 'components/stacks/state/StackStateGraph'
import { ReactFlowProvider } from 'reactflow'

import { StackRun } from '../../../../generated/graphql'

export default function StackRunState(): ReactNode {
const { stackRun } = useOutletContext<{ stackRun: StackRun }>()
const value = JSON.stringify(stackRun.state?.state ?? {}, null, 2)
const { state } = stackRun

return (
<CodeEditor
value={value}
language="json"
options={{ readOnly: true }}
/>
<div css={{ height: '100%' }}>
{state ? (
<ReactFlowProvider>
<StackStateGraph state={state} />
</ReactFlowProvider>
) : (
<EmptyState message="No state found." />
)}
</div>
)
}
143 changes: 89 additions & 54 deletions assets/src/components/stacks/state/StackStateGraph.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { IconFrame, ReloadIcon, usePrevious } from '@pluralsh/design-system'
import {
CloseIcon,
IconFrame,
LinkoutIcon,
ReloadIcon,
WrapWithIf,
usePrevious,
} from '@pluralsh/design-system'
import { StackState } from 'generated/graphql'
import {
useCallback,
Expand All @@ -21,6 +28,8 @@ import chroma from 'chroma-js'
import 'reactflow/dist/style.css'
import styled, { useTheme } from 'styled-components'

import { useKeyDown } from '@react-hooks-library/core'

import {
type DagreDirection,
getLayoutedElements,
Expand Down Expand Up @@ -66,6 +75,10 @@ export function getNodesAndEdges(state: StackState) {
export function StackStateGraph({ state }: { state: StackState }) {
const theme = useTheme()
const margin = theme.spacing.large
const [isFullscreen, setIsFullscreen] = useState(false)

useKeyDown('Escape', () => setIsFullscreen(false))

const { nodes: initialNodes, edges: initialEdges } = useMemo(
() => getNodesAndEdges(state),
[state]
Expand Down Expand Up @@ -123,61 +136,75 @@ export function StackStateGraph({ state }: { state: StackState }) {
}, [state, prevState, setEdges, setNodes])

return (
<div
css={{
backgroundColor: theme.colors.grey['950'],
border: theme.borders.default,
width: '100%',
height: '100%',
borderRadius: theme.borderRadiuses.large,
position: 'relative',
overflow: 'hidden',
}}
<WrapWithIf
condition={isFullscreen}
wrapper={<FullScreenWrapperSC />}
>
<ReactFlowWrapperSC>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
draggable
nodesDraggable
edgesUpdatable={false}
edgesFocusable={false}
nodesConnectable={false}
edgeTypes={edgeTypes}
>
<Background
variant={BackgroundVariant.Dots}
gap={theme.spacing.large}
size={1}
color={`${chroma(theme.colors['border-fill-three']).alpha(1)}`}
/>
</ReactFlow>
<div
css={{
position: 'absolute',
top: theme.spacing.xsmall,
right: theme.spacing.xsmall,
display: 'flex',
gap: theme.spacing.xsmall,
}}
>
<IconFrame
clickable
type="floating"
icon={<ReloadIcon />}
tooltip="Reset view"
onClick={() =>
setViewport({ x: 0, y: 0, zoom: 1 }, { duration: 500 })
}
<div
css={{
backgroundColor: theme.colors.grey['950'],
border: theme.borders.default,
width: '100%',
height: '100%',
borderRadius: theme.borderRadiuses.large,
position: 'relative',
overflow: 'hidden',
}}
>
<ReactFlowWrapperSC>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
draggable
nodesDraggable
edgesUpdatable={false}
edgesFocusable={false}
nodesConnectable={false}
edgeTypes={edgeTypes}
>
<Background
variant={BackgroundVariant.Dots}
gap={theme.spacing.large}
size={1}
color={`${chroma(theme.colors['border-fill-three']).alpha(1)}`}
/>
</ReactFlow>
<div
css={{
position: 'absolute',
top: theme.spacing.xsmall,
right: theme.spacing.xsmall,
display: 'flex',
gap: theme.spacing.xsmall,
}}
>
Reset view
</IconFrame>
</div>
</ReactFlowWrapperSC>
</div>
<IconFrame
clickable
type="floating"
icon={isFullscreen ? <CloseIcon /> : <LinkoutIcon />}
tooltip={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
onClick={() => setIsFullscreen(!isFullscreen)}
>
Fullscreen
</IconFrame>
<IconFrame
clickable
type="floating"
icon={<ReloadIcon />}
tooltip="Reset view"
onClick={() =>
setViewport({ x: 0, y: 0, zoom: 1 }, { duration: 500 })
}
>
Reset view
</IconFrame>
</div>
</ReactFlowWrapperSC>
</div>
</WrapWithIf>
)
}

Expand All @@ -195,3 +222,11 @@ const ReactFlowWrapperSC = styled.div<{ $hide?: boolean }>(({ $hide }) => ({
cursor: 'unset',
},
}))

const FullScreenWrapperSC = styled.div((_) => ({
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
}))

0 comments on commit b52f3e8

Please sign in to comment.