@@ -90,7 +90,7 @@ public class ProjectsPage { | |||
} | |||
public ProjectsPage searchProject(String search) { | |||
SelenideElement searchInput = $(".projects-facet-search input"); | |||
SelenideElement searchInput = $(".projects-topbar-item-search input"); | |||
searchInput.setValue("").sendKeys(search); | |||
return this; | |||
} | |||
@@ -115,11 +115,6 @@ public class ProjectsPage { | |||
} | |||
private SelenideElement getOpenTopBar() { | |||
SelenideElement topBar = $(".projects-topbar-actions").should(Condition.exist); | |||
if (!topBar.has(Condition.hasClass("open"))){ | |||
$(".js-projects-topbar-open").click(); | |||
} | |||
topBar.should(Condition.hasClass("open")); | |||
return topBar; | |||
return $(".projects-topbar-items").should(Condition.exist); | |||
} | |||
} |
@@ -804,8 +804,8 @@ export default class App extends React.PureComponent { | |||
{this.renderSide(openIssue)} | |||
<div className="layout-page-main"> | |||
<div className="issues-header-panel issues-main-header"> | |||
<div className="issues-header-panel-inner issues-main-header-inner"> | |||
<div className="layout-page-header-panel layout-page-main-header issues-main-header"> | |||
<div className="layout-page-header-panel-inner layout-page-main-header-inner"> | |||
<div className="layout-page-main-inner"> | |||
{this.renderBulkChange(openIssue)} | |||
{openIssue != null |
@@ -36,8 +36,8 @@ export default function ConciseIssuesListHeader(props: Props) { | |||
const { paging, selectedIndex } = props; | |||
return ( | |||
<header className="issues-header-panel concise-issues-list-header"> | |||
<div className="issues-header-panel-inner concise-issues-list-header-inner"> | |||
<header className="layout-page-header-panel concise-issues-list-header"> | |||
<div className="layout-page-header-panel-inner concise-issues-list-header-inner"> | |||
<BackButton className="pull-left" onClick={props.onBackClick} /> | |||
{props.loading | |||
? <i className="spinner pull-right" /> |
@@ -1,55 +1,13 @@ | |||
.issues-header-panel, | |||
.issues-header-panel-inner { | |||
height: 56px; | |||
box-sizing: border-box; | |||
} | |||
.issues-header-panel { | |||
margin-top: -20px; | |||
} | |||
.issues-header-panel-inner { | |||
position: fixed; | |||
z-index: 30; | |||
line-height: 24px; | |||
padding-top: 16px; | |||
padding-bottom: 16px; | |||
border-bottom: 1px solid #e6e6e6; | |||
background-color: #f3f3f3; | |||
} | |||
.issues-main-header { | |||
margin-bottom: 20px; | |||
} | |||
.issues-main-header .component-name { | |||
line-height: 24px; | |||
} | |||
.issues-main-header-inner { | |||
left: calc(50vw - 360px + 1px); | |||
right: 0; | |||
padding-left: 20px; | |||
padding-right: 20px; | |||
} | |||
@media (max-width: 1320px) { | |||
.issues-main-header-inner { | |||
left: 301px; | |||
} | |||
.concise-issues-list-header, .concise-issues-list-header-inner { | |||
} | |||
.issues-main-header-spinner { | |||
margin-left: 1px; | |||
margin-right: 9px; | |||
margin-top: -1px; | |||
.concise-issues-list-header { | |||
} | |||
.concise-issues-list-header, | |||
.concise-issues-list-header-inner {} | |||
.concise-issues-list-header {} | |||
.concise-issues-list-header-inner { | |||
width: 260px; | |||
text-align: center; | |||
@@ -156,8 +114,7 @@ | |||
text-align: right; | |||
} | |||
.issues .search-navigator-facet-header, | |||
.issues .search-navigator-facet-list { | |||
.issues .search-navigator-facet-header, .issues .search-navigator-facet-list { | |||
padding-left: 0; | |||
padding-right: 0; | |||
} | |||
@@ -167,7 +124,8 @@ | |||
padding-bottom: 8px; | |||
} | |||
.issues .search-navigator-facet-box:not(.hidden):not(.leak-facet-box) + .search-navigator-facet-box:not(.leak-facet-box) { | |||
.issues .search-navigator-facet-box:not(.hidden):not(.leak-facet-box) | |||
+ .search-navigator-facet-box:not(.leak-facet-box) { | |||
border-top: none; | |||
} | |||
@@ -26,8 +26,6 @@ export default class OrganizationFavoriteProjects extends React.PureComponent { | |||
children?: React.Element<*>, | |||
currentUser: { isLoggedIn: boolean }, | |||
location: Object, | |||
optionBarOpen: boolean, | |||
optionBarToggle: (open: boolean) => void, | |||
organization: { | |||
key: string | |||
} | |||
@@ -53,8 +51,6 @@ export default class OrganizationFavoriteProjects extends React.PureComponent { | |||
<FavoriteProjectsContainer | |||
currentUser={this.props.currentUser} | |||
location={this.props.location} | |||
optionBarOpen={this.props.optionBarOpen} | |||
optionBarToggle={this.props.optionBarToggle} | |||
organization={this.props.organization} | |||
/> | |||
</div> |
@@ -26,8 +26,6 @@ export default class OrganizationProjects extends React.PureComponent { | |||
children?: React.Element<*>, | |||
currentUser: { isLoggedIn: boolean }, | |||
location: Object, | |||
optionBarOpen: boolean, | |||
optionBarToggle: (open: boolean) => void, | |||
organization: { | |||
key: string | |||
} | |||
@@ -54,8 +52,6 @@ export default class OrganizationProjects extends React.PureComponent { | |||
currentUser={this.props.currentUser} | |||
isFavorite={false} | |||
location={this.props.location} | |||
optionBarOpen={this.props.optionBarOpen} | |||
optionBarToggle={this.props.optionBarToggle} | |||
organization={this.props.organization} | |||
/> | |||
</div> |
@@ -23,20 +23,10 @@ import { connect } from 'react-redux'; | |||
import { getCurrentUser, getOrganizationByKey } from '../../../store/rootReducer'; | |||
import { updateOrganization } from '../actions'; | |||
type State = { | |||
optionBarOpen: boolean | |||
}; | |||
class OrganizationProjectsContainer extends React.PureComponent { | |||
state: State = { optionBarOpen: false }; | |||
handleOptionBarToggle = (open: boolean) => this.setState({ optionBarOpen: open }); | |||
render() { | |||
return React.cloneElement(this.props.children, { | |||
currentUser: this.props.currentUser, | |||
optionBarOpen: this.state.optionBarOpen, | |||
optionBarToggle: this.handleOptionBarToggle, | |||
organization: this.props.organization | |||
}); | |||
} |
@@ -21,7 +21,6 @@ | |||
import React from 'react'; | |||
import Helmet from 'react-helmet'; | |||
import PageHeaderContainer from './PageHeaderContainer'; | |||
import ProjectsOptionBarContainer from './ProjectsOptionBarContainer'; | |||
import ProjectsListContainer from './ProjectsListContainer'; | |||
import ProjectsListFooterContainer from './ProjectsListFooterContainer'; | |||
import PageSidebar from './PageSidebar'; | |||
@@ -31,16 +30,14 @@ import { translate } from '../../../helpers/l10n'; | |||
import { SORTING_SWITCH, parseSorting } from '../utils'; | |||
import '../styles.css'; | |||
type Props = { | |||
type Props = {| | |||
isFavorite: boolean, | |||
location: { pathname: string, query: { [string]: string } }, | |||
fetchProjects: (query: string, isFavorite: boolean, organization?: {}) => Promise<*>, | |||
optionBarOpen: boolean, | |||
optionBarToggle: (open: boolean) => void, | |||
organization?: { key: string }, | |||
router: { push: ({ pathname: string, query?: {} }) => void }, | |||
currentUser?: { isLoggedIn: boolean } | |||
}; | |||
|}; | |||
type State = { | |||
query: { [string]: string } | |||
@@ -67,11 +64,13 @@ export default class AllProjects extends React.PureComponent { | |||
footer && footer.classList.remove('search-navigator-footer'); | |||
} | |||
openOptionBar = (evt: Event & { currentTarget: HTMLElement }) => { | |||
evt.currentTarget.blur(); | |||
evt.preventDefault(); | |||
this.props.optionBarToggle(true); | |||
}; | |||
getView = () => this.state.query.view || 'overall'; | |||
getVisualization = () => this.state.query.visualization || 'risk'; | |||
getSort = () => this.state.query.sort || 'name'; | |||
isFiltered = () => Object.keys(this.state.query).some(key => this.state.query[key] != null); | |||
handlePerspectiveChange = ({ view, visualization }: { view: string, visualization?: string }) => { | |||
const query: { view: ?string, visualization: ?string, sort?: ?string } = { | |||
@@ -111,78 +110,78 @@ export default class AllProjects extends React.PureComponent { | |||
}); | |||
}; | |||
render() { | |||
const { isFavorite, organization, optionBarOpen } = this.props; | |||
const { query } = this.state; | |||
const isFiltered = Object.keys(query).some(key => query[key] != null); | |||
const view = query.view || 'overall'; | |||
const visualization = query.visualization || 'risk'; | |||
const selectedSort = query.sort || 'name'; | |||
const sideBarTop = (organization ? 95 : 30) + (optionBarOpen ? 45 : 0); | |||
const contentTop = optionBarOpen ? 65 : 20; | |||
renderSide = () => ( | |||
<div className="layout-page-side-outer"> | |||
<div | |||
className="layout-page-side projects-page-side" | |||
style={{ top: this.props.organization ? 95 : 30 }}> | |||
<div className="layout-page-side-inner"> | |||
<div className="layout-page-filters"> | |||
<PageSidebar | |||
isFavorite={this.props.isFavorite} | |||
organization={this.props.organization} | |||
query={this.state.query} | |||
view={this.getView()} | |||
visualization={this.getVisualization()} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
renderHeader = () => ( | |||
<div className="layout-page-header-panel layout-page-main-header"> | |||
<div className="layout-page-header-panel-inner layout-page-main-header-inner"> | |||
<div className="layout-page-main-inner"> | |||
<PageHeaderContainer | |||
query={this.state.query} | |||
isFavorite={this.props.isFavorite} | |||
organization={this.props.organization} | |||
onPerspectiveChange={this.handlePerspectiveChange} | |||
onSortChange={this.handleSortChange} | |||
selectedSort={this.getSort()} | |||
currentUser={this.props.currentUser} | |||
view={this.getView()} | |||
visualization={this.getVisualization()} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
renderMain = () => | |||
(this.getView() === 'visualizations' | |||
? <div className="layout-page-main-inner"> | |||
<VisualizationsContainer | |||
sort={this.state.query.sort} | |||
visualization={this.getVisualization()} | |||
/> | |||
</div> | |||
: <div className="layout-page-main-inner"> | |||
<ProjectsListContainer | |||
isFavorite={this.props.isFavorite} | |||
isFiltered={this.isFiltered()} | |||
organization={this.props.organization} | |||
cardType={this.getView()} | |||
/> | |||
<ProjectsListFooterContainer | |||
query={this.state.query} | |||
isFavorite={this.props.isFavorite} | |||
organization={this.props.organization} | |||
/> | |||
</div>); | |||
render() { | |||
return ( | |||
<div> | |||
<div className="layout-page projects-page"> | |||
<Helmet title={translate('projects.page')} /> | |||
<ProjectsOptionBarContainer | |||
onPerspectiveChange={this.handlePerspectiveChange} | |||
onSortChange={this.handleSortChange} | |||
onToggleOptionBar={this.props.optionBarToggle} | |||
open={optionBarOpen} | |||
selectedSort={selectedSort} | |||
currentUser={this.props.currentUser} | |||
view={view} | |||
visualization={visualization} | |||
/> | |||
<div className="layout-page projects-page"> | |||
<div className="layout-page-side-outer"> | |||
<div className="layout-page-side projects-page-side" style={{ top: sideBarTop }}> | |||
<div className="layout-page-side-inner"> | |||
<div className="layout-page-filters"> | |||
<PageSidebar | |||
isFavorite={isFavorite} | |||
organization={organization} | |||
query={query} | |||
view={view} | |||
visualization={visualization} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
{this.renderSide()} | |||
<div | |||
className="layout-page-main projects-page-content" | |||
style={{ paddingTop: contentTop }}> | |||
<div className="layout-page-main-inner"> | |||
<PageHeaderContainer | |||
query={query} | |||
isFavorite={isFavorite} | |||
organization={organization} | |||
onOpenOptionBar={this.openOptionBar} | |||
optionBarOpen={optionBarOpen} | |||
/> | |||
{view !== 'visualizations' && | |||
<ProjectsListContainer | |||
isFavorite={isFavorite} | |||
isFiltered={isFiltered} | |||
organization={organization} | |||
cardType={view} | |||
/>} | |||
{view !== 'visualizations' && | |||
<ProjectsListFooterContainer | |||
query={query} | |||
isFavorite={isFavorite} | |||
organization={organization} | |||
/>} | |||
{view === 'visualizations' && | |||
<VisualizationsContainer sort={query.sort} visualization={visualization} />} | |||
</div> | |||
</div> | |||
<div className="layout-page-main projects-page-content"> | |||
{this.renderHeader()} | |||
{this.renderMain()} | |||
</div> | |||
</div> | |||
); |
@@ -20,32 +20,25 @@ | |||
//@flow | |||
import React from 'react'; | |||
type State = { | |||
optionBarOpen: boolean | |||
}; | |||
export default class App extends React.PureComponent { | |||
state: State = { optionBarOpen: false }; | |||
componentDidMount() { | |||
const elem = document.querySelector('html'); | |||
elem && elem.classList.add('dashboard-page'); | |||
if (elem) { | |||
elem.classList.add('dashboard-page'); | |||
} | |||
} | |||
componentWillUnmount() { | |||
const elem = document.querySelector('html'); | |||
elem && elem.classList.remove('dashboard-page'); | |||
if (elem) { | |||
elem.classList.remove('dashboard-page'); | |||
} | |||
} | |||
handleOptionBarToggle = (open: boolean) => this.setState({ optionBarOpen: open }); | |||
render() { | |||
return ( | |||
<div id="projects-page"> | |||
{React.cloneElement(this.props.children, { | |||
optionBarOpen: this.state.optionBarOpen, | |||
optionBarToggle: this.handleOptionBarToggle | |||
})} | |||
{this.props.children} | |||
</div> | |||
); | |||
} |
@@ -29,8 +29,6 @@ import { searchProjects } from '../../../api/components'; | |||
type Props = { | |||
currentUser: { isLoggedIn: boolean }, | |||
location: { query: {} }, | |||
optionBarOpen: boolean, | |||
optionBarToggle: (open: boolean) => void, | |||
router: { | |||
replace: (location: { pathname?: string, query?: { [string]: string } }) => void | |||
} | |||
@@ -107,8 +105,6 @@ class DefaultPageSelector extends React.PureComponent { | |||
<AllProjectsContainer | |||
isFavorite={false} | |||
location={this.props.location} | |||
optionBarOpen={this.props.optionBarOpen} | |||
optionBarToggle={this.props.optionBarToggle} | |||
currentUser={this.props.currentUser} | |||
/> | |||
); |
@@ -19,41 +19,88 @@ | |||
*/ | |||
// @flow | |||
import React from 'react'; | |||
import classNames from 'classnames'; | |||
import SearchFilterContainer from '../filters/SearchFilterContainer'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
import PerspectiveSelect from './PerspectiveSelect'; | |||
import ProjectsSortingSelect from './ProjectsSortingSelect'; | |||
import { translate } from '../../../helpers/l10n'; | |||
type Props = { | |||
type Props = {| | |||
currentUser?: { isLoggedIn: boolean }, | |||
isFavorite?: boolean, | |||
loading: boolean, | |||
onOpenOptionBar: () => void, | |||
optionBarOpen?: boolean, | |||
onPerspectiveChange: ({ view: string, visualization?: string }) => void, | |||
organization?: { key: string }, | |||
projects: Array<*>, | |||
projectsAppState: { loading: boolean, total?: number }, | |||
query: { [string]: string }, | |||
total?: number | |||
}; | |||
onSortChange: (sort: string, desc: boolean) => void, | |||
selectedSort: string, | |||
view: string, | |||
visualization?: string | |||
|}; | |||
export default function PageHeader(props: Props) { | |||
const renderSortingSelect = () => { | |||
const { projectsAppState, projects, currentUser, view } = props; | |||
const limitReached = | |||
projects != null && | |||
projectsAppState.total != null && | |||
projects.length < projectsAppState.total; | |||
const defaultOption = currentUser && currentUser.isLoggedIn ? 'name' : 'analysis_date'; | |||
if (view === 'visualizations' && !limitReached) { | |||
return ( | |||
<Tooltip overlay={translate('projects.sort.disabled')}> | |||
<div className="projects-topbar-item disabled"> | |||
<ProjectsSortingSelect | |||
className="js-projects-sorting-select" | |||
defaultOption={defaultOption} | |||
onChange={props.onSortChange} | |||
selectedSort={props.selectedSort} | |||
view={props.view} | |||
/> | |||
</div> | |||
</Tooltip> | |||
); | |||
} | |||
return ( | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption={defaultOption} | |||
onChange={props.onSortChange} | |||
selectedSort={props.selectedSort} | |||
view={props.view} | |||
/> | |||
); | |||
}; | |||
return ( | |||
<header className="page-header"> | |||
<header className="page-header projects-topbar-items"> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
onChange={props.onPerspectiveChange} | |||
view={props.view} | |||
visualization={props.visualization} | |||
/> | |||
{renderSortingSelect()} | |||
<SearchFilterContainer | |||
className="projects-topbar-item projects-topbar-item-search" | |||
isFavorite={props.isFavorite} | |||
organization={props.organization} | |||
query={props.query} | |||
/> | |||
<div className="page-actions projects-page-actions text-right"> | |||
{!props.optionBarOpen && | |||
<a | |||
className="button js-projects-topbar-open spacer-right" | |||
href="#" | |||
onClick={props.onOpenOptionBar}> | |||
{translate('projects.view_settings')} | |||
</a>} | |||
{!!props.loading && <i className="spinner spacer-right" />} | |||
<div | |||
className={classNames('projects-topbar-item', 'is-last', { | |||
'is-loading': props.projectsAppState.loading | |||
})}> | |||
{!!props.projectsAppState.loading && <i className="spinner spacer-right" />} | |||
{props.total != null && | |||
{props.projectsAppState.total != null && | |||
<span> | |||
<strong id="projects-total">{props.total}</strong> | |||
<strong id="projects-total">{props.projectsAppState.total}</strong> | |||
{' '} | |||
{translate('projects._projects')} | |||
</span>} |
@@ -19,6 +19,11 @@ | |||
*/ | |||
import { connect } from 'react-redux'; | |||
import PageHeader from './PageHeader'; | |||
import { getProjectsAppState } from '../../../store/rootReducer'; | |||
import { getProjects, getProjectsAppState } from '../../../store/rootReducer'; | |||
export default connect(state => getProjectsAppState(state))(PageHeader); | |||
const mapStateToProps = state => ({ | |||
projects: getProjects(state), | |||
projectsAppState: getProjectsAppState(state) | |||
}); | |||
export default connect(mapStateToProps)(PageHeader); |
@@ -26,12 +26,12 @@ import { VIEWS, VISUALIZATIONS } from '../utils'; | |||
export type Option = { label: string, type: string, value: string }; | |||
type Props = { | |||
type Props = {| | |||
className?: string, | |||
onChange: ({ view: string, visualization?: string }) => void, | |||
view: string, | |||
visualization?: string | |||
}; | |||
|}; | |||
export default class PerspectiveSelect extends React.PureComponent { | |||
options: Array<Option>; |
@@ -1,106 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
//@flow | |||
import React from 'react'; | |||
import classNames from 'classnames'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
import PerspectiveSelect from './PerspectiveSelect'; | |||
import ProjectsSortingSelect from './ProjectsSortingSelect'; | |||
import { translate } from '../../../helpers/l10n'; | |||
type Props = { | |||
onPerspectiveChange: ({ view: string, visualization?: string }) => void, | |||
onSortChange: (sort: string, desc: boolean) => void, | |||
onToggleOptionBar: boolean => void, | |||
open: boolean, | |||
projects: Array<*>, | |||
projectsAppState: { loading: boolean, total?: number }, | |||
selectedSort: string, | |||
currentUser?: { isLoggedIn: boolean }, | |||
view: string, | |||
visualization?: string | |||
}; | |||
export default class ProjectsOptionBar extends React.PureComponent { | |||
props: Props; | |||
closeBar = (evt: Event & { currentTarget: HTMLElement }) => { | |||
evt.currentTarget.blur(); | |||
evt.preventDefault(); | |||
this.props.onToggleOptionBar(false); | |||
}; | |||
renderSortingSelect() { | |||
const { projectsAppState, projects, currentUser, view } = this.props; | |||
const limitReached = | |||
projects != null && | |||
projectsAppState.total != null && | |||
projects.length < projectsAppState.total; | |||
const defaultOption = currentUser && currentUser.isLoggedIn ? 'name' : 'analysis_date'; | |||
if (view === 'visualizations' && !limitReached) { | |||
return ( | |||
<Tooltip overlay={translate('projects.sort.disabled')}> | |||
<div> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select disabled" | |||
defaultOption={defaultOption} | |||
onChange={this.props.onSortChange} | |||
selectedSort={this.props.selectedSort} | |||
view={this.props.view} | |||
/> | |||
</div> | |||
</Tooltip> | |||
); | |||
} | |||
return ( | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption={defaultOption} | |||
onChange={this.props.onSortChange} | |||
selectedSort={this.props.selectedSort} | |||
view={this.props.view} | |||
/> | |||
); | |||
} | |||
render() { | |||
const { open } = this.props; | |||
return ( | |||
<div className="projects-topbar"> | |||
<div className={classNames('projects-topbar-actions', { open })}> | |||
<div className="projects-topbar-actions-inner"> | |||
<button className="projects-topbar-button" onClick={this.closeBar}> | |||
{translate('close')} | |||
</button> | |||
<div className="projects-topbar-items"> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
onChange={this.props.onPerspectiveChange} | |||
view={this.props.view} | |||
visualization={this.props.visualization} | |||
/> | |||
{this.renderSortingSelect()} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} |
@@ -1,29 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { connect } from 'react-redux'; | |||
import ProjectsOptionBar from './ProjectsOptionBar'; | |||
import { getProjects, getProjectsAppState } from '../../../store/rootReducer'; | |||
const mapStateToProps = state => ({ | |||
projects: getProjects(state), | |||
projectsAppState: getProjectsAppState(state) | |||
}); | |||
export default connect(mapStateToProps)(ProjectsOptionBar); |
@@ -65,10 +65,7 @@ export default class ProjectsSortingSelect extends React.PureComponent { | |||
opt => (opt.value === this.props.defaultOption ? 0 : 1) | |||
).map((opt: { value: string, class?: string }) => ({ | |||
value: opt.value, | |||
label: translate('projects.sorting', opt.value) + | |||
(opt.value === this.props.defaultOption | |||
? ` (${translate('projects.sorting.default')})` | |||
: ''), | |||
label: translate('projects.sorting', opt.value), | |||
class: opt.class | |||
})); | |||
}; | |||
@@ -88,7 +85,7 @@ export default class ProjectsSortingSelect extends React.PureComponent { | |||
<div className={this.props.className}> | |||
<label>{translate('projects.sort_by')}:</label> | |||
<Select | |||
className="little-spacer-left input-large" | |||
className="little-spacer-left input-medium" | |||
clearable={false} | |||
onChange={this.handleSortChange} | |||
optionComponent={ProjectsSortingSelectOption} |
@@ -22,17 +22,65 @@ import { shallow } from 'enzyme'; | |||
import PageHeader from '../PageHeader'; | |||
it('should render correctly', () => { | |||
expect(shallow(<PageHeader query={{ search: 'test' }} total="12" />)).toMatchSnapshot(); | |||
expect( | |||
shallow(<PageHeader query={{ search: 'test' }} projectsAppState={{ total: 12 }} />) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render correctly while loading', () => { | |||
expect( | |||
shallow(<PageHeader query={{ search: '' }} loading={true} isFavorite={true} total="2" />) | |||
shallow( | |||
<PageHeader | |||
query={{ search: '' }} | |||
isFavorite={true} | |||
projectsAppState={{ loading: true, total: 2 }} | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should not render projects total', () => { | |||
expect( | |||
shallow(<PageHeader query={{ search: '' }} />).find('#projects-total').exists() | |||
shallow(<PageHeader projectsAppState={{}} query={{ search: '' }} />) | |||
.find('#projects-total') | |||
.exists() | |||
).toBeFalsy(); | |||
}); | |||
it('should render disabled sorting options for visualizations', () => { | |||
expect( | |||
shallow( | |||
<PageHeader | |||
open={true} | |||
projectsAppState={{}} | |||
view="visualizations" | |||
visualization="coverage" | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render switch the default sorting option for anonymous users', () => { | |||
expect( | |||
shallow( | |||
<PageHeader | |||
currentUser={{ isLoggedIn: true }} | |||
open={true} | |||
projectsAppState={{}} | |||
view="overall" | |||
visualization="risk" | |||
/> | |||
).find('ProjectsSortingSelect') | |||
).toMatchSnapshot(); | |||
expect( | |||
shallow( | |||
<PageHeader | |||
currentUser={{ isLoggedIn: false }} | |||
open={true} | |||
projectsAppState={{}} | |||
view="leak" | |||
visualization="risk" | |||
/> | |||
).find('ProjectsSortingSelect') | |||
).toMatchSnapshot(); | |||
}); |
@@ -1,78 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2017 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ProjectsOptionBar from '../ProjectsOptionBar'; | |||
import { click } from '../../../../helpers/testUtils'; | |||
it('should render option bar closed', () => { | |||
expect(shallow(<ProjectsOptionBar open={false} view="overall" />)).toMatchSnapshot(); | |||
}); | |||
it('should render option bar open', () => { | |||
expect( | |||
shallow( | |||
<ProjectsOptionBar | |||
open={true} | |||
view="leak" | |||
visualization="risk" | |||
projects={[1, 2, 3]} | |||
projectsAppState={{ total: 3 }} | |||
currentUser={{ isLoggedIn: true }} | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render disabled sorting options for visualizations', () => { | |||
expect( | |||
shallow(<ProjectsOptionBar open={true} view="visualizations" visualization="coverage" />) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should call close method correctly', () => { | |||
const toggle = jest.fn(); | |||
const wrapper = shallow(<ProjectsOptionBar open={true} view="leak" onToggleOptionBar={toggle} />); | |||
click(wrapper.find('.projects-topbar-button')); | |||
expect(toggle.mock.calls).toMatchSnapshot(); | |||
}); | |||
it('should render switch the default sorting option for anonymous users', () => { | |||
expect( | |||
shallow( | |||
<ProjectsOptionBar | |||
open={true} | |||
view="overall" | |||
visualization="risk" | |||
currentUser={{ isLoggedIn: true }} | |||
/> | |||
).find('ProjectsSortingSelect') | |||
).toMatchSnapshot(); | |||
expect( | |||
shallow( | |||
<ProjectsOptionBar | |||
open={true} | |||
view="leak" | |||
visualization="risk" | |||
currentUser={{ isLoggedIn: false }} | |||
/> | |||
).find('ProjectsSortingSelect') | |||
).toMatchSnapshot(); | |||
}); |
@@ -2,9 +2,17 @@ | |||
exports[`should render correctly 1`] = ` | |||
<header | |||
className="page-header" | |||
className="page-header projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
/> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
/> | |||
<withRouter(SearchFilterContainer) | |||
className="projects-topbar-item projects-topbar-item-search" | |||
query={ | |||
Object { | |||
"search": "test", | |||
@@ -12,14 +20,8 @@ exports[`should render correctly 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="page-actions projects-page-actions text-right" | |||
className="projects-topbar-item is-last" | |||
> | |||
<a | |||
className="button js-projects-topbar-open spacer-right" | |||
href="#" | |||
> | |||
projects.view_settings | |||
</a> | |||
<span> | |||
<strong | |||
id="projects-total" | |||
@@ -35,9 +37,17 @@ exports[`should render correctly 1`] = ` | |||
exports[`should render correctly while loading 1`] = ` | |||
<header | |||
className="page-header" | |||
className="page-header projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
/> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
/> | |||
<withRouter(SearchFilterContainer) | |||
className="projects-topbar-item projects-topbar-item-search" | |||
isFavorite={true} | |||
query={ | |||
Object { | |||
@@ -46,14 +56,8 @@ exports[`should render correctly while loading 1`] = ` | |||
} | |||
/> | |||
<div | |||
className="page-actions projects-page-actions text-right" | |||
className="projects-topbar-item is-last is-loading" | |||
> | |||
<a | |||
className="button js-projects-topbar-open spacer-right" | |||
href="#" | |||
> | |||
projects.view_settings | |||
</a> | |||
<i | |||
className="spinner spacer-right" | |||
/> | |||
@@ -69,3 +73,51 @@ exports[`should render correctly while loading 1`] = ` | |||
</div> | |||
</header> | |||
`; | |||
exports[`should render disabled sorting options for visualizations 1`] = ` | |||
<header | |||
className="page-header projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
view="visualizations" | |||
visualization="coverage" | |||
/> | |||
<Tooltip | |||
overlay="projects.sort.disabled" | |||
placement="bottom" | |||
> | |||
<div | |||
className="projects-topbar-item disabled" | |||
> | |||
<ProjectsSortingSelect | |||
className="js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
view="visualizations" | |||
/> | |||
</div> | |||
</Tooltip> | |||
<withRouter(SearchFilterContainer) | |||
className="projects-topbar-item projects-topbar-item-search" | |||
/> | |||
<div | |||
className="projects-topbar-item is-last" | |||
/> | |||
</header> | |||
`; | |||
exports[`should render switch the default sorting option for anonymous users 1`] = ` | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="name" | |||
view="overall" | |||
/> | |||
`; | |||
exports[`should render switch the default sorting option for anonymous users 2`] = ` | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
view="leak" | |||
/> | |||
`; |
@@ -1,136 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should call close method correctly 1`] = ` | |||
Array [ | |||
Array [ | |||
false, | |||
], | |||
] | |||
`; | |||
exports[`should render disabled sorting options for visualizations 1`] = ` | |||
<div | |||
className="projects-topbar" | |||
> | |||
<div | |||
className="projects-topbar-actions open" | |||
> | |||
<div | |||
className="projects-topbar-actions-inner" | |||
> | |||
<button | |||
className="projects-topbar-button" | |||
onClick={[Function]} | |||
> | |||
close | |||
</button> | |||
<div | |||
className="projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
view="visualizations" | |||
visualization="coverage" | |||
/> | |||
<Tooltip | |||
overlay="projects.sort.disabled" | |||
placement="bottom" | |||
> | |||
<div> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select disabled" | |||
defaultOption="analysis_date" | |||
view="visualizations" | |||
/> | |||
</div> | |||
</Tooltip> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render option bar closed 1`] = ` | |||
<div | |||
className="projects-topbar" | |||
> | |||
<div | |||
className="projects-topbar-actions" | |||
> | |||
<div | |||
className="projects-topbar-actions-inner" | |||
> | |||
<button | |||
className="projects-topbar-button" | |||
onClick={[Function]} | |||
> | |||
close | |||
</button> | |||
<div | |||
className="projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
view="overall" | |||
/> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
view="overall" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render option bar open 1`] = ` | |||
<div | |||
className="projects-topbar" | |||
> | |||
<div | |||
className="projects-topbar-actions open" | |||
> | |||
<div | |||
className="projects-topbar-actions-inner" | |||
> | |||
<button | |||
className="projects-topbar-button" | |||
onClick={[Function]} | |||
> | |||
close | |||
</button> | |||
<div | |||
className="projects-topbar-items" | |||
> | |||
<PerspectiveSelect | |||
className="projects-topbar-item js-projects-perspective-select" | |||
view="leak" | |||
visualization="risk" | |||
/> | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="name" | |||
view="leak" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render switch the default sorting option for anonymous users 1`] = ` | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="name" | |||
view="overall" | |||
/> | |||
`; | |||
exports[`should render switch the default sorting option for anonymous users 2`] = ` | |||
<ProjectsSortingSelect | |||
className="projects-topbar-item js-projects-sorting-select" | |||
defaultOption="analysis_date" | |||
view="leak" | |||
/> | |||
`; |
@@ -12,7 +12,7 @@ exports[`should handle the descending sort direction 1`] = ` | |||
autosize={true} | |||
backspaceRemoves={true} | |||
backspaceToRemoveMessage="Press backspace to remove {label}" | |||
className="little-spacer-left input-large" | |||
className="little-spacer-left input-medium" | |||
clearAllText="Clear all" | |||
clearValueText="Clear value" | |||
clearable={false} | |||
@@ -41,7 +41,7 @@ exports[`should handle the descending sort direction 1`] = ` | |||
Array [ | |||
Object { | |||
"class": undefined, | |||
"label": "projects.sorting.name (projects.sorting.default)", | |||
"label": "projects.sorting.name", | |||
"value": "name", | |||
}, | |||
Object { | |||
@@ -121,7 +121,7 @@ exports[`should render correctly for leak view 1`] = ` | |||
autosize={true} | |||
backspaceRemoves={true} | |||
backspaceToRemoveMessage="Press backspace to remove {label}" | |||
className="little-spacer-left input-large" | |||
className="little-spacer-left input-medium" | |||
clearAllText="Clear all" | |||
clearValueText="Clear value" | |||
clearable={false} | |||
@@ -150,7 +150,7 @@ exports[`should render correctly for leak view 1`] = ` | |||
Array [ | |||
Object { | |||
"class": undefined, | |||
"label": "projects.sorting.analysis_date (projects.sorting.default)", | |||
"label": "projects.sorting.analysis_date", | |||
"value": "analysis_date", | |||
}, | |||
Object { | |||
@@ -230,7 +230,7 @@ exports[`should render correctly for overall view 1`] = ` | |||
autosize={true} | |||
backspaceRemoves={true} | |||
backspaceToRemoveMessage="Press backspace to remove {label}" | |||
className="little-spacer-left input-large" | |||
className="little-spacer-left input-medium" | |||
clearAllText="Clear all" | |||
clearValueText="Clear value" | |||
clearable={false} | |||
@@ -259,7 +259,7 @@ exports[`should render correctly for overall view 1`] = ` | |||
Array [ | |||
Object { | |||
"class": undefined, | |||
"label": "projects.sorting.name (projects.sorting.default)", | |||
"label": "projects.sorting.name", | |||
"value": "name", | |||
}, | |||
Object { |
@@ -22,6 +22,7 @@ import React from 'react'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
type Props = { | |||
className?: string, | |||
handleSearch: (userString?: string) => void, | |||
query: { search?: string } | |||
}; | |||
@@ -63,11 +64,10 @@ export default class SearchFilter extends React.PureComponent { | |||
const { userQuery } = this.state; | |||
const shortQuery = userQuery != null && userQuery.length === 1; | |||
return ( | |||
<div className="projects-facet-search" data-key="search"> | |||
<div className={this.props.className}> | |||
<input | |||
type="search" | |||
value={userQuery || ''} | |||
className="input-super-large" | |||
placeholder={translate('projects.search')} | |||
onChange={this.handleQueryChange} | |||
autoComplete="off" |
@@ -24,12 +24,13 @@ import { debounce } from 'lodash'; | |||
import { getFilterUrl } from './utils'; | |||
import SearchFilter from './SearchFilter'; | |||
type Props = { | |||
type Props = {| | |||
className?: string, | |||
query: { search?: string }, | |||
router: { push: ({ pathname: string }) => void }, | |||
isFavorite?: boolean, | |||
organization?: {} | |||
}; | |||
|}; | |||
class SearchFilterContainer extends React.PureComponent { | |||
handleSearch: (userQuery?: string) => void; | |||
@@ -46,7 +47,13 @@ class SearchFilterContainer extends React.PureComponent { | |||
} | |||
render() { | |||
return <SearchFilter query={this.props.query} handleSearch={this.handleSearch} />; | |||
return ( | |||
<SearchFilter | |||
className={this.props.className} | |||
query={this.props.query} | |||
handleSearch={this.handleSearch} | |||
/> | |||
); | |||
} | |||
} | |||
@@ -1,13 +1,9 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should display a help message when there is less than 2 characters 1`] = ` | |||
<div | |||
className="projects-facet-search" | |||
data-key="search" | |||
> | |||
<div> | |||
<input | |||
autoComplete="off" | |||
className="input-super-large" | |||
onChange={[Function]} | |||
placeholder="projects.search" | |||
type="search" | |||
@@ -22,13 +18,9 @@ exports[`should display a help message when there is less than 2 characters 1`] | |||
`; | |||
exports[`should display a help message when there is less than 2 characters 2`] = ` | |||
<div | |||
className="projects-facet-search" | |||
data-key="search" | |||
> | |||
<div> | |||
<input | |||
autoComplete="off" | |||
className="input-super-large" | |||
onChange={[Function]} | |||
placeholder="projects.search" | |||
type="search" | |||
@@ -38,13 +30,9 @@ exports[`should display a help message when there is less than 2 characters 2`] | |||
`; | |||
exports[`should render correctly without any search query 1`] = ` | |||
<div | |||
className="projects-facet-search" | |||
data-key="search" | |||
> | |||
<div> | |||
<input | |||
autoComplete="off" | |||
className="input-super-large" | |||
onChange={[Function]} | |||
placeholder="projects.search" | |||
type="search" | |||
@@ -54,13 +42,9 @@ exports[`should render correctly without any search query 1`] = ` | |||
`; | |||
exports[`should render with a search query 1`] = ` | |||
<div | |||
className="projects-facet-search" | |||
data-key="search" | |||
> | |||
<div> | |||
<input | |||
autoComplete="off" | |||
className="input-super-large" | |||
onChange={[Function]} | |||
placeholder="projects.search" | |||
type="search" |
@@ -1,7 +1,3 @@ | |||
.projects-page-actions { | |||
margin-bottom: 0; | |||
} | |||
.projects-page-side { | |||
transition: top 150ms ease-out; | |||
} | |||
@@ -10,48 +6,27 @@ | |||
transition: padding-top 150ms ease-out; | |||
} | |||
.projects-topbar { | |||
position: fixed; | |||
width: 100%; | |||
z-index: 100; | |||
} | |||
.projects-topbar-actions { | |||
box-sizing: border-box; | |||
position: absolute; | |||
left: 0; | |||
right: 0; | |||
top: -50px; | |||
z-index: 50; | |||
flex-grow: 0.000001; | |||
border-bottom: 1px solid #e6e6e6; | |||
background-color: #fff; | |||
transition: top 150ms ease-out; | |||
.projects-topbar-items { | |||
display: flex; | |||
align-items: center; | |||
flex-grow: 1; | |||
} | |||
.projects-topbar-actions.open { | |||
top: 0; | |||
.projects-topbar-item + .projects-topbar-item { | |||
padding-left: 24px; | |||
} | |||
.projects-topbar-actions-inner { | |||
position: relative; | |||
margin: auto; | |||
padding: 0 20px; | |||
min-width: 1040px; | |||
max-width: 1280px; | |||
.projects-topbar-item .spinner { | |||
top: -1px; | |||
} | |||
.projects-topbar-items { | |||
display: flex; | |||
flex-wrap: nowrap; | |||
justify-content: center; | |||
align-items: center; | |||
flex-grow: 1; | |||
height: 46px; | |||
.projects-topbar-item.is-last { | |||
margin-left: auto; | |||
padding-left: 32px; | |||
} | |||
.projects-topbar-item { | |||
padding: 0 24px; | |||
.projects-topbar-item.is-loading { | |||
padding-left: 0; | |||
} | |||
.projects-topbar-item.disabled { | |||
@@ -63,14 +38,22 @@ | |||
pointer-events: none !important; | |||
} | |||
.projects-topbar-button { | |||
position: absolute; | |||
right: 20px; | |||
top: 10px; | |||
.projects-topbar-item-search { | |||
position: relative; | |||
flex: 1; | |||
} | |||
.projects-sidebar { | |||
width: 260px; | |||
.projects-topbar-item-search input { | |||
width: 100%; | |||
max-width: 300px; | |||
} | |||
.projects-topbar-item-search .note { | |||
position: absolute; | |||
top: 1px; | |||
left: 80px; | |||
line-height: 24px; | |||
pointer-events: none; | |||
} | |||
.projects-list .page-actions { | |||
@@ -237,26 +220,12 @@ | |||
border-bottom: 1px solid #e6e6e6; | |||
} | |||
.projects-facet-search { | |||
position: absolute; | |||
bottom: 0; | |||
left: 0; | |||
width: 300px; | |||
} | |||
.projects-facet-search .note { | |||
position: absolute; | |||
top: 1px; | |||
right: 30px; | |||
line-height: 24px; | |||
pointer-events: none; | |||
} | |||
.projects-facets-reset { | |||
float: right; | |||
} | |||
.projects-facets-reset .button {} | |||
.projects-facets-reset .button { | |||
} | |||
.projects-facet-bar { | |||
display: inline-block; | |||
@@ -272,7 +241,8 @@ | |||
} | |||
.search-navigator-facet.active .projects-facet-bar-inner, | |||
.search-navigator-facet-highlight-under-container .search-navigator-facet.active ~ .search-navigator-facet .projects-facet-bar-inner { | |||
.search-navigator-facet-highlight-under-container .search-navigator-facet.active | |||
~ .search-navigator-facet .projects-facet-bar-inner { | |||
background-color: #4b9fd5; | |||
} | |||
@@ -178,15 +178,19 @@ | |||
background: #f3f3f3; | |||
@media (max-width: 1335px) { | |||
& { width: 310px; } | |||
& { | |||
width: 310px; | |||
} | |||
} | |||
.search-navigator-facets-list { | |||
width: 260px; | |||
margin-left: ~"calc(50vw - 640px + 290px - 260px - 37px)"; | |||
@media (max-width: 1335px) { | |||
& { margin-left: 20px; } | |||
& { | |||
margin-left: 20px; | |||
} | |||
} | |||
} | |||
} | |||
@@ -241,6 +245,40 @@ | |||
background-color: #f3f3f3; | |||
} | |||
.layout-page-header-panel, .layout-page-header-panel-inner { | |||
height: 56px; | |||
box-sizing: border-box; | |||
} | |||
.layout-page-header-panel { | |||
margin-top: -20px; | |||
} | |||
.layout-page-header-panel-inner { | |||
position: fixed; | |||
z-index: 30; | |||
line-height: 24px; | |||
padding-top: 16px; | |||
padding-bottom: 16px; | |||
border-bottom: 1px solid #e6e6e6; | |||
background-color: #f3f3f3; | |||
} | |||
.layout-page-main-header { | |||
margin-bottom: 20px; | |||
} | |||
.layout-page-main-header .component-name { | |||
line-height: 24px; | |||
} | |||
.layout-page-main-header-inner { | |||
left: ~"calc(50vw - 360px + 1px)"; | |||
right: 0; | |||
padding-left: 20px; | |||
padding-right: 20px; | |||
} | |||
@media (max-width: 1320px) { | |||
.layout-page-side-outer { | |||
width: 300px; | |||
@@ -253,4 +291,8 @@ | |||
.layout-page-side-inner { | |||
margin-left: 0; | |||
} | |||
} | |||
.layout-page-main-header-inner { | |||
left: 301px; | |||
} | |||
} |