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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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;
}
}
Loading