}
public ProjectsPage searchProject(String search) {
- SelenideElement searchInput = $(".projects-facet-search input");
+ SelenideElement searchInput = $(".projects-topbar-item-search input");
searchInput.setValue("").sendKeys(search);
return this;
}
}
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);
}
}
{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
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" />
-.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;
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;
}
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;
}
children?: React.Element<*>,
currentUser: { isLoggedIn: boolean },
location: Object,
- optionBarOpen: boolean,
- optionBarToggle: (open: boolean) => void,
organization: {
key: string
}
<FavoriteProjectsContainer
currentUser={this.props.currentUser}
location={this.props.location}
- optionBarOpen={this.props.optionBarOpen}
- optionBarToggle={this.props.optionBarToggle}
organization={this.props.organization}
/>
</div>
children?: React.Element<*>,
currentUser: { isLoggedIn: boolean },
location: Object,
- optionBarOpen: boolean,
- optionBarToggle: (open: boolean) => void,
organization: {
key: string
}
currentUser={this.props.currentUser}
isFavorite={false}
location={this.props.location}
- optionBarOpen={this.props.optionBarOpen}
- optionBarToggle={this.props.optionBarToggle}
organization={this.props.organization}
/>
</div>
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
});
}
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';
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 }
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 } = {
});
};
- 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>
);
//@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>
);
}
type Props = {
currentUser: { isLoggedIn: boolean },
location: { query: {} },
- optionBarOpen: boolean,
- optionBarToggle: (open: boolean) => void,
router: {
replace: (location: { pathname?: string, query?: { [string]: string } }) => void
}
<AllProjectsContainer
isFavorite={false}
location={this.props.location}
- optionBarOpen={this.props.optionBarOpen}
- optionBarToggle={this.props.optionBarToggle}
currentUser={this.props.currentUser}
/>
);
*/
// @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>}
*/
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);
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>;
+++ /dev/null
-/*
- * 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>
- );
- }
-}
+++ /dev/null
-/*
- * 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);
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
}));
};
<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}
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();
+});
+++ /dev/null
-/*
- * 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();
-});
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",
}
/>
<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"
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 {
}
/>
<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"
/>
</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"
+/>
+`;
+++ /dev/null
-// 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"
-/>
-`;
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}
Array [
Object {
"class": undefined,
- "label": "projects.sorting.name (projects.sorting.default)",
+ "label": "projects.sorting.name",
"value": "name",
},
Object {
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}
Array [
Object {
"class": undefined,
- "label": "projects.sorting.analysis_date (projects.sorting.default)",
+ "label": "projects.sorting.analysis_date",
"value": "analysis_date",
},
Object {
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}
Array [
Object {
"class": undefined,
- "label": "projects.sorting.name (projects.sorting.default)",
+ "label": "projects.sorting.name",
"value": "name",
},
Object {
import { translate, translateWithParameters } from '../../../helpers/l10n';
type Props = {
+ className?: string,
handleSearch: (userString?: string) => void,
query: { search?: string }
};
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"
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;
}
render() {
- return <SearchFilter query={this.props.query} handleSearch={this.handleSearch} />;
+ return (
+ <SearchFilter
+ className={this.props.className}
+ query={this.props.query}
+ handleSearch={this.handleSearch}
+ />
+ );
}
}
// 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"
`;
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"
`;
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"
`;
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"
-.projects-page-actions {
- margin-bottom: 0;
-}
-
.projects-page-side {
transition: top 150ms ease-out;
}
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 {
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 {
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;
}
.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;
}
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;
+ }
}
}
}
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;
.layout-page-side-inner {
margin-left: 0;
}
-}
\ No newline at end of file
+
+ .layout-page-main-header-inner {
+ left: 301px;
+ }
+}