Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): Refresh Rollouts dashboard UI #2723

Merged
merged 15 commits into from Apr 21, 2023
8 changes: 6 additions & 2 deletions ui/package.json
Expand Up @@ -3,6 +3,10 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.0",
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"antd": "^5.4.2",
"argo-ui": "git+https://github.com/argoproj/argo-ui.git",
"classnames": "2.2.6",
"isomorphic-fetch": "^3.0.0",
Expand All @@ -16,7 +20,7 @@
"react-keyhooks": "^0.2.3",
"react-router-dom": "5.2.0",
"rxjs": "^6.6.6",
"typescript": "4.3.5",
"typescript": "^5.0.4",
"web-vitals": "^1.0.1"
},
"scripts": {
Expand Down Expand Up @@ -69,4 +73,4 @@
"resolutions": {
"@types/react": "16.9.3"
}
}
}
4 changes: 2 additions & 2 deletions ui/src/app/App.scss
Expand Up @@ -27,7 +27,7 @@ html {
}

a {
color: inherit;
color: inherit !important;
text-decoration: none;
}

Expand All @@ -38,7 +38,7 @@ a {
.rollouts {
height: 100%;
overflow-y: auto;
font-family: 'Heebo', sans-serif;
font-family: system-ui, sans-serif;
background-color: $argo-color-gray-3;

&--dark {
Expand Down
108 changes: 49 additions & 59 deletions ui/src/app/App.tsx
@@ -1,55 +1,47 @@
import {ThemeDiv, ThemeProvider} from 'argo-ui/v2';
import {Header} from './components/header/header';
import {createBrowserHistory} from 'history';
import * as React from 'react';
import {Key, KeybindingContext, KeybindingProvider} from 'react-keyhooks';
import {KeybindingProvider} from 'react-keyhooks';
import {Route, Router, Switch} from 'react-router-dom';
import './App.scss';
import {NamespaceContext, RolloutAPI} from './shared/context/api';
import {Modal} from './components/modal/modal';
import {Rollout} from './components/rollout/rollout';
import {RolloutsList} from './components/rollouts-list/rollouts-list';
import {Shortcut, Shortcuts} from './components/shortcuts/shortcuts';
import {ConfigProvider} from 'antd';
import {theme} from '../config/theme';

const bases = document.getElementsByTagName('base');
const base = bases.length > 0 ? bases[0].getAttribute('href') || '/' : '/';
export const history = createBrowserHistory({basename: base});

const Page = (props: {path: string; component: React.ReactNode; exact?: boolean; shortcuts?: Shortcut[]; changeNamespace: (val: string) => void}) => {
const {useKeybinding} = React.useContext(KeybindingContext);
const [showShortcuts, setShowShortcuts] = React.useState(false);
useKeybinding(
[Key.SHIFT, Key.H],
() => {
if (props.shortcuts) {
setShowShortcuts(!showShortcuts);
}
return false;
},
true
);
return (
<ThemeDiv className='rollouts'>
{showShortcuts && (
<Modal hide={() => setShowShortcuts(false)}>
<Shortcuts shortcuts={props.shortcuts} />
</Modal>
)}
<Route path={props.path} exact={props.exact}>
<React.Fragment>
<Header
changeNamespace={props.changeNamespace}
pageHasShortcuts={!!props.shortcuts}
showHelp={() => {
if (props.shortcuts) {
setShowShortcuts(true);
}
}}
/>
{props.component}
</React.Fragment>
</Route>
</ThemeDiv>
<ConfigProvider theme={theme}>
<div className='rollouts'>
{showShortcuts && (
<Modal hide={() => setShowShortcuts(false)}>
<Shortcuts shortcuts={props.shortcuts} />
</Modal>
)}
<Route path={props.path} exact={props.exact}>
<React.Fragment>
<Header
changeNamespace={props.changeNamespace}
pageHasShortcuts={!!props.shortcuts}
showHelp={() => {
if (props.shortcuts) {
setShowShortcuts(true);
}
}}
/>
{props.component}
</React.Fragment>
</Route>
</div>
</ConfigProvider>
);
};

Expand Down Expand Up @@ -84,31 +76,29 @@ const App = () => {
};

return (
<ThemeProvider>
{namespace && (
<NamespaceContext.Provider value={{namespace, availableNamespaces}}>
<KeybindingProvider>
<Router history={history}>
<Switch>
<Page
exact
path='/:namespace?'
component={<RolloutsList />}
shortcuts={[
{key: '/', description: 'Search'},
{key: 'TAB', description: 'Search, navigate search items'},
{key: ['fa-arrow-left', 'fa-arrow-right', 'fa-arrow-up', 'fa-arrow-down'], description: 'Navigate rollouts list', icon: true},
{key: ['SHIFT', 'H'], description: 'Show help menu', combo: true},
]}
changeNamespace={changeNamespace}
/>
<Page path='/rollout/:namespace?/:name' component={<Rollout />} changeNamespace={changeNamespace} />
</Switch>
</Router>
</KeybindingProvider>
</NamespaceContext.Provider>
)}
</ThemeProvider>
namespace && (
<NamespaceContext.Provider value={{namespace, availableNamespaces}}>
<KeybindingProvider>
<Router history={history}>
<Switch>
<Page
exact
path='/:namespace?'
component={<RolloutsList />}
shortcuts={[
{key: '/', description: 'Search'},
{key: 'TAB', description: 'Search, navigate search items'},
{key: ['fa-arrow-left', 'fa-arrow-right', 'fa-arrow-up', 'fa-arrow-down'], description: 'Navigate rollouts list', icon: true},
{key: ['SHIFT', 'H'], description: 'Show help menu', combo: true},
]}
changeNamespace={changeNamespace}
/>
<Page path='/rollout/:namespace?/:name' component={<Rollout />} changeNamespace={changeNamespace} />
</Switch>
</Router>
</KeybindingProvider>
</NamespaceContext.Provider>
)
);
};

Expand Down
72 changes: 72 additions & 0 deletions ui/src/app/components/confirm-button/confirm-button.tsx
@@ -0,0 +1,72 @@
import * as React from 'react';

import {Button, Popconfirm, Tooltip} from 'antd';
import {ButtonProps} from 'antd/es/button/button';
import {useState} from 'react';
import { TooltipPlacement } from 'antd/es/tooltip';

interface ConfirmButtonProps extends ButtonProps {
skipconfirm?: boolean;
tooltip?: string;
placement?: TooltipPlacement;
}

export const ConfirmButton = (props: ConfirmButtonProps) => {
const [open, setOpen] = useState(false);
const [buttonProps, setButtonProps] = useState(props);

React.useEffect(() => {
const tmp = {...props};
delete tmp.skipconfirm;
delete tmp.children;
delete tmp.onClick;
setButtonProps(tmp);
}, [props]);

const confirm = () => {
setOpen(false);
if (props.onClick) {
props.onClick(null);
}
};

const cancel = () => {
setOpen(false);
};

const handleOpenChange = (newOpen: boolean) => {
if (!newOpen) {
setOpen(newOpen);
return;
}
if (props.skipconfirm) {
confirm(); // next step
} else {
setOpen(newOpen);
}
};

return (
<div
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
}}>
<Popconfirm
title='Are you sure?'
open={open && !props.disabled}
onConfirm={confirm}
onCancel={cancel}
okText='Yes'
cancelText='No'
onOpenChange={handleOpenChange}
placement={props.placement || 'bottom'}>
<div>
<Tooltip title={props.tooltip}>
<Button {...buttonProps}>{props.children}</Button>
</Tooltip>
</div>
</Popconfirm>
</div>
);
};
13 changes: 13 additions & 0 deletions ui/src/app/components/ellipsis-middle/ellipsis-middle.tsx
@@ -0,0 +1,13 @@
import * as React from 'react';
import {Typography} from 'antd';

