]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19474 The code viewer header adopts the new UI
authorDavid Cho-Lerat <david.cho-lerat@sonarsource.com>
Tue, 6 Jun 2023 13:03:08 +0000 (15:03 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 9 Jun 2023 20:03:10 +0000 (20:03 +0000)
server/sonar-web/design-system/src/components/DropdownMenu.tsx
server/sonar-web/design-system/src/components/Link.tsx
server/sonar-web/design-system/src/components/icons/index.ts
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.css [deleted file]
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.tsx
server/sonar-web/src/main/js/apps/marketplace/components/PluginActions.tsx
server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/PluginActions-test.tsx.snap
server/sonar-web/src/main/js/components/SourceViewer/SourceViewerHeader.tsx
server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx [deleted file]
server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/SourceViewer/styles.css

index d822cf684379a00f071b2b275d108701c66c21c4..74c415817038d51382b52244f01e24d430b3d3f0 100644 (file)
@@ -71,18 +71,20 @@ interface ListItemProps {
 }
 
 type ItemLinkProps = Omit<ListItemProps, 'innerRef'> &
-  Pick<LinkProps, 'disabled' | 'icon' | 'onClick' | 'to'> & {
+  Pick<LinkProps, 'disabled' | 'icon' | 'isExternal' | 'onClick' | 'to'> & {
     innerRef?: React.Ref<HTMLAnchorElement>;
   };
 
 export function ItemLink(props: ItemLinkProps) {
-  const { children, className, disabled, icon, onClick, innerRef, to, ...liProps } = props;
+  const { children, className, disabled, icon, isExternal, onClick, innerRef, to, ...liProps } =
+    props;
   return (
     <li {...liProps}>
       <ItemLinkStyled
         className={classNames(className, { disabled })}
         disabled={disabled}
         icon={icon}
+        isExternal={isExternal}
         onClick={onClick}
         ref={innerRef}
         role="menuitem"
index c11760152233d3d638b51e9bbef5040201b3a9d6..0234c8589284813f4774245e362516a6bd0cf354 100644 (file)
@@ -32,6 +32,7 @@ export interface LinkProps extends RouterLinkProps {
   disabled?: boolean;
   forceExternal?: boolean;
   icon?: React.ReactNode;
+  isExternal?: boolean;
   onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void;
   preventDefault?: boolean;
   showExternalIcon?: boolean;
@@ -45,6 +46,7 @@ function BaseLinkWithRef(props: LinkProps, ref: React.ForwardedRef<HTMLAnchorEle
     blurAfterClick,
     disabled,
     icon,
+    isExternal: isExternalProp = false,
     onClick,
     preventDefault,
     showExternalIcon = !icon,
@@ -53,7 +55,12 @@ function BaseLinkWithRef(props: LinkProps, ref: React.ForwardedRef<HTMLAnchorEle
     to,
     ...rest
   } = props;
-  const isExternal = typeof to === 'string' && to.startsWith('http');
+
+  const toAsString =
+    typeof to === 'string' ? to : `${to.pathname ?? ''}${to.search ?? ''}${to.hash ?? ''}`;
+
+  const isExternal = isExternalProp || toAsString.startsWith('http');
+
   const handleClick = React.useCallback(
     (event: React.MouseEvent<HTMLAnchorElement>) => {
       if (blurAfterClick) {
@@ -75,20 +82,24 @@ function BaseLinkWithRef(props: LinkProps, ref: React.ForwardedRef<HTMLAnchorEle
     [onClick, blurAfterClick, preventDefault, stopPropagation, disabled]
   );
 
-  return isExternal ? (
-    <a
-      {...rest}
-      href={to}
-      onClick={handleClick}
-      ref={ref}
-      rel="noopener noreferrer"
-      target={target}
-    >
-      {icon}
-      {children}
-      {showExternalIcon && <OpenNewTabIcon className="sw-ml-1" />}
-    </a>
-  ) : (
+  if (isExternal) {
+    return (
+      <a
+        {...rest}
+        href={toAsString}
+        onClick={handleClick}
+        ref={ref}
+        rel="noopener noreferrer"
+        target={target}
+      >
+        {icon}
+        {children}
+        {showExternalIcon && <OpenNewTabIcon className="sw-ml-1" />}
+      </a>
+    );
+  }
+
+  return (
     <RouterLink ref={ref} {...rest} onClick={handleClick} to={to}>
       {icon}
       {children}
index a65e5e893fa26240aabc278edef992059deb4ca3..f6a20a74a7c3c29838f48c014c629d8f173e6f9a 100644 (file)
@@ -47,6 +47,7 @@ export { LinkIcon } from './LinkIcon';
 export { LockIcon } from './LockIcon';
 export { MainBranchIcon } from './MainBranchIcon';
 export { MenuHelpIcon } from './MenuHelpIcon';
+export { MenuIcon } from './MenuIcon';
 export { MenuSearchIcon } from './MenuSearchIcon';
 export { NoDataIcon } from './NoDataIcon';
 export { OpenCloseIndicator } from './OpenCloseIndicator';
diff --git a/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.css b/server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/IssueSourceViewerHeader.css
deleted file mode 100644 (file)
index 6146efe..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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.
- */
-.issue-source-viewer-header {
-  padding: 4px 10px;
-  border: 1px solid var(--gray80);
-  background-color: var(--barBackgroundColor);
-  align-items: center;
-  min-height: 25px;
-  position: sticky;
-  z-index: 100;
-  top: 0;
-  margin-top: 8px;
-  margin-bottom: -1px;
-}
-
-.issue-source-viewer-header:first-child {
-  margin-top: 0;
-}
index e51e0e58fb2418ea7e9a370fa6d1b4e8b6f95ce8..5115e878787286d59b6a7513e9c7ef37c6a5bdc3 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import classNames from 'classnames';
 import {
@@ -42,7 +43,6 @@ import { getBranchLikeUrl, getComponentIssuesUrl, getPathUrlAsString } from '../
 import { BranchLike } from '../../../types/branch-like';
 import { ComponentQualifier } from '../../../types/component';
 import { SourceViewerFile } from '../../../types/types';
-import './IssueSourceViewerHeader.css';
 
 export const INTERACTIVE_TOOLTIP_DELAY = 0.5;
 
index 186609b0b54a653dd03d05e23aa10efe81ee9de6..487b50dabe1579329246968c441353c4117911d6 100644 (file)
 import * as React from 'react';
 import { installPlugin, uninstallPlugin, updatePlugin } from '../../../api/plugins';
 import Link from '../../../components/common/Link';
-import { Button } from '../../../components/controls/buttons';
 import Checkbox from '../../../components/controls/Checkbox';
 import Tooltip from '../../../components/controls/Tooltip';
+import { Button } from '../../../components/controls/buttons';
 import CheckIcon from '../../../components/icons/CheckIcon';
 import { translate } from '../../../helpers/l10n';
-import { isAvailablePlugin, isInstalledPlugin, Plugin } from '../../../types/plugins';
+import { Plugin, isAvailablePlugin, isInstalledPlugin } from '../../../types/plugins';
 import PluginUpdateButton from './PluginUpdateButton';
 
 interface Props {
@@ -76,7 +76,7 @@ export default class PluginActions extends React.PureComponent<Props, State> {
     const { plugin } = this.props;
 
     return (
-      <div className="js-actions">
+      <div className="it__js-actions">
         {isAvailablePlugin(plugin) && (
           <div>
             <p className="little-spacer-bottom">
@@ -120,7 +120,7 @@ export default class PluginActions extends React.PureComponent<Props, State> {
 
     const { loading } = this.state;
     return (
-      <div className="js-actions">
+      <div className="it__js-actions">
         {isAvailablePlugin(plugin) && plugin.termsAndConditionsUrl && (
           <p className="little-spacer-bottom">
             <Checkbox
index 676c7005b7acdc0a3aa7963b81ebb5fd64acd9ec..f0cbba993853db60f98e03c0bb2965c89af3c7f1 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should render available plugin correctly 1`] = `
 <div
-  className="js-actions"
+  className="it__js-actions"
 >
   <p
     className="little-spacer-bottom"
@@ -46,7 +46,7 @@ exports[`should render available plugin correctly 1`] = `
 
 exports[`should render available plugin correctly 2`] = `
 <div
-  className="js-actions"
+  className="it__js-actions"
 >
   <div>
     <p
@@ -60,7 +60,7 @@ exports[`should render available plugin correctly 2`] = `
 
 exports[`should render installed plugin correctly 1`] = `
 <div
-  className="js-actions"
+  className="it__js-actions"
 >
   <PluginUpdateButton
     disabled={false}
@@ -89,7 +89,7 @@ exports[`should render installed plugin correctly 1`] = `
 
 exports[`should render installed plugin correctly 2`] = `
 <div
-  className="js-actions"
+  className="it__js-actions"
 >
   <p>
     <CheckIcon
index c1ed0d9dafb63b70882ce741c636c39be2b43ea0..ce3f530e3c0c1fde1f44b6b6ebaa1ff62856f02d 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
+import styled from '@emotion/styled';
+import {
+  ClipboardIconButton,
+  DrilldownLink,
+  Dropdown,
+  InteractiveIcon,
+  ItemButton,
+  ItemLink,
+  Link,
+  MenuIcon,
+  Note,
+  PopupPlacement,
+  PopupZLevel,
+  ProjectIcon,
+  QualifierIcon,
+  themeBorder,
+  themeColor,
+} from 'design-system';
 import * as React from 'react';
-import { ButtonIcon } from '../../components/controls/buttons';
-import { ClipboardIconButton } from '../../components/controls/clipboard';
-import Dropdown from '../../components/controls/Dropdown';
-import ListIcon from '../../components/icons/ListIcon';
-import QualifierIcon from '../../components/icons/QualifierIcon';
-import { PopupPlacement } from '../../components/ui/popups';
+
 import { getBranchLikeQuery } from '../../helpers/branch-like';
 import { ISSUE_TYPES } from '../../helpers/constants';
 import { ISSUETYPE_METRIC_KEYS_MAP } from '../../helpers/issues';
@@ -39,13 +53,14 @@ import {
   getComponentSecurityHotspotsUrl,
   getPathUrlAsString,
 } from '../../helpers/urls';
-import { BranchLike } from '../../types/branch-like';
+
 import { ComponentQualifier } from '../../types/component';
 import { IssueType } from '../../types/issues';
-import { Measure, SourceViewerFile } from '../../types/types';
-import Link from '../common/Link';
-import { WorkspaceContextShape } from '../workspace/context';
-import MeasuresOverlay from './components/MeasuresOverlay';
+import { MetricKey, MetricType } from '../../types/metrics';
+
+import type { BranchLike } from '../../types/branch-like';
+import type { Measure, SourceViewerFile } from '../../types/types';
+import type { WorkspaceContextShape } from '../workspace/context';
 
 interface Props {
   branchLike: BranchLike | undefined;
@@ -55,64 +70,54 @@ interface Props {
   sourceViewerFile: SourceViewerFile;
 }
 
-interface State {
-  measuresOverlay: boolean;
-}
-
-export default class SourceViewerHeader extends React.PureComponent<Props, State> {
-  state: State = { measuresOverlay: false };
-
-  handleShowMeasuresClick = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
-    this.setState({ measuresOverlay: true });
-  };
-
-  handleMeasuresOverlayClose = () => {
-    this.setState({ measuresOverlay: false });
-  };
-
-  openInWorkspace = (event: React.SyntheticEvent<HTMLAnchorElement>) => {
-    event.preventDefault();
+export default class SourceViewerHeader extends React.PureComponent<Props> {
+  openInWorkspace = () => {
     const { key } = this.props.sourceViewerFile;
     this.props.openComponent({ branchLike: this.props.branchLike, key });
   };
 
   renderIssueMeasures = () => {
     const { branchLike, componentMeasures, sourceViewerFile } = this.props;
+
     return (
       componentMeasures &&
       componentMeasures.length > 0 && (
         <>
-          <div className="source-viewer-header-measure-separator" />
-
-          {ISSUE_TYPES.map((type: IssueType) => {
-            const params = {
-              ...getBranchLikeQuery(branchLike),
-              files: sourceViewerFile.path,
-              resolved: 'false',
-              types: type,
-            };
-
-            const measure = componentMeasures.find(
-              (m) => m.metric === ISSUETYPE_METRIC_KEYS_MAP[type].metric
-            );
-
-            const linkUrl =
-              type === IssueType.SecurityHotspot
-                ? getComponentSecurityHotspotsUrl(sourceViewerFile.project, params)
-                : getComponentIssuesUrl(sourceViewerFile.project, params);
-
-            return (
-              <div className="source-viewer-header-measure" key={type}>
-                <span className="source-viewer-header-measure-label">
-                  {translate('issue.type', type)}
-                </span>
-                <span className="source-viewer-header-measure-value">
-                  <Link to={linkUrl}>{formatMeasure((measure && measure.value) || 0, 'INT')}</Link>
-                </span>
-              </div>
-            );
-          })}
+          <StyledVerticalSeparator className="sw-h-8 sw-mx-6" />
+
+          <div className="sw-flex sw-gap-6">
+            {ISSUE_TYPES.map((type: IssueType) => {
+              const params = {
+                ...getBranchLikeQuery(branchLike),
+                files: sourceViewerFile.path,
+                resolved: 'false',
+                types: type,
+              };
+
+              const measure = componentMeasures.find(
+                (m) => m.metric === ISSUETYPE_METRIC_KEYS_MAP[type].metric
+              );
+
+              const linkUrl =
+                type === IssueType.SecurityHotspot
+                  ? getComponentSecurityHotspotsUrl(sourceViewerFile.project, params)
+                  : getComponentIssuesUrl(sourceViewerFile.project, params);
+
+              return (
+                <div className="sw-flex sw-flex-col sw-gap-1" key={type}>
+                  <Note className="it__source-viewer-header-measure-label sw-body-lg">
+                    {translate('issue.type', type)}
+                  </Note>
+
+                  <span>
+                    <StyledDrilldownLink className="sw-body-md" to={linkUrl}>
+                      {formatMeasure(measure?.value ?? 0, MetricType.Integer)}
+                    </StyledDrilldownLink>
+                  </span>
+                </div>
+              );
+            })}
+          </div>
         </>
       )
     );
@@ -121,80 +126,81 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
   render() {
     const { showMeasures } = this.props;
     const { key, measures, path, project, projectName, q } = this.props.sourceViewerFile;
-    const unitTestsOrLines = q === ComponentQualifier.TestFile ? 'tests' : 'lines';
-    const workspace = false;
+    const unitTestsOrLines = q === ComponentQualifier.TestFile ? MetricKey.tests : MetricKey.lines;
+
     const query = new URLSearchParams(
       omitNil({ key, ...getBranchLikeQuery(this.props.branchLike) })
     ).toString();
+
     const rawSourcesLink = `${getBaseUrl()}/api/sources/raw?${query}`;
 
-    // TODO favorite
     return (
-      <div className="source-viewer-header display-flex-center">
-        <div className="flex-1 little-spacer-top">
-          <div className="component-name">
-            <div className="component-name-parent">
-              <a
-                className="link-no-underline"
-                href={getPathUrlAsString(getBranchLikeUrl(project, this.props.branchLike))}
-              >
-                <QualifierIcon qualifier={ComponentQualifier.Project} /> <span>{projectName}</span>
-              </a>
-            </div>
-
-            <div className="component-name-path">
-              <QualifierIcon qualifier={q} /> <span>{collapsedDirFromPath(path)}</span>
-              <span className="component-name-file">{fileFromPath(path)}</span>
-              <span className="nudged-up spacer-left">
-                <ClipboardIconButton
-                  aria-label={translate('component_viewer.copy_path_to_clipboard')}
-                  className="button-link link-no-underline"
-                  copyValue={path}
-                />
-              </span>
-            </div>
+      <StyledHeaderContainer
+        className={
+          'it__source-viewer-header sw-body-sm sw-flex sw-items-center sw-px-4 sw-py-3 ' +
+          'sw-relative'
+        }
+      >
+        <div className="sw-flex sw-flex-1 sw-flex-col sw-gap-1 sw-mr-5 sw-my-1">
+          <div className="sw-flex sw-gap-1 sw-items-center">
+            <Link
+              icon={<ProjectIcon />}
+              to={getPathUrlAsString(getBranchLikeUrl(project, this.props.branchLike))}
+            >
+              {projectName}
+            </Link>
           </div>
-        </div>
 
-        {this.state.measuresOverlay && (
-          <MeasuresOverlay
-            branchLike={this.props.branchLike}
-            onClose={this.handleMeasuresOverlayClose}
-            sourceViewerFile={this.props.sourceViewerFile}
-          />
-        )}
+          <div className="sw-flex sw-gap-1 sw-items-center">
+            <QualifierIcon qualifier={q} />
+
+            {collapsedDirFromPath(path)}
+
+            {fileFromPath(path)}
+
+            <span className="sw-ml-1">
+              <ClipboardIconButton
+                aria-label={translate('component_viewer.copy_path_to_clipboard')}
+                copyValue={path}
+              />
+            </span>
+          </div>
+        </div>
 
         {showMeasures && (
-          <div className="display-flex-center">
+          <div className="sw-flex sw-gap-6 sw-items-center">
             {measures[unitTestsOrLines] && (
-              <div className="source-viewer-header-measure">
-                <span className="source-viewer-header-measure-label">
+              <div className="sw-flex sw-flex-col sw-gap-1">
+                <Note className="it__source-viewer-header-measure-label sw-body-lg">
                   {translate(`metric.${unitTestsOrLines}.name`)}
-                </span>
-                <span className="source-viewer-header-measure-value">
-                  {formatMeasure(measures[unitTestsOrLines], 'SHORT_INT')}
+                </Note>
+
+                <span className="sw-body-lg">
+                  {formatMeasure(measures[unitTestsOrLines], MetricType.ShortInteger)}
                 </span>
               </div>
             )}
 
             {measures.coverage !== undefined && (
-              <div className="source-viewer-header-measure">
-                <span className="source-viewer-header-measure-label">
+              <div className="sw-flex sw-flex-col sw-gap-1">
+                <Note className="it__source-viewer-header-measure-label sw-body-lg">
                   {translate('metric.coverage.name')}
-                </span>
-                <span className="source-viewer-header-measure-value">
-                  {formatMeasure(measures.coverage, 'PERCENT')}
+                </Note>
+
+                <span className="sw-body-lg">
+                  {formatMeasure(measures.coverage, MetricType.Percent)}
                 </span>
               </div>
             )}
 
             {measures.duplicationDensity !== undefined && (
-              <div className="source-viewer-header-measure">
-                <span className="source-viewer-header-measure-label">
+              <div className="sw-flex sw-flex-col sw-gap-1">
+                <Note className="it__source-viewer-header-measure-label sw-body-lg">
                   {translate('duplications')}
-                </span>
-                <span className="source-viewer-header-measure-value">
-                  {formatMeasure(measures.duplicationDensity, 'PERCENT')}
+                </Note>
+
+                <span className="sw-body-lg">
+                  {formatMeasure(measures.duplicationDensity, MetricType.Percent)}
                 </span>
               </div>
             )}
@@ -204,50 +210,58 @@ export default class SourceViewerHeader extends React.PureComponent<Props, State
         )}
 
         <Dropdown
-          className="source-viewer-header-actions flex-0"
+          id="source-viewer-header-actions"
           overlay={
-            <ul className="menu">
-              <li>
-                <a className="js-measures" href="#" onClick={this.handleShowMeasuresClick}>
-                  {translate('component_viewer.show_details')}
-                </a>
-              </li>
-              <li>
-                <Link
-                  className="js-new-window"
-                  rel="noopener noreferrer"
-                  target="_blank"
-                  to={getCodeUrl(this.props.sourceViewerFile.project, this.props.branchLike, key)}
-                >
-                  {translate('component_viewer.new_window')}
-                </Link>
-              </li>
-              {!workspace && (
-                <li>
-                  <a className="js-workspace" href="#" onClick={this.openInWorkspace}>
-                    {translate('component_viewer.open_in_workspace')}
-                  </a>
-                </li>
-              )}
-              <li>
-                <a
-                  className="js-raw-source"
-                  href={rawSourcesLink}
-                  rel="noopener noreferrer"
-                  target="_blank"
-                >
-                  {translate('component_viewer.show_raw_source')}
-                </a>
-              </li>
-            </ul>
+            <>
+              <ItemLink
+                isExternal
+                to={getCodeUrl(this.props.sourceViewerFile.project, this.props.branchLike, key)}
+              >
+                {translate('component_viewer.new_window')}
+              </ItemLink>
+
+              <ItemButton className="it__js-workspace" onClick={this.openInWorkspace}>
+                {translate('component_viewer.open_in_workspace')}
+              </ItemButton>
+
+              <ItemLink isExternal to={rawSourcesLink}>
+                {translate('component_viewer.show_raw_source')}
+              </ItemLink>
+            </>
           }
-          overlayPlacement={PopupPlacement.BottomRight}
+          placement={PopupPlacement.BottomRight}
+          zLevel={PopupZLevel.Global}
         >
-          <ButtonIcon className="js-actions" aria-label={translate('component_viewer.action_menu')}>
-            <ListIcon />
-          </ButtonIcon>
+          <InteractiveIcon
+            aria-label={translate('component_viewer.action_menu')}
+            className="it__js-actions sw-flex-0 sw-ml-4 sw-px-3 sw-py-2"
+            Icon={MenuIcon}
+          />
         </Dropdown>
-      </div>
+      </StyledHeaderContainer>
     );
   }
 }
+
+const StyledDrilldownLink = styled(DrilldownLink)`
+  color: ${themeColor('linkDefault')};
+
+  &:visited {
+    color: ${themeColor('linkDefault')};
+  }
+
+  &:active,
+  &:focus,
+  &:hover {
+    color: ${themeColor('linkActive')};
+  }
+`;
+
+const StyledHeaderContainer = styled.div`
+  background-color: ${themeColor('backgroundSecondary')};
+  border-bottom: ${themeBorder('default', 'codeLineBorder')};
+`;
+
+const StyledVerticalSeparator = styled.div`
+  border-right: ${themeBorder('default', 'codeLineBorder')};
+`;
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/SourceViewerHeader-test.tsx
deleted file mode 100644 (file)
index 2bf7768..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 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 { mockMainBranch } from '../../../helpers/mocks/branch-like';
-import { mockSourceViewerFile } from '../../../helpers/mocks/sources';
-import { ComponentQualifier } from '../../../types/component';
-import { MetricKey } from '../../../types/metrics';
-import { Measure } from '../../../types/types';
-import SourceViewerHeader from '../SourceViewerHeader';
-
-it('should render correctly for a regular file', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render correctly for a unit test', () => {
-  expect(
-    shallowRender({
-      showMeasures: true,
-      sourceViewerFile: mockSourceViewerFile('foo/bar.ts', 'my-project', {
-        q: ComponentQualifier.TestFile,
-        measures: { tests: '12' },
-      }),
-    })
-  ).toMatchSnapshot();
-});
-
-it('should render correctly if issue details are passed', () => {
-  const componentMeasures: Measure[] = [
-    { metric: MetricKey.code_smells, value: '1' },
-    { metric: MetricKey.file_complexity_distribution, value: '42' }, // unused, should be ignored
-    { metric: MetricKey.security_hotspots, value: '2' },
-    { metric: MetricKey.vulnerabilities, value: '2' },
-  ];
-
-  expect(
-    shallowRender({
-      componentMeasures,
-      showMeasures: true,
-    })
-  ).toMatchSnapshot();
-
-  expect(
-    shallowRender({
-      componentMeasures,
-      showMeasures: false,
-    })
-      .find('.source-viewer-header-measure')
-      .exists()
-  ).toBe(false);
-});
-
-function shallowRender(props: Partial<SourceViewerHeader['props']> = {}) {
-  return shallow(
-    <SourceViewerHeader
-      branchLike={mockMainBranch()}
-      openComponent={jest.fn()}
-      sourceViewerFile={mockSourceViewerFile()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap b/server/sonar-web/src/main/js/components/SourceViewer/__tests__/__snapshots__/SourceViewerHeader-test.tsx.snap
deleted file mode 100644 (file)
index abfac0e..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly for a regular file 1`] = `
-<div
-  className="source-viewer-header display-flex-center"
->
-  <div
-    className="flex-1 little-spacer-top"
-  >
-    <div
-      className="component-name"
-    >
-      <div
-        className="component-name-parent"
-      >
-        <a
-          className="link-no-underline"
-          href="/dashboard?id=project"
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            MyProject
-          </span>
-        </a>
-      </div>
-      <div
-        className="component-name-path"
-      >
-        <QualifierIcon
-          qualifier="FIL"
-        />
-         
-        <span>
-          foo/
-        </span>
-        <span
-          className="component-name-file"
-        >
-          bar.ts
-        </span>
-        <span
-          className="nudged-up spacer-left"
-        >
-          <ClipboardIconButton
-            aria-label="component_viewer.copy_path_to_clipboard"
-            className="button-link link-no-underline"
-            copyValue="foo/bar.ts"
-          />
-        </span>
-      </div>
-    </div>
-  </div>
-  <Dropdown
-    className="source-viewer-header-actions flex-0"
-    overlay={
-      <ul
-        className="menu"
-      >
-        <li>
-          <a
-            className="js-measures"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.show_details
-          </a>
-        </li>
-        <li>
-          <ForwardRef(Link)
-            className="js-new-window"
-            rel="noopener noreferrer"
-            target="_blank"
-            to={
-              {
-                "pathname": "/code",
-                "search": "?id=project&selected=project%3Afoo%2Fbar.ts",
-              }
-            }
-          >
-            component_viewer.new_window
-          </ForwardRef(Link)>
-        </li>
-        <li>
-          <a
-            className="js-workspace"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.open_in_workspace
-          </a>
-        </li>
-        <li>
-          <a
-            className="js-raw-source"
-            href="/api/sources/raw?key=project%3Afoo%2Fbar.ts"
-            rel="noopener noreferrer"
-            target="_blank"
-          >
-            component_viewer.show_raw_source
-          </a>
-        </li>
-      </ul>
-    }
-    overlayPlacement="bottom-right"
-  >
-    <ButtonIcon
-      aria-label="component_viewer.action_menu"
-      className="js-actions"
-    >
-      <ListIcon />
-    </ButtonIcon>
-  </Dropdown>
-</div>
-`;
-
-exports[`should render correctly for a unit test 1`] = `
-<div
-  className="source-viewer-header display-flex-center"
->
-  <div
-    className="flex-1 little-spacer-top"
-  >
-    <div
-      className="component-name"
-    >
-      <div
-        className="component-name-parent"
-      >
-        <a
-          className="link-no-underline"
-          href="/dashboard?id=my-project"
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            MyProject
-          </span>
-        </a>
-      </div>
-      <div
-        className="component-name-path"
-      >
-        <QualifierIcon
-          qualifier="UTS"
-        />
-         
-        <span>
-          foo/
-        </span>
-        <span
-          className="component-name-file"
-        >
-          bar.ts
-        </span>
-        <span
-          className="nudged-up spacer-left"
-        >
-          <ClipboardIconButton
-            aria-label="component_viewer.copy_path_to_clipboard"
-            className="button-link link-no-underline"
-            copyValue="foo/bar.ts"
-          />
-        </span>
-      </div>
-    </div>
-  </div>
-  <div
-    className="display-flex-center"
-  >
-    <div
-      className="source-viewer-header-measure"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        metric.tests.name
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        12
-      </span>
-    </div>
-  </div>
-  <Dropdown
-    className="source-viewer-header-actions flex-0"
-    overlay={
-      <ul
-        className="menu"
-      >
-        <li>
-          <a
-            className="js-measures"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.show_details
-          </a>
-        </li>
-        <li>
-          <ForwardRef(Link)
-            className="js-new-window"
-            rel="noopener noreferrer"
-            target="_blank"
-            to={
-              {
-                "pathname": "/code",
-                "search": "?id=my-project&selected=my-project%3Afoo%2Fbar.ts",
-              }
-            }
-          >
-            component_viewer.new_window
-          </ForwardRef(Link)>
-        </li>
-        <li>
-          <a
-            className="js-workspace"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.open_in_workspace
-          </a>
-        </li>
-        <li>
-          <a
-            className="js-raw-source"
-            href="/api/sources/raw?key=my-project%3Afoo%2Fbar.ts"
-            rel="noopener noreferrer"
-            target="_blank"
-          >
-            component_viewer.show_raw_source
-          </a>
-        </li>
-      </ul>
-    }
-    overlayPlacement="bottom-right"
-  >
-    <ButtonIcon
-      aria-label="component_viewer.action_menu"
-      className="js-actions"
-    >
-      <ListIcon />
-    </ButtonIcon>
-  </Dropdown>
-</div>
-`;
-
-exports[`should render correctly if issue details are passed 1`] = `
-<div
-  className="source-viewer-header display-flex-center"
->
-  <div
-    className="flex-1 little-spacer-top"
-  >
-    <div
-      className="component-name"
-    >
-      <div
-        className="component-name-parent"
-      >
-        <a
-          className="link-no-underline"
-          href="/dashboard?id=project"
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            MyProject
-          </span>
-        </a>
-      </div>
-      <div
-        className="component-name-path"
-      >
-        <QualifierIcon
-          qualifier="FIL"
-        />
-         
-        <span>
-          foo/
-        </span>
-        <span
-          className="component-name-file"
-        >
-          bar.ts
-        </span>
-        <span
-          className="nudged-up spacer-left"
-        >
-          <ClipboardIconButton
-            aria-label="component_viewer.copy_path_to_clipboard"
-            className="button-link link-no-underline"
-            copyValue="foo/bar.ts"
-          />
-        </span>
-      </div>
-    </div>
-  </div>
-  <div
-    className="display-flex-center"
-  >
-    <div
-      className="source-viewer-header-measure"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        metric.lines.name
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        56
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        metric.coverage.name
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        85.2%
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        duplications
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        1.0%
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure-separator"
-    />
-    <div
-      className="source-viewer-header-measure"
-      key="BUG"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        issue.type.BUG
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "hash": "",
-              "pathname": "/project/issues",
-              "search": "?files=foo%2Fbar.ts&resolved=false&types=BUG&id=project",
-            }
-          }
-        >
-          0
-        </ForwardRef(Link)>
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure"
-      key="VULNERABILITY"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        issue.type.VULNERABILITY
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "hash": "",
-              "pathname": "/project/issues",
-              "search": "?files=foo%2Fbar.ts&resolved=false&types=VULNERABILITY&id=project",
-            }
-          }
-        >
-          2
-        </ForwardRef(Link)>
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure"
-      key="CODE_SMELL"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        issue.type.CODE_SMELL
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "hash": "",
-              "pathname": "/project/issues",
-              "search": "?files=foo%2Fbar.ts&resolved=false&types=CODE_SMELL&id=project",
-            }
-          }
-        >
-          1
-        </ForwardRef(Link)>
-      </span>
-    </div>
-    <div
-      className="source-viewer-header-measure"
-      key="SECURITY_HOTSPOT"
-    >
-      <span
-        className="source-viewer-header-measure-label"
-      >
-        issue.type.SECURITY_HOTSPOT
-      </span>
-      <span
-        className="source-viewer-header-measure-value"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "hash": "",
-              "pathname": "/security_hotspots",
-              "search": "?id=project&files=foo%2Fbar.ts",
-            }
-          }
-        >
-          2
-        </ForwardRef(Link)>
-      </span>
-    </div>
-  </div>
-  <Dropdown
-    className="source-viewer-header-actions flex-0"
-    overlay={
-      <ul
-        className="menu"
-      >
-        <li>
-          <a
-            className="js-measures"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.show_details
-          </a>
-        </li>
-        <li>
-          <ForwardRef(Link)
-            className="js-new-window"
-            rel="noopener noreferrer"
-            target="_blank"
-            to={
-              {
-                "pathname": "/code",
-                "search": "?id=project&selected=project%3Afoo%2Fbar.ts",
-              }
-            }
-          >
-            component_viewer.new_window
-          </ForwardRef(Link)>
-        </li>
-        <li>
-          <a
-            className="js-workspace"
-            href="#"
-            onClick={[Function]}
-          >
-            component_viewer.open_in_workspace
-          </a>
-        </li>
-        <li>
-          <a
-            className="js-raw-source"
-            href="/api/sources/raw?key=project%3Afoo%2Fbar.ts"
-            rel="noopener noreferrer"
-            target="_blank"
-          >
-            component_viewer.show_raw_source
-          </a>
-        </li>
-      </ul>
-    }
-    overlayPlacement="bottom-right"
-  >
-    <ButtonIcon
-      aria-label="component_viewer.action_menu"
-      className="js-actions"
-    >
-      <ListIcon />
-    </ButtonIcon>
-  </Dropdown>
-</div>
-`;
index 63cef19ca70805a41135a9788d8fae7505697e05..5915806fda5b7643d900604e975e15f179e02bc8 100644 (file)
   border-collapse: collapse;
 }
 
-.source-viewer-header {
-  position: relative;
-  padding: 2px 10px 4px;
-  border-bottom: 1px solid var(--barBorderColor);
-  background-color: var(--barBackgroundColor);
-}
-
-.source-viewer-header-measure {
-  vertical-align: middle;
-  font-size: var(--baseFontSize);
-}
-
-.source-viewer-header-measure .rating {
-  font-size: 18px;
-}
-
-.source-viewer-header-measure-separator {
-  margin: 0 calc(3 * var(--gridSize));
-  height: 30px;
-  border-right: 1px solid var(--gray80);
-}
-
-.source-viewer-header-measure + .source-viewer-header-measure {
-  margin-left: calc(3 * var(--gridSize));
-}
-
-.source-viewer-header-measure-label {
-  display: block;
-  line-height: var(--smallFontSize);
-  color: var(--secondFontColor);
-  font-size: var(--smallFontSize);
-}
-
-.source-viewer-header-measure-value {
-  display: block;
-  margin-top: 2px;
-  line-height: 18px;
-  color: var(--baseFontColor);
-  font-size: var(--bigFontSize);
-}
-
-.source-viewer-header-actions {
-  display: block;
-  margin-left: calc(3 * var(--gridSize));
-  padding: var(--gridSize) calc(var(--gridSize) / 2);
-}
-
-.source-viewer-header-actions svg {
-  margin-top: 2px;
-}
-
-.source-viewer-header-more-actions {
-  position: absolute;
-  z-index: var(--dropdownMenuZIndex);
-  right: 0;
-  top: 100%;
-  padding: 10px;
-  border: 1px solid var(--barBorderColor);
-  border-right: none;
-  background-color: #fff;
-  line-height: 1.8;
-}
-
 .source-viewer-code {
   overflow-x: auto;
 }