]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20500 Background, layout and other fixes for rules page
authorRevanshu Paliwal <revanshu.paliwal@sonarsource.com>
Mon, 2 Oct 2023 15:39:36 +0000 (17:39 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 5 Oct 2023 20:02:48 +0000 (20:02 +0000)
server/sonar-web/src/main/js/app/components/GlobalContainer.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/BulkChange.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesApp.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
server/sonar-web/src/main/js/components/common/PageCounter.tsx
server/sonar-web/src/main/js/components/common/__tests__/__snapshots__/PageCounter-test.tsx.snap
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 375edebed5015e85357deec8fb4c67e6ce123afe..d099db095adae68c04c8eb81dea644c196c1dddb 100644 (file)
@@ -51,6 +51,7 @@ const TEMP_PAGELIST_WITH_NEW_BACKGROUND = [
   '/project/information',
   '/web_api_v2',
   '/quality_gates',
+  '/coding_rules',
 ];
 
 const TEMP_PAGELIST_WITH_NEW_BACKGROUND_WHITE = ['/tutorials', '/projects/create'];
index bf8ff0c4caa06221e6aa0bd00dc2da8b1e7c76e7..0dde26c5ffbeefc7b7ffbc155bbb5a84e0da506d 100644 (file)
@@ -108,7 +108,8 @@ export default class BulkChange extends React.PureComponent<Props, State> {
 
               {allowActivateOnProfile && profile && (
                 <ItemButton onClick={this.handleActivateInProfileClick}>
-                  {translate('coding_rules.activate_in')} <strong>{profile.name}</strong>
+                  {translate('coding_rules.activate_in')}{' '}
+                  <strong className="sw-ml-1">{profile.name}</strong>
                 </ItemButton>
               )}
 
@@ -118,7 +119,8 @@ export default class BulkChange extends React.PureComponent<Props, State> {
 
               {allowDeactivateOnProfile && profile && (
                 <ItemButton onClick={this.handleDeactivateInProfileClick}>
-                  {translate('coding_rules.deactivate_in')} <strong>{profile.name}</strong>
+                  {translate('coding_rules.deactivate_in')}{' '}
+                  <strong className="sw-ml-1">{profile.name}</strong>
                 </ItemButton>
               )}
             </>
index ad4b71ea1510c953ebfeccea44923eb81aec13d3..c787c6dddbbb91dcc76bbae80f4e1cd95d8ad86d 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 { InputSearch } from 'design-system';
+import styled from '@emotion/styled';
+import {
+  InputSearch,
+  LAYOUT_FOOTER_HEIGHT,
+  LAYOUT_GLOBAL_NAV_HEIGHT,
+  LargeCenteredLayout,
+  PageContentFontWrapper,
+  themeBorder,
+  themeColor,
+} from 'design-system';
 import { keyBy } from 'lodash';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
@@ -26,11 +35,9 @@ import { getRulesApp, searchRules } from '../../../api/rules';
 import { getValue } from '../../../api/settings';
 import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
 import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget';
-import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
 import ListFooter from '../../../components/controls/ListFooter';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import BackIcon from '../../../components/icons/BackIcon';
 import '../../../components/search-navigator.css';
 import { isDatePicker, isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
 import { KeyboardKeys } from '../../../helpers/keycodes';
@@ -97,6 +104,8 @@ interface State {
   rules: Rule[];
 }
 
+const RULE_LIST_HEADER_HEIGHT = 68;
+
 export class CodingRulesApp extends React.PureComponent<Props, State> {
   mounted = false;
 
@@ -585,119 +594,117 @@ export class CodingRulesApp extends React.PureComponent<Props, State> {
             <meta content="noindex" name="robots" />
           </Helmet>
         )}
-        <div className="layout-page" id="coding-rules-page">
-          <ScreenPositionHelper className="layout-page-side-outer">
-            {({ top }) => (
-              <nav aria-label={translate('filters')} className="layout-page-side" style={{ top }}>
-                <div className="layout-page-side-inner">
-                  <div className="layout-page-filters">
-                    <A11ySkipTarget
-                      anchor="rules_filters"
-                      label={translate('coding_rules.skip_to_filters')}
-                      weight={10}
-                    />
-                    <FiltersHeader displayReset={this.isFiltered()} onReset={this.handleReset} />
-                    <FacetsList
-                      facets={this.state.facets}
-                      onFacetToggle={this.handleFacetToggle}
-                      onFilterChange={this.handleFilterChange}
-                      openFacets={this.state.openFacets}
-                      query={query}
+        <LargeCenteredLayout id="coding-rules-page">
+          <PageContentFontWrapper className="sw-body-sm">
+            <div className="sw-grid sw-gap-x-12 sw-gap-y-6 sw-grid-cols-12 sw-w-full">
+              <StyledContentWrapper
+                as="nav"
+                className="sw-col-span-3 sw-p-4 sw-overflow-y-auto"
+                aria-label={translate('filters')}
+                style={{
+                  height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px)`,
+                }}
+              >
+                <div>
+                  <A11ySkipTarget
+                    anchor="rules_filters"
+                    label={translate('coding_rules.skip_to_filters')}
+                    weight={10}
+                  />
+                  <FiltersHeader displayReset={this.isFiltered()} onReset={this.handleReset} />
+                  <FacetsList
+                    facets={this.state.facets}
+                    onFacetToggle={this.handleFacetToggle}
+                    onFilterChange={this.handleFilterChange}
+                    openFacets={this.state.openFacets}
+                    query={query}
+                    referencedProfiles={this.state.referencedProfiles}
+                    referencedRepositories={this.state.referencedRepositories}
+                    selectedProfile={this.getSelectedProfile()}
+                  />
+                </div>
+              </StyledContentWrapper>
+
+              <main className="sw-col-span-9">
+                {!openRule && (
+                  <div>
+                    <A11ySkipTarget anchor="rules_main" />
+
+                    <div className="sw-flex sw-justify-between sw-py-4">
+                      <InputSearch
+                        className="sw-min-w-abs-250 sw-max-w-abs-350 sw-mr-4"
+                        id="coding-rules-search"
+                        maxLength={MAX_SEARCH_LENGTH}
+                        minLength={2}
+                        onChange={this.handleSearch}
+                        placeholder={translate('search.search_for_rules')}
+                        value={query.searchQuery ?? ''}
+                        size="auto"
+                      />
+                      {this.renderBulkButton()}
+                      {!usingPermalink && (
+                        <PageActions paging={paging} selectedIndex={selectedIndex} />
+                      )}
+                    </div>
+                  </div>
+                )}
+
+                <div
+                  className="sw-overflow-y-auto"
+                  style={{
+                    height: `calc(100vh - ${LAYOUT_GLOBAL_NAV_HEIGHT + LAYOUT_FOOTER_HEIGHT}px - ${
+                      !openRule ? RULE_LIST_HEADER_HEIGHT : 0
+                    }px)`,
+                  }}
+                >
+                  {openRule ? (
+                    <RuleDetails
+                      allowCustomRules
+                      canWrite={this.state.canWrite}
+                      canDeactivateInherited={this.state.canDeactivateInherited}
+                      onActivate={this.handleRuleActivate}
+                      onDeactivate={this.handleRuleDeactivate}
+                      onDelete={this.handleRuleDelete}
                       referencedProfiles={this.state.referencedProfiles}
                       referencedRepositories={this.state.referencedRepositories}
+                      ruleKey={openRule.key}
                       selectedProfile={this.getSelectedProfile()}
                     />
-                  </div>
-                </div>
-              </nav>
-            )}
-          </ScreenPositionHelper>
-
-          <main className="layout-page-main">
-            <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">
-                  <A11ySkipTarget anchor="rules_main" />
-                  <div className="display-flex-space-between">
-                    <InputSearch
-                      className="sw-min-w-abs-250 sw-max-w-abs-350 sw-mr-4"
-                      id="coding-rules-search"
-                      maxLength={MAX_SEARCH_LENGTH}
-                      minLength={2}
-                      onChange={this.handleSearch}
-                      placeholder={translate('search.search_for_rules')}
-                      value={query.searchQuery ?? ''}
-                      size="auto"
-                    />
-
-                    {openRule ? (
-                      <a
-                        className="js-back display-inline-flex-center link-no-underline"
-                        href="#"
-                        onClick={this.handleBack}
-                      >
-                        <BackIcon className="spacer-right" />
-                        {usingPermalink
-                          ? translate('coding_rules.see_all')
-                          : translate('coding_rules.return_to_list')}
-                      </a>
-                    ) : (
-                      this.renderBulkButton()
-                    )}
-                    {!usingPermalink && (
-                      <PageActions paging={paging} selectedIndex={selectedIndex} />
-                    )}
-                  </div>
-                </div>
-              </div>
-            </div>
-
-            <div className="layout-page-main-inner">
-              {openRule ? (
-                <RuleDetails
-                  allowCustomRules
-                  canWrite={this.state.canWrite}
-                  canDeactivateInherited={this.state.canDeactivateInherited}
-                  onActivate={this.handleRuleActivate}
-                  onDeactivate={this.handleRuleDeactivate}
-                  onDelete={this.handleRuleDelete}
-                  referencedProfiles={this.state.referencedProfiles}
-                  referencedRepositories={this.state.referencedRepositories}
-                  ruleKey={openRule.key}
-                  selectedProfile={this.getSelectedProfile()}
-                />
-              ) : (
-                <>
-                  <ul aria-label={translate('list_of_rules')}>
-                    {rules.map((rule) => (
-                      <RuleListItem
-                        activation={this.getRuleActivation(rule.key)}
-                        isLoggedIn={isLoggedIn(this.props.currentUser)}
-                        canDeactivateInherited={this.state.canDeactivateInherited}
-                        key={rule.key}
-                        onActivate={this.handleRuleActivate}
-                        onDeactivate={this.handleRuleDeactivate}
-                        onOpen={this.handleRuleOpen}
-                        rule={rule}
-                        selected={rule.key === selected}
-                        selectedProfile={this.getSelectedProfile()}
-                      />
-                    ))}
-                  </ul>
-                  {paging !== undefined && (
-                    <ListFooter
-                      count={rules.length}
-                      loadMore={this.fetchMoreRules}
-                      ready={!this.state.loading}
-                      total={paging.total}
-                      useMIUIButtons
-                    />
+                  ) : (
+                    <>
+                      <ul aria-label={translate('list_of_rules')}>
+                        {rules.map((rule) => (
+                          <RuleListItem
+                            activation={this.getRuleActivation(rule.key)}
+                            isLoggedIn={isLoggedIn(this.props.currentUser)}
+                            canDeactivateInherited={this.state.canDeactivateInherited}
+                            key={rule.key}
+                            onActivate={this.handleRuleActivate}
+                            onDeactivate={this.handleRuleDeactivate}
+                            onOpen={this.handleRuleOpen}
+                            rule={rule}
+                            selected={rule.key === selected}
+                            selectedProfile={this.getSelectedProfile()}
+                          />
+                        ))}
+                      </ul>
+                      {paging !== undefined && (
+                        <ListFooter
+                          className="sw-mb-4"
+                          count={rules.length}
+                          loadMore={this.fetchMoreRules}
+                          ready={!this.state.loading}
+                          total={paging.total}
+                          useMIUIButtons
+                        />
+                      )}
+                    </>
                   )}
-                </>
-              )}
+                </div>
+              </main>
             </div>
-          </main>
-        </div>
+          </PageContentFontWrapper>
+        </LargeCenteredLayout>
       </>
     );
   }
@@ -727,3 +734,11 @@ function parseFacets(rawFacets: { property: string; values: { count: number; val
 }
 
 export default withRouter(withCurrentUserContext(CodingRulesApp));
+
+const StyledContentWrapper = styled.div`
+  box-sizing: border-box;
+  background-color: ${themeColor('filterbar')};
+  border: ${themeBorder('default', 'filterbarBorder')};
+  border-bottom: none;
+  overflow-x: hidden;
+`;
index cdf4b644195b3b37365b526f401357e2d4bf79d4..49ca07211b6cb6879392c84c82bda14ce8b699a2 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 {
   ButtonSecondary,
   DangerButtonSecondary,
   HelperHintIcon,
   SubHeadingHighlight,
+  themeBorder,
+  themeColor,
 } from 'design-system';
 import * as React from 'react';
 import { Profile } from '../../../api/quality-profiles';
@@ -168,7 +171,7 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
     const isEditable = canWrite && !!this.props.allowCustomRules && isCustom;
 
     return (
-      <div className="coding-rule-details">
+      <StyledRuleDetails className="it__coding-rule-details sw-p-6 sw-mt-6">
         <Spinner loading={this.state.loading}>
           <RuleDetailsMeta
             canWrite={canWrite}
@@ -268,7 +271,15 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
             <DateFormatter date={ruleDetails.createdAt} />
           </div>
         </Spinner>
-      </div>
+      </StyledRuleDetails>
     );
   }
 }
+
+const StyledRuleDetails = styled.div`
+  box-sizing: border-box;
+  border-radius: 4px;
+  background-color: ${themeColor('filterbar')};
+  border: ${themeBorder('default', 'filterbarBorder')};
+  overflow-x: hidden;
+`;
index 753585d33829690bc94f2c6d978e75702b84cb31..c38cf54d036786949755f2ed4d7c1f8b55373365 100644 (file)
@@ -96,7 +96,7 @@ export default class RuleListItem extends React.PureComponent<Props> {
     }
 
     return (
-      <div className="sw-mr-2">
+      <div className="sw-mr-2 sw-shrink-0">
         <SeverityIcon severity={activation.severity} />
         {selectedProfile && selectedProfile.parentName && (
           <>
@@ -201,7 +201,7 @@ export default class RuleListItem extends React.PureComponent<Props> {
     return (
       <ListItemStyled
         selected={selected}
-        className="it__coding-rule sw-p-3 sw-mb-4 sw-rounded-1"
+        className="it__coding-rule sw-p-3 sw-mb-4 sw-rounded-1 sw-bg-white"
         aria-current={selected}
         data-rule={rule.key}
       >
index 8ad2fa057e5101a8c38285a3024bae6d1244b07e..8ef45129e65cba2e4ef5bdd61b1a7d162d9ffffa 100644 (file)
@@ -31,7 +31,7 @@ export interface PageCounterProps {
 export default function PageCounter({ className, current, label, total }: PageCounterProps) {
   return (
     <div className={className}>
-      <strong className="sw-ml-1">
+      <strong className="sw-mr-1">
         {current !== undefined && formatMeasure(current + 1, MetricType.Integer) + ' / '}
         <span className="it__page-counter-total">{formatMeasure(total, MetricType.Integer)}</span>
       </strong>
index 2ac7d76bea858c490ccf6c973270571bcd811bf5..a36f29997fda3d7b1cea12e7d23c7cae60cbb07f 100644 (file)
@@ -3,7 +3,7 @@
 exports[`should render correctly 1`] = `
 <div>
   <strong
-    className="sw-ml-1"
+    className="sw-mr-1"
   >
     124 / 
     <span
index 56f66c35befa304c58802356cd322a98842ab26a..a83a184f419acc06080e08c83d9f1eaad6388b38 100644 (file)
@@ -2305,7 +2305,7 @@ coding_rules._rules=rules
 coding_rules.show_template=Show Template
 coding_rules.skip_to_filters=Skip to rules filters
 coding_rules.to_select_rules=Select rules
-coding_rules.to_navigate=Navtigate to rule
+coding_rules.to_navigate=Navigate to rule
 coding_rules.type.tooltip.CODE_SMELL=Code Smell Detection Rule
 coding_rules.type.tooltip.BUG=Bug Detection Rule
 coding_rules.type.tooltip.VULNERABILITY=Vulnerability Detection Rule