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:
parent
825269c119
commit
f78a6568a6
70 changed files with 999 additions and 1596 deletions
|
@ -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}>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
31
app/react/components/PageHeader/HeaderTitle.module.css
Normal file
31
app/react/components/PageHeader/HeaderTitle.module.css
Normal 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);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue