]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19236 Add base layout for Hotspots page
authorstanislavh <stanislav.honcharov@sonarsource.com>
Tue, 9 May 2023 15:29:59 +0000 (17:29 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 24 May 2023 20:03:13 +0000 (20:03 +0000)
server/sonar-web/src/main/js/@types/emotion.d.ts [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx

diff --git a/server/sonar-web/src/main/js/@types/emotion.d.ts b/server/sonar-web/src/main/js/@types/emotion.d.ts
new file mode 100644 (file)
index 0000000..0a01440
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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 '@emotion/react';
+import { Theme as SQTheme } from 'design-system';
+
+declare module '@emotion/react' {
+  export interface Theme extends SQTheme {}
+}
index e9bf7fb47617d7e22a8dd013210ed71c9d52f1b4..9468d011da431e7521212b52bcb90c03788c44c6 100644 (file)
@@ -38,7 +38,7 @@ import GlobalNav from './nav/global/GlobalNav';
 import PromotionNotification from './promotion-notification/PromotionNotification';
 import UpdateNotification from './update-notification/UpdateNotification';
 
-const TEMP_PAGELIST_WITH_NEW_BACKGROUND = ['/dashboard'];
+const TEMP_PAGELIST_WITH_NEW_BACKGROUND = ['/dashboard', '/security_hotspots'];
 
 export default function GlobalContainer() {
   // it is important to pass `location` down to `GlobalNav` to trigger render on url change
index 580f7592375f42707c29d9a6684d6521f2b03475..c3ffa80624298939d42bca3f653698cf12a67ee5 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 { useTheme } from '@emotion/react';
+import styled from '@emotion/styled';
+import {
+  LargeCenteredLayout,
+  PageContentFontWrapper,
+  themeBorder,
+  themeColor,
+} from 'design-system';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import A11ySkipTarget from '../../components/a11y/A11ySkipTarget';
-import ScreenPositionHelper from '../../components/common/ScreenPositionHelper';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import DeferredSpinner from '../../components/ui/DeferredSpinner';
 import { isBranch } from '../../helpers/branch-like';
 import { translate } from '../../helpers/l10n';
 import { BranchLike } from '../../types/branch-like';
+import { MetricKey } from '../../types/metrics';
 import { SecurityStandard, Standards } from '../../types/security';
 import { HotspotFilters, HotspotStatusFilter, RawHotspot } from '../../types/security-hotspots';
 import { Component, StandardSecurityCategories } from '../../types/types';
@@ -86,7 +94,7 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
     standards,
   } = props;
 
-  const scrollableRef = React.useRef(null);
+  const theme = useTheme();
 
   React.useEffect(() => {
     if (!selectedHotspot) {
@@ -102,7 +110,7 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
   }, [selectedHotspot]);
 
   return (
-    <div id="security_hotspots">
+    <>
       <Suggestions suggestions="security_hotspots" />
       <Helmet title={translate('hotspots.page')} />
       <A11ySkipTarget anchor="security_hotspots_main" />
@@ -116,32 +124,28 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
         onBranch={isBranch(branchLike)}
         onChangeFilters={props.onChangeFilters}
       />
+      <LargeCenteredLayout id={MetricKey.security_hotspots}>
+        <PageContentFontWrapper>
+          <div className="sw-grid sw-grid-cols-12 sw-w-full">
+            <DeferredSpinner className="sw-mt-3" loading={loading} />
 
-      {loading && (
-        <div className="layout-page">
-          <div className="layout-page-side-inner">
-            <DeferredSpinner className="big-spacer-top" />
-          </div>
-        </div>
-      )}
-
-      {!loading &&
-        (hotspots.length === 0 || !selectedHotspot ? (
-          <EmptyHotspotsPage
-            filtered={
-              filters.assignedToMe ||
-              (isBranch(branchLike) && filters.inNewCodePeriod) ||
-              filters.status !== HotspotStatusFilter.TO_REVIEW
-            }
-            filterByFile={Boolean(filterByFile)}
-            isStaticListOfHotspots={isStaticListOfHotspots}
-          />
-        ) : (
-          <div className="layout-page">
-            <ScreenPositionHelper className="layout-page-side-outer">
-              {({ top }) => (
-                <div className="layout-page-side" ref={scrollableRef} style={{ top }}>
-                  <div className="layout-page-side-inner">
+            {!loading &&
+              (hotspots.length === 0 || !selectedHotspot ? (
+                <EmptyHotspotsPage
+                  filtered={
+                    filters.assignedToMe ||
+                    (isBranch(branchLike) && filters.inNewCodePeriod) ||
+                    filters.status !== HotspotStatusFilter.TO_REVIEW
+                  }
+                  filterByFile={Boolean(filterByFile)}
+                  isStaticListOfHotspots={isStaticListOfHotspots}
+                />
+              ) : (
+                <>
+                  <FilterbarStyled
+                    theme={theme}
+                    className="sw-col-span-4 sw-rounded-t-1 sw-mt-0 sw-z-filterbar"
+                  >
                     {filterByCategory || filterByCWE || filterByFile ? (
                       <HotspotSimpleList
                         filterByCategory={filterByCategory}
@@ -172,24 +176,40 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
                         statusFilter={filters.status}
                       />
                     )}
-                  </div>
-                </div>
-              )}
-            </ScreenPositionHelper>
+                  </FilterbarStyled>
 
-            <main className="layout-page-main">
-              <HotspotViewer
-                component={component}
-                hotspotKey={selectedHotspot.key}
-                hotspotsReviewedMeasure={hotspotsReviewedMeasure}
-                onSwitchStatusFilter={props.onSwitchStatusFilter}
-                onUpdateHotspot={props.onUpdateHotspot}
-                onLocationClick={props.onLocationClick}
-                selectedHotspotLocation={selectedHotspotLocation}
-              />
-            </main>
+                  <main className="sw-col-span-8">
+                    <HotspotViewer
+                      component={component}
+                      hotspotKey={selectedHotspot.key}
+                      hotspotsReviewedMeasure={hotspotsReviewedMeasure}
+                      onSwitchStatusFilter={props.onSwitchStatusFilter}
+                      onUpdateHotspot={props.onUpdateHotspot}
+                      onLocationClick={props.onLocationClick}
+                      selectedHotspotLocation={selectedHotspotLocation}
+                    />
+                  </main>
+                </>
+              ))}
           </div>
-        ))}
-    </div>
+        </PageContentFontWrapper>
+      </LargeCenteredLayout>
+    </>
   );
 }
+
+const FilterbarStyled = styled.div(
+  (props) => `
+position: sticky;
+box-sizing: border-box;
+overflow-x: hidden;
+overflow-y: auto;
+background-color: ${themeColor('filterbar')(props)};
+border-right: ${themeBorder('default', 'filterbarBorder')(props)};
+// ToDo set proper hegiht
+height: calc(100vh - ${'100px'});
+
+&.border-left {
+  border-left: ${themeBorder('default', 'filterbarBorder')(props)};
+}`
+);