margin-right: 4px;
}
+.shortcut-button-tiny {
+ width: 14px;
+ min-width: auto;
+ padding: 0;
+ height: 14px;
+ line-height: inherit;
+ font-size: 6px;
+}
+
+.page-shortcuts-tooltip {
+ line-height: 12px;
+}
+
.identity-provider {
display: inline-block;
line-height: 14px;
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
import PageCounter from '../../../components/common/PageCounter';
+import PageShortcutsTooltip from '../../../components/ui/PageShortcutsTooltip';
-interface Props {
+export interface PageActionsProps {
loading: boolean;
onReload: () => void;
paging?: T.Paging;
selectedIndex?: number;
}
-export default function PageActions(props: Props) {
+export default function PageActions(props: PageActionsProps) {
return (
- <div className="pull-right">
- <Shortcuts />
+ <div className="display-flex-center display-flex-justify-end">
+ <PageShortcutsTooltip
+ className="big-spacer-right"
+ leftAndRightLabel={translate('issues.to_navigate')}
+ upAndDownLabel={translate('coding_rules.to_select_rules')}
+ />
<DeferredSpinner loading={props.loading}>
<ReloadButton onClick={props.onReload} />
</div>
);
}
-
-function Shortcuts() {
- return (
- <span className="note big-spacer-right">
- <span className="big-spacer-right">
- <span className="shortcut-button little-spacer-right">↑</span>
- <span className="shortcut-button little-spacer-right">↓</span>
- {translate('coding_rules.to_select_rules')}
- </span>
-
- <span>
- <span className="shortcut-button little-spacer-right">←</span>
- <span className="shortcut-button little-spacer-right">→</span>
- {translate('issues.to_navigate')}
- </span>
- </span>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import PageActions, { PageActionsProps } from '../PageActions';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
+ expect(shallowRender({ paging: { total: 100 } as T.Paging })).toMatchSnapshot('with paging');
+});
+
+function shallowRender(props: Partial<PageActionsProps> = {}) {
+ return shallow<PageActionsProps>(<PageActions loading={false} onReload={jest.fn()} {...props} />);
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+ className="display-flex-center display-flex-justify-end"
+>
+ <PageShortcutsTooltip
+ className="big-spacer-right"
+ leftAndRightLabel="issues.to_navigate"
+ upAndDownLabel="coding_rules.to_select_rules"
+ />
+ <DeferredSpinner
+ loading={false}
+ >
+ <ReloadButton
+ onClick={[MockFunction]}
+ />
+ </DeferredSpinner>
+</div>
+`;
+
+exports[`should render correctly: loading 1`] = `
+<div
+ className="display-flex-center display-flex-justify-end"
+>
+ <PageShortcutsTooltip
+ className="big-spacer-right"
+ leftAndRightLabel="issues.to_navigate"
+ upAndDownLabel="coding_rules.to_select_rules"
+ />
+ <DeferredSpinner
+ loading={true}
+ >
+ <ReloadButton
+ onClick={[MockFunction]}
+ />
+ </DeferredSpinner>
+</div>
+`;
+
+exports[`should render correctly: with paging 1`] = `
+<div
+ className="display-flex-center display-flex-justify-end"
+>
+ <PageShortcutsTooltip
+ className="big-spacer-right"
+ leftAndRightLabel="issues.to_navigate"
+ upAndDownLabel="coding_rules.to_select_rules"
+ />
+ <DeferredSpinner
+ loading={false}
+ >
+ <ReloadButton
+ onClick={[MockFunction]}
+ />
+ </DeferredSpinner>
+ <PageCounter
+ className="spacer-left"
+ label="coding_rules._rules"
+ total={100}
+ />
+</div>
+`;
this.handleCloseBulkChange();
};
- handleReload = () => {
- this.fetchFirstIssues();
- this.refreshBranchStatus();
- const { branchLike, onBranchesChange } = this.props;
- if (onBranchesChange && isPullRequest(branchLike)) {
- onBranchesChange();
- }
- };
-
- handleReloadAndOpenFirst = () => {
- this.fetchFirstIssues().then(
- (issues: T.Issue[]) => {
- if (issues.length > 0) {
- this.openIssue(issues[0].key);
- }
- },
- () => {}
- );
- };
-
selectLocation = (index: number) => {
this.setState(actions.selectLocation(index));
};
displayBackButton={query.issues.length !== 1}
loading={this.state.loading}
onBackClick={this.closeIssue}
- onReload={this.handleReloadAndOpenFirst}
- paging={paging}
- selectedIndex={this.getSelectedIndex()}
/>
<ConciseIssuesList
issues={issues}
<PageActions
canSetHome={!this.props.component}
effortTotal={this.state.effortTotal}
- onReload={this.handleReload}
paging={paging}
selectedIndex={selectedIndex}
/>
}
render() {
- const { openIssue } = this.state;
+ const { openIssue, paging } = this.state;
+ const selectedIndex = this.getSelectedIndex();
return (
<div className="layout-page issues" id="issues-page">
<Suggestions suggestions="issues" />
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2021 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 * as React from 'react';
-import { translate } from 'sonar-ui-common/helpers/l10n';
-
-export interface Props {
- issue: Pick<T.Issue, 'flows' | 'secondaryLocations'> | undefined;
-}
-
-export default function LocationNavigationKeyboardShortcuts({ issue }: Props) {
- if (!issue || (!issue.secondaryLocations.length && !issue.flows.length)) {
- return null;
- }
- const hasSeveralFlows = issue.flows.length > 1;
- return (
- <div className="navigation-keyboard-shortcuts big-spacer-top text-center">
- <span>
- alt + ↑ ↓ {hasSeveralFlows && <>←→</>}
- {translate('issues.to_navigate_issue_locations')}
- </span>
- </div>
- );
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import ReloadButton from 'sonar-ui-common/components/controls/ReloadButton';
import { translate } from 'sonar-ui-common/helpers/l10n';
import HomePageSelect from '../../../components/controls/HomePageSelect';
+import PageShortcutsTooltip from '../../../components/ui/PageShortcutsTooltip';
import { isSonarCloud } from '../../../helpers/system';
import IssuesCounter from './IssuesCounter';
import TotalEffort from './TotalEffort';
-interface Props {
+export interface PageActionsProps {
canSetHome: boolean;
effortTotal: number | undefined;
- onReload: () => void;
- paging: T.Paging | undefined;
- selectedIndex: number | undefined;
+ paging?: T.Paging;
+ selectedIndex?: number;
}
-export default class PageActions extends React.PureComponent<Props> {
- renderShortcuts() {
- return (
- <span className="note big-spacer-right">
- <span className="big-spacer-right">
- <span className="shortcut-button little-spacer-right">↑</span>
- <span className="shortcut-button little-spacer-right">↓</span>
- {translate('issues.to_select_issues')}
- </span>
+export default function PageActions(props: PageActionsProps) {
+ const { canSetHome, effortTotal, paging, selectedIndex } = props;
- <span>
- <span className="shortcut-button little-spacer-right">←</span>
- <span className="shortcut-button little-spacer-right">→</span>
- {translate('issues.to_navigate')}
- </span>
- </span>
- );
- }
+ return (
+ <div className="display-flex-center display-flex-justify-end">
+ <PageShortcutsTooltip
+ leftAndRightLabel={translate('issues.to_navigate')}
+ upAndDownLabel={translate('issues.to_select_issues')}
+ />
- render() {
- const { effortTotal, paging, selectedIndex } = this.props;
-
- return (
- <div className="pull-right">
- {this.renderShortcuts()}
-
- <div className="issues-page-actions">
- <ReloadButton onClick={this.props.onReload} />
- {paging != null && <IssuesCounter current={selectedIndex} total={paging.total} />}
- {effortTotal !== undefined && <TotalEffort effort={effortTotal} />}
- </div>
-
- {this.props.canSetHome && (
- <HomePageSelect
- className="huge-spacer-left"
- currentPage={isSonarCloud() ? { type: 'MY_ISSUES' } : { type: 'ISSUES' }}
- />
- )}
+ <div className="spacer-left issues-page-actions">
+ {paging != null && <IssuesCounter current={selectedIndex} total={paging.total} />}
+ {effortTotal !== undefined && <TotalEffort effort={effortTotal} />}
</div>
- );
- }
+
+ {canSetHome && (
+ <HomePageSelect
+ className="huge-spacer-left"
+ currentPage={isSonarCloud() ? { type: 'MY_ISSUES' } : { type: 'ISSUES' }}
+ />
+ )}
+ </div>
+ );
}
fetchBranchStatus.mockClear();
instance.handleBulkChangeDone();
expect(fetchBranchStatus).toBeCalled();
-
- fetchBranchStatus.mockClear();
- instance.handleReload();
- expect(fetchBranchStatus).toBeCalled();
});
it('should update the open issue when it is changed', async () => {
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockFlowLocation } from '../../../../helpers/testMocks';
-import LocationNavigationKeyboardShortcuts, { Props } from '../LocationNavigationKeyboardShortcuts';
-
-it('should render correctly', () => {
- expect(shallowRender().type()).toBeNull();
- expect(shallowRender({ issue: { flows: [], secondaryLocations: [] } }).type()).toBeNull();
- expect(
- shallowRender({ issue: { flows: [], secondaryLocations: [mockFlowLocation()] } })
- ).toMatchSnapshot();
- expect(
- shallowRender({ issue: { flows: [[mockFlowLocation()]], secondaryLocations: [] } })
- ).toMatchSnapshot();
-});
-
-const shallowRender = (props: Partial<Props> = {}) => {
- return shallow(<LocationNavigationKeyboardShortcuts issue={undefined} {...props} />);
-};
import PageActions from '../PageActions';
it('should render', () => {
- expect(
- shallow(
- <PageActions
- canSetHome={true}
- effortTotal={125}
- onReload={jest.fn()}
- paging={{ pageIndex: 1, pageSize: 100, total: 12345 }}
- selectedIndex={5}
- />
- )
- ).toMatchSnapshot();
+ expect(shallow(<PageActions canSetHome={true} effortTotal={125} />)).toMatchSnapshot();
});
<PageActions
canSetHome={false}
effortTotal={1}
- onReload={[Function]}
paging={
Object {
"pageIndex": 1,
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
- className="navigation-keyboard-shortcuts big-spacer-top text-center"
->
- <span>
- alt + ↑ ↓
- issues.to_navigate_issue_locations
- </span>
-</div>
-`;
-
-exports[`should render correctly 2`] = `
-<div
- className="navigation-keyboard-shortcuts big-spacer-top text-center"
->
- <span>
- alt + ↑ ↓
- issues.to_navigate_issue_locations
- </span>
-</div>
-`;
exports[`should render 1`] = `
<div
- className="pull-right"
+ className="display-flex-center display-flex-justify-end"
>
- <span
- className="note big-spacer-right"
- >
- <span
- className="big-spacer-right"
- >
- <span
- className="shortcut-button little-spacer-right"
- >
- ↑
- </span>
- <span
- className="shortcut-button little-spacer-right"
- >
- ↓
- </span>
- issues.to_select_issues
- </span>
- <span>
- <span
- className="shortcut-button little-spacer-right"
- >
- ←
- </span>
- <span
- className="shortcut-button little-spacer-right"
- >
- →
- </span>
- issues.to_navigate
- </span>
- </span>
+ <PageShortcutsTooltip
+ leftAndRightLabel="issues.to_navigate"
+ upAndDownLabel="issues.to_select_issues"
+ />
<div
- className="issues-page-actions"
+ className="spacer-left issues-page-actions"
>
- <ReloadButton
- onClick={[MockFunction]}
- />
- <IssuesCounter
- current={5}
- total={12345}
- />
<TotalEffort
effort={125}
/>
import * as classNames from 'classnames';
import * as React from 'react';
import TypeHelper from '../../../components/shared/TypeHelper';
-import LocationNavigationKeyboardShortcuts from '../components/LocationNavigationKeyboardShortcuts';
import ConciseIssueLocations from './ConciseIssueLocations';
import ConciseIssueLocationsNavigator from './ConciseIssueLocationsNavigator';
/>
</div>
{selected && (
- <>
- <ConciseIssueLocationsNavigator
- issue={issue}
- onLocationSelect={this.props.onLocationSelect}
- scroll={this.props.scroll}
- selectedFlowIndex={this.props.selectedFlowIndex}
- selectedLocationIndex={this.props.selectedLocationIndex}
- />
- <LocationNavigationKeyboardShortcuts issue={issue} />
- </>
+ <ConciseIssueLocationsNavigator
+ issue={issue}
+ onLocationSelect={this.props.onLocationSelect}
+ scroll={this.props.scroll}
+ selectedFlowIndex={this.props.selectedFlowIndex}
+ selectedLocationIndex={this.props.selectedLocationIndex}
+ />
)}
</div>
);
*/
import * as React from 'react';
import BackButton from 'sonar-ui-common/components/controls/BackButton';
-import ReloadButton from 'sonar-ui-common/components/controls/ReloadButton';
-import IssuesCounter from '../components/IssuesCounter';
+import { translate } from 'sonar-ui-common/helpers/l10n';
+import PageShortcutsTooltip from '../../../components/ui/PageShortcutsTooltip';
-interface Props {
- displayBackButton?: boolean;
+export interface ConciseIssuesListHeaderProps {
+ displayBackButton: boolean;
loading: boolean;
onBackClick: () => void;
- onReload: () => void;
- paging: T.Paging | undefined;
- selectedIndex: number | undefined;
}
-export default function ConciseIssuesListHeader(props: Props) {
- const { displayBackButton = true, paging, selectedIndex } = props;
+export default function ConciseIssuesListHeader(props: ConciseIssuesListHeaderProps) {
+ const { displayBackButton, loading } = props;
return (
<header className="layout-page-header-panel concise-issues-list-header">
- <div className="layout-page-header-panel-inner concise-issues-list-header-inner">
- {displayBackButton && (
- <BackButton className="pull-left" disabled={props.loading} onClick={props.onBackClick} />
- )}
- {props.loading ? (
- <i className="spinner pull-right" />
- ) : (
- <ReloadButton className="pull-right" onClick={props.onReload} />
- )}
- {paging && <IssuesCounter current={selectedIndex} total={paging.total} />}
+ <div className="layout-page-header-panel-inner concise-issues-list-header-inner display-flex-center display-flex-space-between">
+ {displayBackButton && <BackButton disabled={loading} onClick={props.onBackClick} />}
+ <PageShortcutsTooltip
+ leftLabel={translate('issues.to_navigate_back')}
+ upAndDownLabel={translate('issues.to_select_issues')}
+ metaModifierLabel={translate('issues.to_navigate_issue_locations')}
+ />
+ {loading && <i className="spinner" />}
</div>
</header>
);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import ConciseIssuesListHeader, { ConciseIssuesListHeaderProps } from '../ConciseIssuesListHeader';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
+ expect(shallowRender({ displayBackButton: true })).toMatchSnapshot('with back button');
+});
+
+function shallowRender(props: Partial<ConciseIssuesListHeaderProps> = {}) {
+ return shallow<ConciseIssuesListHeaderProps>(
+ <ConciseIssuesListHeader
+ displayBackButton={false}
+ loading={false}
+ onBackClick={jest.fn()}
+ {...props}
+ />
+ );
+}
selectedFlowIndex={0}
selectedLocationIndex={0}
/>
- <LocationNavigationKeyboardShortcuts
- issue={
- Object {
- "actions": Array [],
- "component": "main.js",
- "componentLongName": "main.js",
- "componentQualifier": "FIL",
- "componentUuid": "foo1234",
- "creationDate": "2017-03-01T09:36:01+0100",
- "flows": Array [],
- "fromHotspot": false,
- "key": "AVsae-CQS-9G3txfbFN2",
- "line": 25,
- "message": "Reduce the number of conditional operators (4) used in the expression",
- "project": "myproject",
- "projectKey": "foo",
- "projectName": "Foo",
- "rule": "javascript:S1067",
- "ruleName": "foo",
- "secondaryLocations": Array [],
- "severity": "MAJOR",
- "status": "OPEN",
- "textRange": Object {
- "endLine": 26,
- "endOffset": 15,
- "startLine": 25,
- "startOffset": 0,
- },
- "transitions": Array [],
- "type": "BUG",
- }
- }
- />
</div>
`;
selectedFlowIndex={0}
selectedLocationIndex={0}
/>
- <LocationNavigationKeyboardShortcuts
- issue={
- Object {
- "actions": Array [],
- "component": "main.js",
- "componentLongName": "main.js",
- "componentQualifier": "FIL",
- "componentUuid": "foo1234",
- "creationDate": "2017-03-01T09:36:01+0100",
- "flows": Array [
- Array [
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- ],
- Array [
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- ],
- ],
- "fromHotspot": false,
- "key": "AVsae-CQS-9G3txfbFN2",
- "line": 25,
- "message": "Reduce the number of conditional operators (4) used in the expression",
- "project": "myproject",
- "projectKey": "foo",
- "projectName": "Foo",
- "rule": "javascript:S1067",
- "ruleName": "foo",
- "secondaryLocations": Array [
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- Object {
- "component": "main.js",
- "textRange": Object {
- "endLine": 2,
- "endOffset": 2,
- "startLine": 1,
- "startOffset": 1,
- },
- },
- ],
- "severity": "MAJOR",
- "status": "OPEN",
- "textRange": Object {
- "endLine": 26,
- "endOffset": 15,
- "startLine": 25,
- "startOffset": 0,
- },
- "transitions": Array [],
- "type": "BUG",
- }
- }
- />
</div>
`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<header
+ className="layout-page-header-panel concise-issues-list-header"
+>
+ <div
+ className="layout-page-header-panel-inner concise-issues-list-header-inner display-flex-center display-flex-space-between"
+ >
+ <PageShortcutsTooltip
+ leftLabel="issues.to_navigate_back"
+ metaModifierLabel="issues.to_navigate_issue_locations"
+ upAndDownLabel="issues.to_select_issues"
+ />
+ </div>
+</header>
+`;
+
+exports[`should render correctly: loading 1`] = `
+<header
+ className="layout-page-header-panel concise-issues-list-header"
+>
+ <div
+ className="layout-page-header-panel-inner concise-issues-list-header-inner display-flex-center display-flex-space-between"
+ >
+ <PageShortcutsTooltip
+ leftLabel="issues.to_navigate_back"
+ metaModifierLabel="issues.to_navigate_issue_locations"
+ upAndDownLabel="issues.to_select_issues"
+ />
+ <i
+ className="spinner"
+ />
+ </div>
+</header>
+`;
+
+exports[`should render correctly: with back button 1`] = `
+<header
+ className="layout-page-header-panel concise-issues-list-header"
+>
+ <div
+ className="layout-page-header-panel-inner concise-issues-list-header-inner display-flex-center display-flex-space-between"
+ >
+ <BackButton
+ disabled={false}
+ onClick={[MockFunction]}
+ />
+ <PageShortcutsTooltip
+ leftLabel="issues.to_navigate_back"
+ metaModifierLabel="issues.to_navigate_issue_locations"
+ upAndDownLabel="issues.to_select_issues"
+ />
+ </div>
+</header>
+`;
.bulk-change-radio-button:hover {
background-color: var(--barBackgroundColor);
}
-
-.navigation-keyboard-shortcuts > span {
- background-color: var(--transparentGray);
- border-radius: 16px;
- display: inline-block;
- font-size: var(--smallFontSize);
- height: 16px;
- padding: calc(var(--gridSize) / 2) var(--gridSize);
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 * as classNames from 'classnames';
+import * as React from 'react';
+import Tooltip from 'sonar-ui-common/components/controls/Tooltip';
+import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
+
+export interface PageShortcutsTooltipProps {
+ className?: string;
+ leftAndRightLabel?: string;
+ leftLabel?: string;
+ upAndDownLabel?: string;
+ metaModifierLabel?: string;
+}
+
+export default function PageShortcutsTooltip(props: PageShortcutsTooltipProps) {
+ const { className, leftAndRightLabel, leftLabel, upAndDownLabel, metaModifierLabel } = props;
+ return (
+ <Tooltip
+ overlay={
+ <div className="small nowrap">
+ <div>
+ {upAndDownLabel && (
+ <span>
+ <span className="shortcut-button little-spacer-right">↑</span>
+ <span className="shortcut-button spacer-right">↓</span>
+ {upAndDownLabel}
+ </span>
+ )}
+ {leftAndRightLabel && (
+ <span className={classNames({ 'big-spacer-left': upAndDownLabel })}>
+ <span className="shortcut-button little-spacer-right">←</span>
+ <span className="shortcut-button spacer-right">→</span>
+ {leftAndRightLabel}
+ </span>
+ )}
+ {leftLabel && (
+ <span className={classNames({ 'big-spacer-left': upAndDownLabel })}>
+ <span className="shortcut-button spacer-right">←</span>
+ {leftLabel}
+ </span>
+ )}
+ </div>
+ {metaModifierLabel && (
+ <div className="big-spacer-top big-padded-top bordered-top">
+ <span className="shortcut-button little-spacer-right">alt</span>
+ <span className="little-spacer-right">+</span>
+ <span className="shortcut-button little-spacer-right">↑</span>
+ <span className="shortcut-button spacer-right">↓</span>
+ <span className="shortcut-button little-spacer-right">←</span>
+ <span className="shortcut-button spacer-right">→</span>
+ {metaModifierLabel}
+ </div>
+ )}
+ </div>
+ }>
+ <div
+ aria-label={`
+ ${translate('shortcuts.on_page.intro')}
+ ${
+ upAndDownLabel
+ ? translateWithParameters('shortcuts.on_page.up_down_x', upAndDownLabel)
+ : ''
+ }
+ ${
+ leftAndRightLabel
+ ? translateWithParameters('shortcuts.on_page.left_right_x', leftAndRightLabel)
+ : ''
+ }
+ ${leftLabel ? translateWithParameters('shortcuts.on_page.left_x', leftLabel) : ''}
+ ${
+ metaModifierLabel
+ ? translateWithParameters('shortcuts.on_page.meta_x', metaModifierLabel)
+ : ''
+ }
+ `}
+ className={classNames(
+ className,
+ 'page-shortcuts-tooltip note text-center display-inline-block'
+ )}>
+ <div>
+ <span className="shortcut-button shortcut-button-tiny">↑</span>
+ </div>
+ <div>
+ <span className="shortcut-button shortcut-button-tiny">←</span>
+ <span className="shortcut-button shortcut-button-tiny">↓</span>
+ <span className="shortcut-button shortcut-button-tiny">→</span>
+ </div>
+ </div>
+ </Tooltip>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import PageShortcutsTooltip, { PageShortcutsTooltipProps } from '../PageShortcutsTooltip';
+
+it('should render correctly', () => {
+ expect(shallowRender()).toMatchSnapshot('default');
+ expect(shallowRender({ upAndDownLabel: 'foo', leftAndRightLabel: 'bar' })).toMatchSnapshot(
+ 'with up/down and left/right labels'
+ );
+ expect(shallowRender({ leftLabel: 'baz' })).toMatchSnapshot('only left label');
+ expect(shallowRender({ metaModifierLabel: 'funky' })).toMatchSnapshot('with meta label');
+});
+
+function shallowRender(props: Partial<PageShortcutsTooltipProps> = {}) {
+ return shallow<PageShortcutsTooltipProps>(<PageShortcutsTooltip {...props} />);
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<Tooltip
+ overlay={
+ <div
+ className="small nowrap"
+ >
+ <div />
+ </div>
+ }
+>
+ <div
+ aria-label="
+ shortcuts.on_page.intro
+
+
+
+
+ "
+ className="page-shortcuts-tooltip note text-center display-inline-block"
+ >
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↑
+ </span>
+ </div>
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↓
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ →
+ </span>
+ </div>
+ </div>
+</Tooltip>
+`;
+
+exports[`should render correctly: only left label 1`] = `
+<Tooltip
+ overlay={
+ <div
+ className="small nowrap"
+ >
+ <div>
+ <span
+ className=""
+ >
+ <span
+ className="shortcut-button spacer-right"
+ >
+ ←
+ </span>
+ baz
+ </span>
+ </div>
+ </div>
+ }
+>
+ <div
+ aria-label="
+ shortcuts.on_page.intro
+
+
+ shortcuts.on_page.left_x.baz
+
+ "
+ className="page-shortcuts-tooltip note text-center display-inline-block"
+ >
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↑
+ </span>
+ </div>
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↓
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ →
+ </span>
+ </div>
+ </div>
+</Tooltip>
+`;
+
+exports[`should render correctly: with meta label 1`] = `
+<Tooltip
+ overlay={
+ <div
+ className="small nowrap"
+ >
+ <div />
+ <div
+ className="big-spacer-top big-padded-top bordered-top"
+ >
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ alt
+ </span>
+ <span
+ className="little-spacer-right"
+ >
+ +
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↑
+ </span>
+ <span
+ className="shortcut-button spacer-right"
+ >
+ ↓
+ </span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button spacer-right"
+ >
+ →
+ </span>
+ funky
+ </div>
+ </div>
+ }
+>
+ <div
+ aria-label="
+ shortcuts.on_page.intro
+
+
+
+ shortcuts.on_page.meta_x.funky
+ "
+ className="page-shortcuts-tooltip note text-center display-inline-block"
+ >
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↑
+ </span>
+ </div>
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↓
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ →
+ </span>
+ </div>
+ </div>
+</Tooltip>
+`;
+
+exports[`should render correctly: with up/down and left/right labels 1`] = `
+<Tooltip
+ overlay={
+ <div
+ className="small nowrap"
+ >
+ <div>
+ <span>
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ↑
+ </span>
+ <span
+ className="shortcut-button spacer-right"
+ >
+ ↓
+ </span>
+ foo
+ </span>
+ <span
+ className="big-spacer-left"
+ >
+ <span
+ className="shortcut-button little-spacer-right"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button spacer-right"
+ >
+ →
+ </span>
+ bar
+ </span>
+ </div>
+ </div>
+ }
+>
+ <div
+ aria-label="
+ shortcuts.on_page.intro
+ shortcuts.on_page.up_down_x.foo
+ shortcuts.on_page.left_right_x.bar
+
+
+ "
+ className="page-shortcuts-tooltip note text-center display-inline-block"
+ >
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↑
+ </span>
+ </div>
+ <div>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ←
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ ↓
+ </span>
+ <span
+ className="shortcut-button shortcut-button-tiny"
+ >
+ →
+ </span>
+ </div>
+ </div>
+</Tooltip>
+`;
issues.issues=issues
issues.to_select_issues=to select issues
issues.to_navigate=to navigate
+issues.to_navigate_back=to navigate back
issues.to_navigate_issue_locations=to navigate issue locations
issues.to_switch_flows=to switch flows
issues.new_code=New code
shortcuts.section.rules.activate=activate selected rule
shortcuts.section.rules.deactivate=deactivate selected rule
+shortcuts.on_page.intro=This page allows you to use the following keyboard shortcuts:
+shortcuts.on_page.left_x=Left arrow key: {0}
+shortcuts.on_page.left_right_x=Left and right arrow keys: {0}
+shortcuts.on_page.up_down_x=Up and down arrow keys: {0}
+shortcuts.on_page.meta_x=Alt key + arrow keys: {0}
+
tutorials.onboarding=Analyze a new project
tutorials.skip=Skip this tutorial
tutorials.finish=Finish this tutorial