]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20366 Migrate profile changelog page to MIUI
author7PH <benjamin.raymond@sonarsource.com>
Tue, 3 Oct 2023 09:15:37 +0000 (11:15 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 4 Oct 2023 20:03:19 +0000 (20:03 +0000)
server/sonar-web/design-system/src/components/input/DateRangePicker.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/Changelog.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogEmpty.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangesList.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ParameterChange.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileHeader.tsx
server/sonar-web/src/main/js/apps/quality-profiles/styles.css
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 393946732ea2dfc857d3c472a5653755af2e576f..8c917da71b2724a929074ee6f0dc25039afd4fe6 100644 (file)
@@ -21,6 +21,7 @@ import classNames from 'classnames';
 import { max, min } from 'date-fns';
 import * as React from 'react';
 import { PopupZLevel } from '../../helpers';
+import { InputSizeKeys } from '../../types';
 import { LightLabel } from '../Text';
 import { DatePicker } from './DatePicker';
 
@@ -34,6 +35,7 @@ interface Props {
   className?: string;
   clearButtonLabel: string;
   fromLabel: string;
+  inputSize?: InputSizeKeys;
   maxDate?: Date;
   minDate?: Date;
   onChange: (date: DateRange) => void;
@@ -75,6 +77,7 @@ export class DateRangePicker extends React.PureComponent<Props> {
       alignEndDateCalandarRight,
       clearButtonLabel,
       fromLabel,
+      inputSize = 'full',
       minDate,
       maxDate,
       separatorText,
@@ -95,7 +98,7 @@ export class DateRangePicker extends React.PureComponent<Props> {
           minDate={minDate}
           onChange={this.handleFromChange}
           placeholder={fromLabel}
-          size="full"
+          size={inputSize}
           value={this.from}
           valueFormatter={valueFormatter}
           zLevel={zLevel}
@@ -115,7 +118,7 @@ export class DateRangePicker extends React.PureComponent<Props> {
           minDate={minDate && this.from ? max([minDate, this.from]) : minDate ?? this.from}
           onChange={this.handleToChange}
           placeholder={toLabel}
-          size="full"
+          size={inputSize}
           value={this.to}
           valueFormatter={valueFormatter}
           zLevel={zLevel}
index f5c9c7fac3d1045f349d35bdfcd467599f464719..28ecbf030297fec2f2fce933c39dafd1645a305f 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { isSameMinute } from 'date-fns';
+import { ContentCell, Link, Note, Table, TableRow, TableRowInteractive } from 'design-system';
 import { sortBy } from 'lodash';
 import * as React from 'react';
-import Link from '../../../components/common/Link';
+import { useIntl } from 'react-intl';
 import DateTimeFormatter from '../../../components/intl/DateTimeFormatter';
 import { parseDate } from '../../../helpers/dates';
-import { translate } from '../../../helpers/l10n';
 import { getRulesUrl } from '../../../helpers/urls';
 import { ProfileChangelogEvent } from '../types';
 import ChangesList from './ChangesList';
@@ -33,6 +33,8 @@ interface Props {
 }
 
 export default function Changelog(props: Props) {
+  const intl = useIntl();
+
   let isEvenRow = false;
   const sortedRows = sortBy(
     props.events,
@@ -54,46 +56,44 @@ export default function Changelog(props: Props) {
       isEvenRow = !isEvenRow;
     }
 
-    const className = 'js-profile-changelog-event ' + (isEvenRow ? 'even' : 'odd');
-
     return (
-      <tr className={className} key={index}>
-        <td className="thin nowrap">{!isBulkChange && <DateTimeFormatter date={event.date} />}</td>
+      <TableRowInteractive key={`${event.date}-${event.ruleKey}`}>
+        <ContentCell className="sw-whitespace-nowrap">
+          {!isBulkChange && <DateTimeFormatter date={event.date} />}
+        </ContentCell>
 
-        <td className="thin nowrap">
-          {!isBulkChange &&
-            (event.authorName ? (
-              <span>{event.authorName}</span>
-            ) : (
-              <span className="note">System</span>
-            ))}
-        </td>
+        <ContentCell className="sw-whitespace-nowrap sw-max-w-[120px]">
+          {!isBulkChange && (event.authorName ? event.authorName : <Note>System</Note>)}
+        </ContentCell>
 
-        <td className="thin nowrap">
-          {!isBulkChange && translate('quality_profiles.changelog', event.action)}
-        </td>
+        <ContentCell className="sw-whitespace-nowrap">
+          {!isBulkChange &&
+            intl.formatMessage({ id: `quality_profiles.changelog.${event.action}` })}
+        </ContentCell>
 
-        <td className="quality-profile-changelog-rule-cell">
+        <ContentCell>
           <Link to={getRulesUrl({ rule_key: event.ruleKey })}>{event.ruleName}</Link>
-        </td>
+        </ContentCell>
 
-        <td>{event.params && <ChangesList changes={event.params} />}</td>
-      </tr>
+        <ContentCell>{event.params && <ChangesList changes={event.params} />}</ContentCell>
+      </TableRowInteractive>
     );
   });
 
   return (
-    <table className="data zebra-hover">
-      <thead>
-        <tr>
-          <th className="thin nowrap">{translate('date')}</th>
-          <th className="thin nowrap">{translate('user')}</th>
-          <th className="thin nowrap">{translate('action')}</th>
-          <th>{translate('rule')}</th>
-          <th>{translate('parameters')}</th>
-        </tr>
-      </thead>
-      <tbody>{rows}</tbody>
-    </table>
+    <Table
+      columnCount={5}
+      header={
+        <TableRow>
+          <ContentCell>{intl.formatMessage({ id: 'date' })}</ContentCell>
+          <ContentCell>{intl.formatMessage({ id: 'user' })}</ContentCell>
+          <ContentCell>{intl.formatMessage({ id: 'action' })}</ContentCell>
+          <ContentCell>{intl.formatMessage({ id: 'rule' })}</ContentCell>
+          <ContentCell>{intl.formatMessage({ id: 'updates' })}</ContentCell>
+        </TableRow>
+      }
+    >
+      {rows}
+    </Table>
   );
 }
index 4d0507c2dea80ef444f9e35f4387379c391af52a..b78462000cca55c738236143a45f926ab58725e0 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 { ButtonSecondary, Spinner } from 'design-system';
 import * as React from 'react';
 import { ChangelogResponse, getProfileChangelog } from '../../../api/quality-profiles';
 import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import Spinner from '../../../components/ui/Spinner';
 import { parseDate, toISO8601WithOffsetString } from '../../../helpers/dates';
 import { translate } from '../../../helpers/l10n';
 import { withQualityProfilesContext } from '../qualityProfilesContext';
@@ -137,8 +137,8 @@ class ChangelogContainer extends React.PureComponent<Props, State> {
       this.state.events.length < this.state.total;
 
     return (
-      <div className="boxed-group boxed-group-inner js-profile-changelog">
-        <div className="spacer-bottom">
+      <div>
+        <div className="sw-mb-2 sw-flex sw-gap-4 sw-items-center">
           <ChangelogSearch
             dateRange={{
               from: query.since ? parseDate(query.since) : undefined,
@@ -147,7 +147,7 @@ class ChangelogContainer extends React.PureComponent<Props, State> {
             onDateRangeChange={this.handleDateRangeChange}
             onReset={this.handleReset}
           />
-          <Spinner loading={this.state.loading} className="spacer-left" />
+          <Spinner loading={this.state.loading} />
         </div>
 
         {this.state.events != null && this.state.events.length === 0 && <ChangelogEmpty />}
@@ -157,10 +157,10 @@ class ChangelogContainer extends React.PureComponent<Props, State> {
         )}
 
         {shouldDisplayFooter && (
-          <footer className="text-center spacer-top small">
-            <a href="#" onClick={this.loadMore.bind(this)}>
+          <footer className="sw-text-center sw-mt-2">
+            <ButtonSecondary onClick={this.loadMore.bind(this)}>
               {translate('show_more')}
-            </a>
+            </ButtonSecondary>
           </footer>
         )}
       </div>
index 9c51644b1f58b4b18512f4fe2e66f957e5c1b3cf..2159594477f38e74380aeee9ad649823e42c03cc 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { translate } from '../../../helpers/l10n';
+import { useIntl } from 'react-intl';
 
 export default function ChangelogEmpty() {
-  return <div className="big-spacer-top">{translate('no_results')}</div>;
+  const intl = useIntl();
+
+  return <div className="sw-mt-6">{intl.formatMessage({ id: 'no_results' })}</div>;
 }
index 6cb2ad54a74589ddabf02d7558ca6849b7a67fa9..8fcec92577bb46087940e577e419f4143d2b0f24 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 { ButtonSecondary, DateRangePicker } from 'design-system';
 import * as React from 'react';
-import { Button } from '../../../components/controls/buttons';
-import DateRangeInput from '../../../components/controls/DateRangeInput';
-import { translate } from '../../../helpers/l10n';
+import { useIntl } from 'react-intl';
 
 interface ChangelogSearchProps {
   dateRange: { from?: Date; to?: Date } | undefined;
@@ -30,12 +29,23 @@ interface ChangelogSearchProps {
 
 export default function ChangelogSearch(props: ChangelogSearchProps) {
   const { dateRange } = props;
+
+  const intl = useIntl();
+
   return (
-    <div className="display-flex-end" id="quality-profile-changelog-form">
-      <DateRangeInput onChange={props.onDateRangeChange} value={dateRange} />
-      <Button className="spacer-left text-top" onClick={props.onReset}>
-        {translate('reset_verb')}
-      </Button>
+    <div className="sw-flex sw-gap-2">
+      <DateRangePicker
+        clearButtonLabel={intl.formatMessage({ id: 'clear' })}
+        fromLabel={intl.formatMessage({ id: 'start_date' })}
+        inputSize="small"
+        separatorText={intl.formatMessage({ id: 'to' })}
+        toLabel={intl.formatMessage({ id: 'end_date' })}
+        onChange={props.onDateRangeChange}
+        value={dateRange}
+      />
+      <ButtonSecondary className="sw-ml-2 sw-align-top" onClick={props.onReset}>
+        {intl.formatMessage({ id: 'reset_verb' })}
+      </ButtonSecondary>
     </div>
   );
 }
index 047c2ccb2cffe4f5ed81fdd1e83c6351a5fb47e0..c1ea0b8b39ecd02b4e19c02808b25d3a055df8e0 100644 (file)
@@ -33,7 +33,7 @@ export default function ChangesList({ changes }: Props) {
   };
 
   return (
-    <ul>
+    <ul className="sw-flex sw-flex-col sw-gap-1">
       {Object.keys(changes).map((key) => (
         <li key={key}>
           {key === 'severity' ? (
index b289c2c799d8d8ec97aed7fd9a86592e8d4cbc95..68b7abb92f3e54d060447826cdee971e3206873c 100644 (file)
@@ -27,13 +27,13 @@ interface Props {
 
 export default function ParameterChange({ name, value }: Props) {
   return (
-    <div className="quality-profile-changelog-parameter">
+    <p className="sw-break-words">
       {value == null
         ? translateWithParameters(
             'quality_profiles.changelog.parameter_reset_to_default_value',
             name,
           )
         : translateWithParameters('quality_profiles.parameter_set_to', name, value)}
-    </div>
+    </p>
   );
 }
index 7af855cbbfbbd51776cb5dd37f3db54d3bd3b534..6f6c1e489f3095f12bec16914ec262520d30f5d0 100644 (file)
@@ -33,7 +33,7 @@ const ui = {
   row: byRole('row'),
   link: byRole('link'),
   emptyPage: byText('no_results'),
-  showMore: byRole('link', { name: 'show_more' }),
+  showMore: byRole('button', { name: 'show_more' }),
   startDate: byRole('textbox', { name: 'start_date' }),
   endDate: byRole('textbox', { name: 'end_date' }),
   reset: byRole('button', { name: 'reset_verb' }),
index f877e5b1ad697209f96262827b2eee37fa5e78f3..ee7041557f59367c295b22516b8b882d18f1fb8b 100644 (file)
@@ -94,14 +94,16 @@ export default function ProfileHeader(props: Props) {
                 <DateFromNow date={profile.lastUsed} />
               </div>
 
-              <div>
-                <Link
-                  className="it__quality-profiles__changelog"
-                  to={getProfileChangelogPath(profile.name, profile.language)}
-                >
-                  {translate('see_changelog')}
-                </Link>
-              </div>
+              {!isChangeLogPage && (
+                <div>
+                  <Link
+                    className="it__quality-profiles__changelog"
+                    to={getProfileChangelogPath(profile.name, profile.language)}
+                  >
+                    {translate('see_changelog')}
+                  </Link>
+                </div>
+              )}
             </>
           )}
 
index 291324828b80d1e7392d9abcb9bb94a6790fa73f..e22d2dea61fb8ae9b9605d6828728b0ac09aff41 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-.quality-profile-changelog-rule-cell {
-  line-height: 1.5;
-}
-
-.quality-profile-changelog-parameter {
-  max-width: 270px;
-  word-break: break-word;
-}
-
 #create-profile-form .radio-card {
   width: 244px;
   background-color: var(--neutral50);
index c76c2d6bb7d0dc326639d220ef899ce57586cdd8..e9a392af9b676dde47ffcbabf5a5ece73eb2422e 100644 (file)
@@ -236,6 +236,7 @@ unknown=Unknown
 unresolved=Unresolved
 updated=Updated
 updated_on=Updated on
+updates=Updates
 update_verb=Update
 updating=Updating
 unselected=Unselected