mirror of
https://github.com/ansible/awx.git
synced 2026-02-01 17:48:10 -03:30
Refactor breadcrumbs, tabs, routing.
* Cleanup previous params logic from Notificaitons list * Add shared breadcrumbs and tabs components * Structure Organization screens to render only cardBody content * Add styles * Fetch organization when location changes
This commit is contained in:
70
src/components/Breadcrumbs/Breadcrumbs.jsx
Normal file
70
src/components/Breadcrumbs/Breadcrumbs.jsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import {
|
||||
PageSection,
|
||||
PageSectionVariants,
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbHeading
|
||||
} from '@patternfly/react-core';
|
||||
import {
|
||||
Link,
|
||||
Route,
|
||||
withRouter
|
||||
} from 'react-router-dom';
|
||||
import './breadcrumbs.scss';
|
||||
|
||||
const Breadcrumbs = ({ breadcrumbConfig }) => {
|
||||
const { light } = PageSectionVariants;
|
||||
|
||||
return (
|
||||
<PageSection
|
||||
variant={light}
|
||||
className="pf-m-condensed"
|
||||
>
|
||||
<Breadcrumb>
|
||||
<Route
|
||||
render={(props) => <Crumb breadcrumbConfig={breadcrumbConfig} {...props} />}
|
||||
/>
|
||||
</Breadcrumb>
|
||||
</PageSection>
|
||||
);
|
||||
};
|
||||
|
||||
const Crumb = ({ breadcrumbConfig, match }) => {
|
||||
const crumb = breadcrumbConfig[match.url];
|
||||
|
||||
let crumbElement = (
|
||||
<BreadcrumbItem key={match.url}>
|
||||
<Link to={match.url}>
|
||||
{crumb}
|
||||
</Link>
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
|
||||
if (match.isExact) {
|
||||
crumbElement = (
|
||||
<BreadcrumbHeading
|
||||
key="breadcrumb-heading"
|
||||
className="heading"
|
||||
>
|
||||
{crumb}
|
||||
</BreadcrumbHeading>
|
||||
);
|
||||
}
|
||||
|
||||
if (!crumb) {
|
||||
crumbElement = null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{crumbElement}
|
||||
<Route
|
||||
path={`${match.url}/:path`}
|
||||
render={(props) => <Crumb breadcrumbConfig={breadcrumbConfig} {...props} />}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(Breadcrumbs);
|
||||
15
src/components/Breadcrumbs/breadcrumbs.scss
Normal file
15
src/components/Breadcrumbs/breadcrumbs.scss
Normal file
@@ -0,0 +1,15 @@
|
||||
.pf-c-breadcrumb__item {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.pf-c-breadcrumb__item.heading {
|
||||
--pf-c-breadcrumb__heading--FontSize: 20px;
|
||||
line-height: 24px;
|
||||
flex: 100%;
|
||||
}
|
||||
|
||||
.pf-c-breadcrumb__item:nth-last-child(2) {
|
||||
.pf-c-breadcrumb__item-divider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
--awx-toolbar--BorderColor: var(--pf-global--Color--light-200);
|
||||
--awx-toolbar--BorderWidth: var(--pf-global--BorderWidth--sm);
|
||||
|
||||
border: var(--awx-toolbar--BorderWidth) solid var(--awx-toolbar--BorderColor);
|
||||
border-bottom: var(--awx-toolbar--BorderWidth) solid var(--awx-toolbar--BorderColor);
|
||||
background-color: var(--awx-toolbar--BackgroundColor);
|
||||
height: 70px;
|
||||
padding-top: 5px;
|
||||
|
||||
@@ -65,9 +65,7 @@ class Notifications extends Component {
|
||||
|
||||
componentDidMount () {
|
||||
const queryParams = this.getQueryParams();
|
||||
// TODO: remove this hack once tab query param is gone
|
||||
const { tab, ...queryParamsWithoutTab } = queryParams;
|
||||
this.fetchNotifications(queryParamsWithoutTab);
|
||||
this.fetchNotifications(queryParams);
|
||||
}
|
||||
|
||||
onSearch () {
|
||||
@@ -81,10 +79,8 @@ class Notifications extends Component {
|
||||
const { search } = location;
|
||||
|
||||
const searchParams = parseQueryString(search.substring(1));
|
||||
// TODO: remove this hack once tab query param is gone
|
||||
const { tab, ...queryParamsWithoutTab } = searchParams;
|
||||
|
||||
return Object.assign({}, this.defaultParams, queryParamsWithoutTab, overrides);
|
||||
return Object.assign({}, this.defaultParams, searchParams, overrides);
|
||||
}
|
||||
|
||||
onSort = (sortedColumnKey, sortOrder) => {
|
||||
@@ -240,8 +236,6 @@ class Notifications extends Component {
|
||||
}
|
||||
|
||||
this.setState(stateToUpdate);
|
||||
// TODO: remove this hack once tab query param is gone
|
||||
this.updateUrl({ ...queryParams, tab: 'notifications' });
|
||||
|
||||
const notificationTemplateIds = results
|
||||
.map(notificationTemplate => notificationTemplate.id)
|
||||
@@ -299,7 +293,7 @@ class Notifications extends Component {
|
||||
<EmptyState>
|
||||
<EmptyStateIcon icon={CubesIcon} />
|
||||
<Title size="lg">
|
||||
<Trans>No Notifictions Found</Trans>
|
||||
<Trans>No Notifications Found</Trans>
|
||||
</Title>
|
||||
<EmptyStateBody>
|
||||
<Trans>Please add a notification template to populate this list</Trans>
|
||||
@@ -331,7 +325,7 @@ class Notifications extends Component {
|
||||
itemId={o.id}
|
||||
name={o.name}
|
||||
notificationType={o.notification_type}
|
||||
detailUrl={`notifications/${o.id}`}
|
||||
detailUrl={`/notifications/${o.id}`}
|
||||
isSelected={selected.includes(o.id)}
|
||||
onSelect={() => this.onSelect(o.id)}
|
||||
toggleNotification={this.toggleNotification}
|
||||
|
||||
@@ -1,40 +1,18 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import './tabs.scss';
|
||||
|
||||
const Tab = ({ location, match, tab, currentTab, children, breadcrumb }) => {
|
||||
const tabClasses = () => {
|
||||
let classes = 'pf-c-tabs__item';
|
||||
if (tab === currentTab) {
|
||||
classes += ' pf-m-current';
|
||||
}
|
||||
|
||||
return classes;
|
||||
};
|
||||
|
||||
const tabParams = () => {
|
||||
const params = new URLSearchParams(location.search);
|
||||
if (params.get('tab') !== undefined) {
|
||||
params.set('tab', tab);
|
||||
} else {
|
||||
params.append('tab', tab);
|
||||
}
|
||||
|
||||
return `?${params.toString()}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<li className={tabClasses()}>
|
||||
<Link
|
||||
className="pf-c-tabs__button"
|
||||
to={{ pathname: `${match.url}`, search: tabParams(), state: { breadcrumb } }}
|
||||
replace={tab === currentTab}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
const Tab = ({ children, link, replace }) => (
|
||||
<li className="pf-c-tabs__item">
|
||||
<NavLink
|
||||
to={link}
|
||||
replace={replace}
|
||||
className="pf-c-tabs__button"
|
||||
activeClassName="pf-m-current"
|
||||
>
|
||||
{children}
|
||||
</NavLink>
|
||||
</li>
|
||||
);
|
||||
|
||||
export default Tab;
|
||||
|
||||
@@ -1,11 +1,37 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button } from '@patternfly/react-core';
|
||||
import { TimesIcon } from '@patternfly/react-icons';
|
||||
import Tooltip from '../Tooltip';
|
||||
import './tabs.scss';
|
||||
|
||||
const Tabs = ({ children, labelText }) => (
|
||||
<div className="pf-c-tabs" aria-label={labelText}>
|
||||
const Tabs = ({ children, labelText, closeButton }) => (
|
||||
<div
|
||||
aria-label={labelText}
|
||||
className="pf-c-tabs pf-u-flex-direction-row pf-u-justify-content-space-between"
|
||||
>
|
||||
<ul className="pf-c-tabs__list">
|
||||
{children}
|
||||
</ul>
|
||||
{closeButton
|
||||
&& (
|
||||
<div className="pf-u-align-self-center">
|
||||
<Tooltip
|
||||
message={closeButton.text}
|
||||
position="top"
|
||||
>
|
||||
<Link to={closeButton.link}>
|
||||
<Button
|
||||
variant="plain"
|
||||
aria-label={closeButton.text}
|
||||
>
|
||||
<TimesIcon />
|
||||
</Button>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
.at-c-orgPane {
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-c-card__header {
|
||||
--pf-c-card__header--PaddingBottom: 0;
|
||||
--pf-c-card__header--PaddingX: 0;
|
||||
@@ -29,22 +23,34 @@
|
||||
.pf-c-tabs__button {
|
||||
--pf-c-tabs__button--PaddingLeft: 20px;
|
||||
--pf-c-tabs__button--PaddingRight: 20px;
|
||||
}
|
||||
display: block;
|
||||
|
||||
.pf-c-tabs__item.pf-m-current
|
||||
.pf-c-tabs__button::after {
|
||||
border-bottom: 3px solid var(--pf-c-tabs__item--m-current--Color);
|
||||
border-top: none;
|
||||
&:after {
|
||||
content: '';
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-c-tabs__item:not(.pf-m-current):hover
|
||||
.pf-c-tabs__button::after {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.pf-c-tabs__item:hover
|
||||
.pf-c-tabs__button:not(.pf-m-current)::after {
|
||||
border-bottom: 3px solid var(--pf-global--Color--dark-200);
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.pf-c-tabs__button.pf-m-current::after {
|
||||
content: '';
|
||||
border-bottom: 3px solid var(--pf-c-tabs__item--m-current--Color);
|
||||
border-top: none;
|
||||
margin-left: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-c-breadcrumb__item.heading {
|
||||
flex: 100%;
|
||||
font-size: 20px;
|
||||
}
|
||||
Reference in New Issue
Block a user