1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-25 00:09:40 +02:00

feat(ui): portainer base component css change [EE-3381] (#7115)

This commit is contained in:
Chaim Lev-Ari 2022-06-23 09:32:18 +03:00 committed by GitHub
parent 825269c119
commit f78a6568a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 999 additions and 1596 deletions

View file

@ -10,7 +10,7 @@ export interface Crumb {
linkParams?: Record<string, unknown>;
}
interface Props {
breadcrumbs: Crumb[];
breadcrumbs: (Crumb | string)[];
}
export function Breadcrumbs({ breadcrumbs }: Props) {
@ -26,7 +26,11 @@ export function Breadcrumbs({ breadcrumbs }: Props) {
);
}
function renderCrumb(crumb: Crumb) {
function renderCrumb(crumb: Crumb | string) {
if (typeof crumb === 'string') {
return crumb;
}
if (crumb.link) {
return (
<Link to={crumb.link} params={crumb.linkParams}>

View file

@ -1,19 +0,0 @@
.user-links {
margin-right: 25px;
}
.user-links > * + * {
margin-left: 5px;
}
.link {
cursor: pointer;
}
.link .link-text {
text-decoration: underline;
}
.link .link-icon {
margin-right: 2px;
}

View file

@ -1,6 +1,4 @@
import { UserContext } from '@/portainer/hooks/useUser';
import { UserViewModel } from '@/portainer/models/user';
import { render } from '@/react-tools/test-utils';
import { renderWithQueryClient } from '@/react-tools/test-utils';
import { HeaderContainer } from './HeaderContainer';
import { HeaderContent } from './HeaderContent';
@ -11,7 +9,7 @@ test('should not render without a wrapping HeaderContainer', async () => {
.mockImplementation(() => jest.fn());
function renderComponent() {
return render(<HeaderContent />);
return renderWithQueryClient(<HeaderContent />);
}
expect(renderComponent).toThrowErrorMatchingSnapshot();
@ -20,22 +18,14 @@ test('should not render without a wrapping HeaderContainer', async () => {
});
test('should display a HeaderContent', async () => {
const username = 'username';
const user = new UserViewModel({ Username: username });
const userProviderState = { user };
const content = 'content';
const { queryByText } = render(
<UserContext.Provider value={userProviderState}>
<HeaderContainer>
<HeaderContent>{content}</HeaderContent>
</HeaderContainer>
</UserContext.Provider>
const { queryByText } = renderWithQueryClient(
<HeaderContainer>
<HeaderContent>{content}</HeaderContent>
</HeaderContainer>
);
const contentElement = queryByText(content);
expect(contentElement).toBeVisible();
expect(queryByText('my account')).toBeVisible();
expect(queryByText('log out')).toBeVisible();
});

View file

@ -1,43 +1,13 @@
import { PropsWithChildren } from 'react';
import clsx from 'clsx';
import { useUser } from '@/portainer/hooks/useUser';
import { Link } from '@@/Link';
import styles from './HeaderContent.module.css';
import { useHeaderContext } from './HeaderContainer';
export function HeaderContent({ children }: PropsWithChildren<unknown>) {
useHeaderContext();
const { user } = useUser();
return (
<div className="breadcrumb-links">
<div className="pull-left">{children}</div>
{user && !window.ddExtension && (
<div className={clsx('pull-right', styles.userLinks)}>
<Link to="portainer.account" className={styles.link}>
<i
className={clsx('fa fa-wrench', styles.linkIcon)}
aria-hidden="true"
/>
<span className={styles.linkText}>my account</span>
</Link>
<Link
to="portainer.logout"
params={{ performApiLogout: true }}
className={clsx('text-danger', styles.link)}
data-cy="template-logoutButton"
>
<i
className={clsx('fa fa-sign-out-alt', styles.linkIcon)}
aria-hidden="true"
/>
<span className={styles.linkText}>log out</span>
</Link>
</div>
)}
</div>
);
}

View file

@ -0,0 +1,31 @@
.menu-button {
border: 0px;
font-size: 17px;
background: none;
margin-right: 15px;
}
.menu-list {
background: var(--bg-dropdown-menu-color);
border-radius: 8px;
border: 1px solid var(--ui-grey-1) !important;
width: 180px;
padding: 5px !important;
box-shadow: 0 6px 12px rgb(0 0 0 / 18%);
}
.menu-link {
display: block;
padding: 5px 20px;
font-weight: 500;
line-height: 1.42857143;
white-space: nowrap;
font-size: 14px;
color: var(--text-dropdown-menu-color);
text-decoration: none !important;
}
.menu-link:hover {
background: var(--bg-dropdown-hover);
color: var(--text-dropdown-menu-color);
}

View file

@ -1,8 +1,14 @@
import { PropsWithChildren } from 'react';
import { Menu, MenuButton, MenuList, MenuLink } from '@reach/menu-button';
import clsx from 'clsx';
import { User, ChevronDown } from 'react-feather';
import { useUser } from '@/portainer/hooks/useUser';
import { Link } from '@@/Link';
import { useHeaderContext } from './HeaderContainer';
import styles from './HeaderTitle.module.css';
interface Props {
title: string;
@ -16,12 +22,25 @@ export function HeaderTitle({ title, children }: PropsWithChildren<Props>) {
<div className="page white-space-normal">
{title}
<span className="header_title_content">{children}</span>
{user && !window.ddExtension && (
<span className="pull-right user-box">
<i className="fa fa-user-circle" aria-hidden="true" />
{user.Username}
</span>
)}
<Menu>
<MenuButton className={clsx('pull-right', styles.menuButton)}>
<User className="feather" />
{user && <span>{user.Username}</span>}
<ChevronDown className="feather" />
</MenuButton>
<MenuList className={styles.menuList}>
<MenuLink
className={styles.menuLink}
as={Link}
to="portainer.account"
>
My account
</MenuLink>
<MenuLink className={styles.menuLink} as={Link} to="portainer.logout">
Log out
</MenuLink>
</MenuList>
</Menu>
</div>
);
}

View file

@ -1,4 +1,5 @@
import { useRouter } from '@uirouter/react';
import { RefreshCw } from 'react-feather';
import { Button } from '../buttons';
@ -11,12 +12,25 @@ import styles from './PageHeader.module.css';
interface Props {
reload?: boolean;
loading?: boolean;
onReload?(): Promise<void> | void;
breadcrumbs?: Crumb[];
title: string;
}
export function PageHeader({ title, breadcrumbs = [], reload }: Props) {
export function PageHeader({
title,
breadcrumbs = [],
reload,
loading,
onReload,
}: Props) {
const router = useRouter();
function onClickedRefresh() {
return onReload ? onReload() : router.stateService.reload();
}
return (
<HeaderContainer>
<HeaderTitle title={title}>
@ -24,10 +38,11 @@ export function PageHeader({ title, breadcrumbs = [], reload }: Props) {
<Button
color="link"
size="medium"
onClick={() => router.stateService.reload()}
onClick={onClickedRefresh}
className={styles.reloadButton}
disabled={loading}
>
<i className="fa fa-sync" aria-hidden="true" />
<RefreshCw className="feather" />
</Button>
)}
</HeaderTitle>