const {Text} = Typography;
export const EllipsisMiddle: React.FC<{suffixCount: number; children: string; style: React.CSSProperties}> = ({suffixCount, children, style}) => {
const start = children.slice(0, children.length - suffixCount).trim();
const suffix = children.slice(-suffixCount).trim();
return (
<Text style={{...style, maxWidth: '100%'}} ellipsis={{suffix}}>
{start}
</Text>
);
};
47 changes: 9 additions & 38 deletions ui/src/app/components/header/header.scss
Expand Up @@ -2,72 +2,43 @@

.rollouts-header {
display: flex;
background: $slate;
background: #0f2733;
color: white;
align-items: center;
padding: 10px 0;

&__brand {
color: $shine;
display: flex;
align-items: center;
text-decoration: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

&__welcome {
position: absolute;
transform-origin: left;
display: block;
overflow: hidden;
width: 174px;
white-space: nowrap;
transition: transform 1s ease 1s, opacity 1s ease;
margin-left: 10px;
}

&__title {
position: absolute;
transform: translateX(174px);
transition: transform 500ms ease 750ms;
display: flex;
align-items: center;
}

h1 {
position: relative;
color: white !important;
font-weight: 600;
font-size: 22px;
font-weight: 400;
margin: 0;
display: flex;
align-items: center;
}

h2 {
font-size: 18px;
color: $sherbert;
margin: 0;
margin-left: 10px;
flex-grow: 1;
white-space: nowrap;
width: 200px;
}

&__info {
margin-left: auto;
display: flex;
align-items: center;
}
&__label {
color: $shine;
margin: 0 15px;
margin: auto;
padding: 5px;
font-size: 10px;
font-weight: 600;
}
&__namespace {
color: black;
display: flex;
position: relative;
margin: 0 20px;
}
}