Skip to content

Commit

Permalink
Added card selection when card stack is expanded.
Browse files Browse the repository at this point in the history
  • Loading branch information
vagarenko authored and codablock committed Jun 9, 2023
1 parent 5ce0efa commit 1c5419f
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 89 deletions.
17 changes: 7 additions & 10 deletions pkg/webui/ui/src/components/LeftDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ import { KluctlLogo, TargetsIcon, KluctlText, SearchIcon, ArrowLeftIcon } from '
import { dark } from './theme';
import { Typography } from '@mui/material';

const drawerWidthOpen = 224;
const drawerWidthClosed = 96;

const openedMixin = (theme: Theme): CSSObject => ({
width: drawerWidthOpen,
width: theme.consts.leftDrawerWidthOpen,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
Expand All @@ -35,7 +32,7 @@ const closedMixin = (theme: Theme): CSSObject => ({
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: drawerWidthClosed,
width: theme.consts.leftDrawerWidthClosed,
});

const DrawerHeader = styled('div')(({ theme }) => ({
Expand All @@ -57,17 +54,17 @@ const AppBar = styled(MuiAppBar, {
boxShadow: 'none',
background: 'transparent',
padding: '40px 40px 0 40px',
marginLeft: drawerWidthClosed,
marginLeft: theme.consts.leftDrawerWidthClosed,
justifyContent: 'space-between',
width: `calc(100% - ${drawerWidthClosed}px)`,
width: `calc(100% - ${theme.consts.leftDrawerWidthClosed}px)`,
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
marginLeft: drawerWidthOpen,
width: `calc(100% - ${drawerWidthOpen}px)`,
marginLeft: theme.consts.leftDrawerWidthOpen,
width: `calc(100% - ${theme.consts.leftDrawerWidthOpen}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
Expand All @@ -77,7 +74,7 @@ const AppBar = styled(MuiAppBar, {

const Drawer = styled(MuiDrawer, { shouldForwardProp: (prop) => prop !== 'open' })(
({ theme, open }) => ({
width: drawerWidthOpen,
width: theme.consts.leftDrawerWidthOpen,
flexShrink: 0,
whiteSpace: 'nowrap',
boxSizing: 'border-box',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { NodeBuilder } from "../result-view/nodes/NodeBuilder";
import { Suspense, useEffect, useState } from "react";
import { NodeData } from "../result-view/nodes/NodeData";
import { SidePanel } from "../result-view/SidePanel";
import { Box, Drawer, ThemeProvider } from "@mui/material";
import { Box, Drawer, ThemeProvider, useTheme } from "@mui/material";
import { Loading } from "../Loading";
import { dark, light } from "../theme";
import { dark } from "../theme";
import { Card, CardCol } from "./Card";
import { CommandResultItem } from "./CommandResultItem";
import React from "react";

const sidePanelWidth = 720;

Expand All @@ -25,68 +26,81 @@ async function doGetRootNode(rs: CommandResultSummary) {
return node
}

export const CommandResultDetailsDrawer = (props: { rs?: CommandResultSummary, ts?: TargetSummary, ps?: ProjectSummary, onClose: () => void }) => {
const [prevId, setPrevId] = useState<string>()
const [promise, setPromise] = useState<Promise<NodeData>>(new Promise(() => undefined))
export const CommandResultDetailsDrawer = React.memo((props: {
rs?: CommandResultSummary,
ts?: TargetSummary,
ps?: ProjectSummary,
onClose: () => void
}) => {
const { ps, ts } = props;
const theme = useTheme();
const [promise, setPromise] = useState<Promise<NodeData>>(new Promise(() => undefined));
const [selectedCommandResult, setSelectedCommandResult] = useState<CommandResultSummary | undefined>();
const [prevTargetSummary, setPrevTargetSummary] = useState<TargetSummary | undefined>(ts);

if (prevTargetSummary !== ts) {
setPrevTargetSummary(ts);
setSelectedCommandResult(ts?.commandResults?.[0]);
}

useEffect(() => {
if (props.rs === undefined) {
return
}
if (props.rs.id === prevId) {
if (selectedCommandResult === undefined) {
return
}
setPrevId(props.rs.id)
setPromise(doGetRootNode(props.rs))
}, [props.rs, prevId])
setPromise(doGetRootNode(selectedCommandResult));
}, [selectedCommandResult])

const Content = (props: { onClose: () => void }) => {
const node = usePromise(promise)
return <SidePanel provider={node} onClose={props.onClose} />
}

const { ps, ts } = props;

return <ThemeProvider theme={dark}>
<Drawer
sx={{ zIndex: 1300 }}
anchor={"right"}
open={props.rs !== undefined}
onClose={props.onClose}
>
<Box width={sidePanelWidth} height={"100%"}>
<Suspense fallback={<Loading />}>
<Content onClose={props.onClose} />
</Suspense>
return <>
{ps && ts &&
<Box
sx={{
position: 'fixed',
top: 0,
bottom: 0,
right: sidePanelWidth,
width: `calc(100% - ${sidePanelWidth}px)`,
overflow: 'auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '25px 0',
zIndex: theme.zIndex.modal + 1
}}
onClick={props.onClose}
>
<CardCol onClick={(e) => e.stopPropagation()} flexGrow={1} justifyContent='center'>
{ts.commandResults?.map((rs, i) => {
return <Card key={i}>
<CommandResultItem
ps={ps}
ts={ts}
rs={rs}
onSelectCommandResult={setSelectedCommandResult}
selected={rs === selectedCommandResult}
/>
</Card>
})}
</CardCol>
</Box>
<ThemeProvider theme={light}>
<Box
sx={{
position: 'fixed',
top: 0,
bottom: 0,
left: 0,
right: sidePanelWidth,
padding: '30px',
overflow: 'auto',
display: 'flex',
justifyContent: 'center'
}}
>
<CardCol>
{ps && ts?.commandResults?.map((rs, i) => {
return <Card key={i} >
<CommandResultItem
ps={ps}
ts={ts}
rs={rs}
onSelectCommandResult={() => { }}
/>
</Card>
})}
</CardCol>
}
<ThemeProvider theme={dark}>
<Drawer
sx={{ zIndex: 1300 }}
anchor={"right"}
open={props.rs !== undefined}
onClose={props.onClose}
>
<Box width={sidePanelWidth} height={"100%"}>
<Suspense fallback={<Loading />}>
<Content onClose={props.onClose} />
</Suspense>
</Box>
</ThemeProvider>
</Drawer>
</ThemeProvider>
}
</Drawer>
</ThemeProvider>
</>
});
32 changes: 20 additions & 12 deletions pkg/webui/ui/src/components/targets-view/CommandResultItem.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from "react";
import { CommandResultSummary, ProjectSummary, TargetSummary } from "../../models";
import { useEffect, useMemo, useState } from "react";
import * as yaml from "js-yaml";
Expand All @@ -9,16 +10,22 @@ import { useNavigate } from "react-router";
import { formatDurationShort } from "../../utils/duration";
import { DeployIcon, DiffIcon, PruneIcon, TreeViewIcon } from "../../icons/Icons";

export const CommandResultItem = (props: { ps: ProjectSummary, ts: TargetSummary, rs: CommandResultSummary, onSelectCommandResult: (rs: CommandResultSummary) => void }) => {
const calcAgo = () => {
const t1 = new Date(props.rs.commandInfo.startTime)
const t2 = new Date()
const d = t2.getTime() - t1.getTime()
return formatDurationShort(d)
}
const calcAgo = (startTime: string) => {
const t1 = new Date(startTime)
const t2 = new Date()
const d = t2.getTime() - t1.getTime()
return formatDurationShort(d)
}

export const CommandResultItem = React.memo((props: {
ps: ProjectSummary,
ts: TargetSummary,
rs: CommandResultSummary,
onSelectCommandResult: (rs: CommandResultSummary) => void,
selected?: boolean;
}) => {
const navigate = useNavigate()
const [ago, setAgo] = useState(calcAgo())
const [ago, setAgo] = useState(calcAgo(props.rs.commandInfo.startTime))

let Icon: () => JSX.Element = DiffIcon
switch (props.rs.commandInfo?.command) {
Expand All @@ -45,9 +52,9 @@ export const CommandResultItem = (props: { ps: ProjectSummary, ts: TargetSummary
let iconTooltip = <CodeViewer code={cmdInfoYaml} language={"yaml"} />

useEffect(() => {
const interval = setInterval(() => setAgo(calcAgo()), 5000);
const interval = setInterval(() => setAgo(calcAgo(props.rs.commandInfo.startTime)), 5000);
return () => clearInterval(interval);
}, [])
}, [props.rs.commandInfo.startTime])

return <Paper
elevation={5}
Expand All @@ -57,7 +64,8 @@ export const CommandResultItem = (props: { ps: ProjectSummary, ts: TargetSummary
borderRadius: '12px',
border: '1px solid #59A588',
boxShadow: '4px 4px 10px #1E617A',
padding: '20px 16px 5px 16px'
padding: '20px 16px 5px 16px',
outline: props.selected ? '8px solid #59A588' : 'none'
}}
onClick={e => props.onSelectCommandResult(props.rs)}
>
Expand Down Expand Up @@ -116,4 +124,4 @@ export const CommandResultItem = (props: { ps: ProjectSummary, ts: TargetSummary
</Box>
</Box>
</Paper>
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,18 @@ class MyProvider implements SidePanelProvider {
}
}

export const TargetDetailsDrawer = (props: { ts?: TargetSummary, onClose: () => void }) => {
export const TargetDetailsDrawer = React.memo((props: { ts?: TargetSummary, onClose: () => void }) => {
return <ThemeProvider theme={dark}>
<Drawer
sx={{ zIndex: 1300 }}
anchor={"right"}
open={props.ts !== undefined}
onClose={props.onClose}
ModalProps={{ BackdropProps: { invisible: true }}}
ModalProps={{ BackdropProps: { invisible: true } }}
>
<Box width={"382px"} height={"100%"}>
<SidePanel provider={new MyProvider(props.ts)} onClose={props.onClose}/>
<SidePanel provider={new MyProvider(props.ts)} onClose={props.onClose} />
</Box>
</Drawer>
</ThemeProvider>;
}
});
23 changes: 16 additions & 7 deletions pkg/webui/ui/src/components/targets-view/TargetsView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useLoaderData } from "react-router-dom";
import { CommandResultSummary, ProjectSummary, TargetSummary } from "../../models";
import { Box, Typography, useTheme } from "@mui/material";
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useAppOutletContext } from "../App";
import { getApi } from "../../api";
import { ProjectItem } from "./Projects";
Expand Down Expand Up @@ -140,25 +140,34 @@ export const TargetsView = () => {
context.setFilters(undefined)
})

const doSetSelectedCommandResult = (o?: {rs: CommandResultSummary, ts: TargetSummary, ps: ProjectSummary}) => {
const doSetSelectedCommandResult = useCallback((o?: {rs: CommandResultSummary, ts: TargetSummary, ps: ProjectSummary}) => {
setSelectedCommandResult(o);
setSelectedTargetSummary(undefined);
}
const doSetSelectedTargetSummary = (ts?: TargetSummary) => {
}, []);

const doSetSelectedTargetSummary = useCallback((ts?: TargetSummary) => {
setSelectedCommandResult(undefined);
setSelectedTargetSummary(ts);
}
}, []);

const onCommandResultDetailsDrawerClose = useCallback(() => {
doSetSelectedCommandResult(undefined);
}, [doSetSelectedCommandResult]);

const onTargetDetailsDrawerClose = useCallback(() => {
setSelectedTargetSummary(undefined);
}, [setSelectedTargetSummary]);

return <Box minWidth={colWidth * 3} p='0 40px'>
<CommandResultDetailsDrawer
rs={selectedCommandResult?.rs}
ts={selectedCommandResult?.ts}
ps={selectedCommandResult?.ps}
onClose={() => doSetSelectedCommandResult(undefined)}
onClose={onCommandResultDetailsDrawerClose}
/>
<TargetDetailsDrawer
ts={selectedTargetSummary}
onClose={() => setSelectedTargetSummary(undefined)}
onClose={onTargetDetailsDrawerClose}
/>
<Box display={"flex"} alignItems={"center"} height='70px'>
<ColHeader>Projects</ColHeader>
Expand Down
20 changes: 19 additions & 1 deletion pkg/webui/ui/src/components/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,40 @@ declare module '@mui/material/styles' {
interface Theme {
consts: {
appBarHeight: number;
leftDrawerWidthOpen: number;
leftDrawerWidthClosed: number;
};
}
// allow configuration using `createTheme`
interface ThemeOptions {
consts?: {
appBarHeight?: number;
leftDrawerWidthOpen?: number;
leftDrawerWidthClosed?: number;
};
}
}

export const common = createTheme({
consts: {
appBarHeight: 106
appBarHeight: 106,
leftDrawerWidthOpen: 224,
leftDrawerWidthClosed: 96
},
typography: {
fontFamily: 'Nunito Variable',
},
components: {
MuiBackdrop: {
styleOverrides: {
root: {
backgroundColor: 'rgba(0, 0, 0, 0.65)'
},
invisible: {
backgroundColor: 'transparent'
}
}
}
}
});

Expand Down

0 comments on commit 1c5419f

Please sign in to comment.