+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { Link } from 'react-router';
-import { getRuleUrl } from '../../../helpers/urls';
-import { Issue, RuleDetails } from '../../../types/types';
-
-interface IssueRuleHeaderProps {
- ruleDetails: RuleDetails;
- issue: Issue;
-}
-
-export default function IssueRuleHeader(props: IssueRuleHeaderProps) {
- const {
- ruleDetails: { name, key },
- issue: { message }
- } = props;
-
- return (
- <>
- <h1 className="text-bold">{message}</h1>
- <div className="spacer-top big-spacer-bottom">
- <span className="note padded-right">{name}</span>
- <Link className="small" to={getRuleUrl(key)} target="_blank">
- {key}
- </Link>
- </div>
- </>
- );
-}
*/
import classNames from 'classnames';
import * as React from 'react';
+import { Link } from 'react-router';
import BoxedTabs from '../../../components/controls/BoxedTabs';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
-import { RuleDescriptionSections, RuleDetails } from '../../../types/types';
+import { getRuleUrl } from '../../../helpers/urls';
+import { Component, Issue, RuleDescriptionSections, RuleDetails } from '../../../types/types';
interface Props {
+ component?: Component;
+ issue: Issue;
codeTabContent: React.ReactNode;
ruleDetails: RuleDetails;
}
}
render() {
- const { codeTabContent } = this.props;
+ const {
+ component,
+ codeTabContent,
+ ruleDetails: { name, key },
+ issue: { message }
+ } = this.props;
const { tabs, currentTabKey } = this.state;
return (
<>
- <BoxedTabs onSelect={this.handleSelectTabs} selected={currentTabKey} tabs={tabs} />
- <div className="bordered huge-spacer-bottom">
+ <div
+ className={classNames('issue-header', {
+ 'issue-project-level': component !== undefined
+ })}>
+ <h1 className="text-bold">{message}</h1>
+ <div className="spacer-top big-spacer-bottom">
+ <span className="note padded-right">{name}</span>
+ <Link className="small" to={getRuleUrl(key)} target="_blank">
+ {key}
+ </Link>
+ </div>
+ <BoxedTabs
+ className="bordered-bottom"
+ onSelect={this.handleSelectTabs}
+ selected={currentTabKey}
+ tabs={tabs}
+ />
+ </div>
+ <div className="bordered-right bordered-left bordered-bottom huge-spacer-bottom">
<div
className={classNames('padded', {
hidden: currentTabKey !== TabKeys.Code
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import styled from '@emotion/styled';
+import classNames from 'classnames';
import { debounce, keyBy, omit, without } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
STANDARDS
} from '../utils';
import BulkChangeModal, { MAX_PAGE_SIZE } from './BulkChangeModal';
-import IssueRuleHeader from './IssueRuleHeader';
import IssuesList from './IssuesList';
import IssuesSourceViewer from './IssuesSourceViewer';
import IssueTabViewer from './IssueTabViewer';
paging,
loadingRule
} = this.state;
+ const { component } = this.props;
return (
<div className="layout-page-main-inner">
<DeferredSpinner loading={loadingRule}>
{openIssue && openRuleDetails ? (
- <>
- <IssueRuleHeader ruleDetails={openRuleDetails} issue={openIssue} />
- <IssueTabViewer
- codeTabContent={
- <IssuesSourceViewer
- branchLike={fillBranchLike(openIssue.branch, openIssue.pullRequest)}
- issues={issues}
- locationsNavigator={this.state.locationsNavigator}
- onIssueChange={this.handleIssueChange}
- onIssueSelect={this.openIssue}
- onLocationSelect={this.selectLocation}
- openIssue={openIssue}
- selectedFlowIndex={this.state.selectedFlowIndex}
- selectedLocationIndex={this.state.selectedLocationIndex}
- />
- }
- ruleDetails={openRuleDetails}
- />
- </>
+ <IssueTabViewer
+ codeTabContent={
+ <IssuesSourceViewer
+ branchLike={fillBranchLike(openIssue.branch, openIssue.pullRequest)}
+ issues={issues}
+ locationsNavigator={this.state.locationsNavigator}
+ onIssueChange={this.handleIssueChange}
+ onIssueSelect={this.openIssue}
+ onLocationSelect={this.selectLocation}
+ openIssue={openIssue}
+ selectedFlowIndex={this.state.selectedFlowIndex}
+ selectedLocationIndex={this.state.selectedLocationIndex}
+ />
+ }
+ issue={openIssue}
+ component={component}
+ ruleDetails={openRuleDetails}
+ />
) : (
<DeferredSpinner loading={loading}>
{checkAll && paging && paging.total > MAX_PAGE_SIZE && (
{this.renderSide(openIssue)}
- <div role="main" className="layout-page-main">
+ <div role="main" className={classNames('layout-page-main', { 'open-issue': !!openIssue })}>
{this.renderHeader({ openIssue, paging, selectedIndex })}
{this.renderPage()}
.bulk-change-radio-button:hover {
background-color: var(--barBackgroundColor);
}
+
+.issue-header {
+ z-index: 100;
+ position: sticky;
+ top: 48px;
+ background-color: white;
+ padding-top: 20px;
+}
+
+.issue-project-level.issue-header {
+ top: 120px;
+}
+
+.layout-page-main.open-issue {
+ padding-top: 0;
+}