]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17000 SONAR-16974
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 7 Oct 2022 08:30:25 +0000 (10:30 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 11 Oct 2022 20:03:59 +0000 (20:03 +0000)
* [894088] Element inappropriately uses semantic markup
* [894116] Label is not persistent

21 files changed:
server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx
server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css
server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/Search.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.tsx
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.tsx
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityDateInput.tsx
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFilters.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.tsx [deleted file]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageFilters-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.tsx.snap
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityDateInput-test.tsx.snap
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageFilters-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogSearch.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap
server/sonar-web/src/main/js/components/controls/DateInput.tsx
server/sonar-web/src/main/js/components/controls/DateRangeInput.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/DateRangeInput-test.tsx.snap

index 668cb99c8e49e4f3d97928b07ee8cdbcc792e158..d191cc46fb309a9e6eccf1a09e20107d79b2ba63 100644 (file)
@@ -119,7 +119,6 @@ export default function AuditAppRenderer(props: AuditAppRendererProps) {
         </ul>
 
         <DateRangeInput
-          className="big-spacer-left"
           onChange={props.handleDateSelection}
           minDate={subDays(now(), HOUSEKEEPING_POLICY_VALUES[housekeepingPolicy])}
           maxDate={now()}
index 5fb4b9ad748574042e61487739a59c828ca6b56c..f08c5d60023d9212f576ca0cb386afc3f16cba63 100644 (file)
   margin-left: 16px;
 }
 
-.bt-search-form-label {
-  margin-bottom: 4px;
-}
-
 .bt-search-form-field {
   padding: 4px 0;
 }
index a6ab2a113b6bcdb5f0ffb14d6bd935d35811331d..d9343452025e4653559f45983fe6c2f513db02b7 100644 (file)
@@ -22,25 +22,29 @@ import Checkbox from '../../../components/controls/Checkbox';
 import { translate } from '../../../helpers/l10n';
 import { CURRENTS } from '../constants';
 
-interface Props {
+interface CurrentsFilterProps {
   value?: string;
+  id: string;
   onChange: (value: string) => void;
 }
 
-export default class CurrentsFilter extends React.PureComponent<Props> {
-  handleChange = (value: boolean) => {
-    const newValue = value ? CURRENTS.ONLY_CURRENTS : CURRENTS.ALL;
-    this.props.onChange(newValue);
-  };
+export default function CurrentsFilter(props: CurrentsFilterProps) {
+  const { id, value, onChange } = props;
+  const checked = value === CURRENTS.ONLY_CURRENTS;
 
-  render() {
-    const checked = this.props.value === CURRENTS.ONLY_CURRENTS;
-    return (
-      <div className="bt-search-form-field">
-        <Checkbox checked={checked} onCheck={this.handleChange}>
-          <span className="little-spacer-left">{translate('yes')}</span>
-        </Checkbox>
-      </div>
-    );
-  }
+  const handleChange = React.useCallback(
+    (value: boolean) => {
+      const newValue = value ? CURRENTS.ONLY_CURRENTS : CURRENTS.ALL;
+      onChange(newValue);
+    },
+    [onChange]
+  );
+
+  return (
+    <div className="bt-search-form-field">
+      <Checkbox id={id} checked={checked} onCheck={handleChange}>
+        <span className="little-spacer-left">{translate('yes')}</span>
+      </Checkbox>
+    </div>
+  );
 }
index 198317542dcd287137e15ab21609cf108f62dffc..bede447ef599f622114577c1cf50680ed6f444da 100644 (file)
@@ -102,29 +102,49 @@ export default class Search extends React.PureComponent<Props> {
       <section className="big-spacer-top big-spacer-bottom">
         <ul className="bt-search-form">
           <li>
-            <h6 id="background-task-status-filter-label" className="bt-search-form-label">
-              {translate('status')}
-            </h6>
-            <StatusFilter onChange={this.handleStatusChange} value={status} />
+            <div className="display-flex-column">
+              <label
+                id="background-task-status-filter-label"
+                className="text-bold little-spacer-bottom"
+                htmlFor="status-filter">
+                {translate('status')}
+              </label>
+              <StatusFilter id="status-filter" onChange={this.handleStatusChange} value={status} />
+            </div>
           </li>
           {types.length > 1 && (
             <li>
-              <h6 id="background-task-type-filter-label" className="bt-search-form-label">
-                {translate('type')}
-              </h6>
-              <TypesFilter onChange={this.handleTypeChange} types={types} value={taskType} />
+              <div className="display-flex-column">
+                <label
+                  id="background-task-type-filter-label"
+                  className="text-bold little-spacer-bottom"
+                  htmlFor="types-filter">
+                  {translate('type')}
+                </label>
+                <TypesFilter
+                  id="types-filter"
+                  onChange={this.handleTypeChange}
+                  types={types}
+                  value={taskType}
+                />
+              </div>
             </li>
           )}
           {!component && (
             <li>
-              <h6 className="bt-search-form-label">
-                {translate('background_tasks.currents_filter.ONLY_CURRENTS')}
-              </h6>
-              <CurrentsFilter onChange={this.handleCurrentsChange} value={currents} />
+              <div className="display-flex-column">
+                <label className="text-bold little-spacer-bottom" htmlFor="currents-filter">
+                  {translate('background_tasks.currents_filter.ONLY_CURRENTS')}
+                </label>
+                <CurrentsFilter
+                  id="currents-filter"
+                  onChange={this.handleCurrentsChange}
+                  value={currents}
+                />
+              </div>
             </li>
           )}
           <li>
-            <h6 className="bt-search-form-label">{translate('date')}</h6>
             <DateFilter
               maxExecutedAt={maxExecutedAt}
               minSubmittedAt={minSubmittedAt}
index 6e248342f5433d5cdd1c57074c54fac27566738d..f797b4337199a868953add5628b39c1d0a09551a 100644 (file)
@@ -23,39 +23,44 @@ import { translate } from '../../../helpers/l10n';
 import { TaskStatuses } from '../../../types/tasks';
 import { STATUSES } from '../constants';
 
-interface Props {
+interface StatusFilterProps {
   value?: string;
+  id: string;
   onChange: (value?: string) => void;
 }
 
-export default class StatusFilter extends React.PureComponent<Props> {
-  handleChange = ({ value }: BasicSelectOption) => {
-    this.props.onChange(value);
-  };
+export default function StatusFilter(props: StatusFilterProps) {
+  const { id, value, onChange } = props;
 
-  render() {
-    const options: BasicSelectOption[] = [
-      { value: STATUSES.ALL, label: translate('background_task.status.ALL') },
-      {
-        value: STATUSES.ALL_EXCEPT_PENDING,
-        label: translate('background_task.status.ALL_EXCEPT_PENDING')
-      },
-      { value: TaskStatuses.Pending, label: translate('background_task.status.PENDING') },
-      { value: TaskStatuses.InProgress, label: translate('background_task.status.IN_PROGRESS') },
-      { value: TaskStatuses.Success, label: translate('background_task.status.SUCCESS') },
-      { value: TaskStatuses.Failed, label: translate('background_task.status.FAILED') },
-      { value: TaskStatuses.Canceled, label: translate('background_task.status.CANCELED') }
-    ];
+  const options: BasicSelectOption[] = [
+    { value: STATUSES.ALL, label: translate('background_task.status.ALL') },
+    {
+      value: STATUSES.ALL_EXCEPT_PENDING,
+      label: translate('background_task.status.ALL_EXCEPT_PENDING')
+    },
+    { value: TaskStatuses.Pending, label: translate('background_task.status.PENDING') },
+    { value: TaskStatuses.InProgress, label: translate('background_task.status.IN_PROGRESS') },
+    { value: TaskStatuses.Success, label: translate('background_task.status.SUCCESS') },
+    { value: TaskStatuses.Failed, label: translate('background_task.status.FAILED') },
+    { value: TaskStatuses.Canceled, label: translate('background_task.status.CANCELED') }
+  ];
 
-    return (
-      <Select
-        aria-labelledby="background-task-status-filter-label"
-        className="input-medium"
-        onChange={this.handleChange}
-        options={options}
-        value={options.find(o => o.value === this.props.value)}
-        isSearchable={false}
-      />
-    );
-  }
+  const handleChange = React.useCallback(
+    ({ value }: BasicSelectOption) => {
+      onChange(value);
+    },
+    [onChange]
+  );
+
+  return (
+    <Select
+      aria-labelledby="background-task-status-filter-label"
+      className="input-medium"
+      id={id}
+      onChange={handleChange}
+      options={options}
+      value={options.find(o => o.value === value)}
+      isSearchable={false}
+    />
+  );
 }
index b84b21505399fd8f5d541a01c44aeb1aec5a5cdd..4ef1522f76da2dc167405aacaebdba23986b4708 100644 (file)
@@ -24,6 +24,7 @@ import { ALL_TYPES } from '../constants';
 
 interface Props {
   value: string;
+  id: string;
   onChange: Function;
   types: string[];
 }
@@ -34,7 +35,7 @@ export default class TypesFilter extends React.PureComponent<Props> {
   };
 
   render() {
-    const { value, types } = this.props;
+    const { value, types, id } = this.props;
     const options = types.map(t => {
       return {
         value: t,
@@ -51,6 +52,7 @@ export default class TypesFilter extends React.PureComponent<Props> {
       <Select
         aria-labelledby="background-task-type-filter-label"
         className="input-large"
+        id={id}
         isClearable={false}
         onChange={this.handleChange}
         options={allOptions}
index b1fa4fa47ad51bbba1a28a7cb1e7b26bacff343f..fe2c2d21886372b284322d660600e0bf987b345b 100644 (file)
@@ -29,7 +29,7 @@ import { Query } from '../utils';
 import './projectActivity.css';
 import ProjectActivityAnalysesList from './ProjectActivityAnalysesList';
 import ProjectActivityGraphs from './ProjectActivityGraphs';
-import ProjectActivityPageHeader from './ProjectActivityPageHeader';
+import ProjectActivityPageFilters from './ProjectActivityPageFilters';
 
 interface Props {
   addCustomEvent: (analysis: string, name: string, category?: string) => Promise<void>;
@@ -62,7 +62,7 @@ export default function ProjectActivityApp(props: Props) {
 
       <A11ySkipTarget anchor="activity_main" />
 
-      <ProjectActivityPageHeader
+      <ProjectActivityPageFilters
         category={query.category}
         from={query.from}
         project={props.project}
index e8ef04cf8c9141cf544f9ef87f8f8afd593baf2d..03fa34586d916ca75b708251d89ef4349aaec3e1 100644 (file)
@@ -40,7 +40,7 @@ export default class ProjectActivityDateInput extends React.PureComponent<Props>
 
   render() {
     return (
-      <div>
+      <div className="display-flex-end">
         <DateRangeInput
           onChange={this.handleChange}
           value={{ from: this.props.from, to: this.props.to }}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFilters.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageFilters.tsx
new file mode 100644 (file)
index 0000000..4e6dd15
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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 Select from '../../../components/controls/Select';
+import { translate } from '../../../helpers/l10n';
+import { ComponentQualifier } from '../../../types/component';
+import { Component } from '../../../types/types';
+import { APPLICATION_EVENT_TYPES, EVENT_TYPES, Query } from '../utils';
+import ProjectActivityDateInput from './ProjectActivityDateInput';
+
+interface ProjectActivityPageFiltersProps {
+  category?: string;
+  from?: Date;
+  project: Pick<Component, 'qualifier'>;
+  to?: Date;
+  updateQuery: (changes: Partial<Query>) => void;
+}
+
+export default function ProjectActivityPageFilters(props: ProjectActivityPageFiltersProps) {
+  const { project, category, from, to, updateQuery } = props;
+
+  const isApp = project.qualifier === ComponentQualifier.Application;
+  const eventTypes = isApp ? APPLICATION_EVENT_TYPES : EVENT_TYPES;
+  const options = eventTypes.map(category => ({
+    label: translate('event.category', category),
+    value: category
+  }));
+
+  const handleCategoryChange = React.useCallback(
+    (option: { value: string } | null) => {
+      updateQuery({ category: option ? option.value : '' });
+    },
+    [updateQuery]
+  );
+
+  return (
+    <div className="page-header display-flex-start">
+      {!([ComponentQualifier.Portfolio, ComponentQualifier.SubPortfolio] as string[]).includes(
+        project.qualifier
+      ) && (
+        <div className="display-flex-column big-spacer-right">
+          <label className="text-bold little-spacer-bottom" htmlFor="filter-events">
+            {translate('project_activity.filter_events')}
+          </label>
+          <Select
+            className={isApp ? 'input-large' : 'input-medium'}
+            id="filter-events"
+            isClearable={true}
+            isSearchable={false}
+            onChange={handleCategoryChange}
+            options={options}
+            value={options.filter(o => o.value === category)}
+          />
+        </div>
+      )}
+      <ProjectActivityDateInput from={from} onChange={props.updateQuery} to={to} />
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityPageHeader.tsx
deleted file mode 100644 (file)
index 57f22d9..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 classNames from 'classnames';
-import * as React from 'react';
-import Select from '../../../components/controls/Select';
-import { translate } from '../../../helpers/l10n';
-import { Component } from '../../../types/types';
-import { APPLICATION_EVENT_TYPES, EVENT_TYPES, Query } from '../utils';
-import ProjectActivityDateInput from './ProjectActivityDateInput';
-
-interface Props {
-  category?: string;
-  from?: Date;
-  project: Pick<Component, 'qualifier'>;
-  to?: Date;
-  updateQuery: (changes: Partial<Query>) => void;
-}
-
-export default class ProjectActivityPageHeader extends React.PureComponent<Props> {
-  handleCategoryChange = (option: { value: string } | null) =>
-    this.props.updateQuery({ category: option ? option.value : '' });
-
-  render() {
-    const isApp = this.props.project.qualifier === 'APP';
-    const eventTypes = isApp ? APPLICATION_EVENT_TYPES : EVENT_TYPES;
-    const options = eventTypes.map(category => ({
-      label: translate('event.category', category),
-      value: category
-    }));
-
-    return (
-      <header className="page-header">
-        {!['VW', 'SVW'].includes(this.props.project.qualifier) && (
-          <Select
-            className={classNames('pull-left big-spacer-right', {
-              'input-medium': !isApp,
-              'input-large': isApp
-            })}
-            placeholder={translate('project_activity.filter_events') + '...'}
-            isClearable={true}
-            isSearchable={false}
-            onChange={this.handleCategoryChange}
-            options={options}
-            value={options.filter(o => o.value === this.props.category)}
-          />
-        )}
-        <ProjectActivityDateInput
-          from={this.props.from}
-          onChange={this.props.updateQuery}
-          to={this.props.to}
-        />
-      </header>
-    );
-  }
-}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageFilters-test.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageFilters-test.tsx
new file mode 100644 (file)
index 0000000..54beadc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 { shallow } from 'enzyme';
+import * as React from 'react';
+import { parseDate } from '../../../../helpers/dates';
+import ProjectActivityPageFilters from '../ProjectActivityPageFilters';
+
+it('should render correctly the list of series', () => {
+  expect(
+    shallow(
+      <ProjectActivityPageFilters
+        category=""
+        from={parseDate('2016-10-27T12:21:15+0200')}
+        project={{ qualifier: 'TRK' }}
+        updateQuery={() => {}}
+      />
+    )
+  ).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityPageHeader-test.tsx
deleted file mode 100644 (file)
index 209ef35..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { parseDate } from '../../../../helpers/dates';
-import ProjectActivityPageHeader from '../ProjectActivityPageHeader';
-
-it('should render correctly the list of series', () => {
-  expect(
-    shallow(
-      <ProjectActivityPageHeader
-        category=""
-        from={parseDate('2016-10-27T12:21:15+0200')}
-        project={{ qualifier: 'TRK' }}
-        updateQuery={() => {}}
-      />
-    )
-  ).toMatchSnapshot();
-});
index bcb41a669164adb90c40df1fc30ff3a303f7ab4d..3f89e7becc18d6b79191bc8dc4b3718b8d381cfd 100644 (file)
@@ -17,7 +17,7 @@ exports[`should render correctly 1`] = `
   <A11ySkipTarget
     anchor="activity_main"
   />
-  <ProjectActivityPageHeader
+  <ProjectActivityPageFilters
     category=""
     project={
       Object {
index d10a64ba95cf09c97be700ad19d4f9615fb3ab92..7ebe7e54805d179af3b0ef76ece5d333d63d0baf 100644 (file)
@@ -1,7 +1,9 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly the date inputs 1`] = `
-<div>
+<div
+  className="display-flex-end"
+>
   <DateRangeInput
     onChange={[Function]}
     value={
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageFilters-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageFilters-test.tsx.snap
new file mode 100644 (file)
index 0000000..56f0a23
--- /dev/null
@@ -0,0 +1,50 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly the list of series 1`] = `
+<div
+  className="page-header display-flex-start"
+>
+  <div
+    className="display-flex-column big-spacer-right"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="filter-events"
+    >
+      project_activity.filter_events
+    </label>
+    <Select
+      className="input-medium"
+      id="filter-events"
+      isClearable={true}
+      isSearchable={false}
+      onChange={[Function]}
+      options={
+        Array [
+          Object {
+            "label": "event.category.VERSION",
+            "value": "VERSION",
+          },
+          Object {
+            "label": "event.category.QUALITY_GATE",
+            "value": "QUALITY_GATE",
+          },
+          Object {
+            "label": "event.category.QUALITY_PROFILE",
+            "value": "QUALITY_PROFILE",
+          },
+          Object {
+            "label": "event.category.OTHER",
+            "value": "OTHER",
+          },
+        ]
+      }
+      value={Array []}
+    />
+  </div>
+  <ProjectActivityDateInput
+    from={2016-10-27T10:21:15.000Z}
+    onChange={[Function]}
+  />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityPageHeader-test.tsx.snap
deleted file mode 100644 (file)
index 5659e62..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly the list of series 1`] = `
-<header
-  className="page-header"
->
-  <Select
-    className="pull-left big-spacer-right input-medium"
-    isClearable={true}
-    isSearchable={false}
-    onChange={[Function]}
-    options={
-      Array [
-        Object {
-          "label": "event.category.VERSION",
-          "value": "VERSION",
-        },
-        Object {
-          "label": "event.category.QUALITY_GATE",
-          "value": "QUALITY_GATE",
-        },
-        Object {
-          "label": "event.category.QUALITY_PROFILE",
-          "value": "QUALITY_PROFILE",
-        },
-        Object {
-          "label": "event.category.OTHER",
-          "value": "OTHER",
-        },
-      ]
-    }
-    placeholder="project_activity.filter_events..."
-    value={Array []}
-  />
-  <ProjectActivityDateInput
-    from={2016-10-27T10:21:15.000Z}
-    onChange={[Function]}
-  />
-</header>
-`;
index 9b34dcf77f678121df51d88573fcf5fb5a69a1f4..0a59ac50f2306693f99474708212e228b99e3008 100644 (file)
@@ -22,21 +22,20 @@ import { Button } from '../../../components/controls/buttons';
 import DateRangeInput from '../../../components/controls/DateRangeInput';
 import { translate } from '../../../helpers/l10n';
 
-interface Props {
+interface ChangelogSearchProps {
   dateRange: { from?: Date; to?: Date } | undefined;
   onDateRangeChange: (range: { from?: Date; to?: Date }) => void;
   onReset: () => void;
 }
 
-export default class ChangelogSearch extends React.PureComponent<Props> {
-  render() {
-    return (
-      <div className="display-inline-block" id="quality-profile-changelog-form">
-        <DateRangeInput onChange={this.props.onDateRangeChange} value={this.props.dateRange} />
-        <Button className="spacer-left text-top" onClick={this.props.onReset}>
-          {translate('reset_verb')}
-        </Button>
-      </div>
-    );
-  }
+export default function ChangelogSearch(props: ChangelogSearchProps) {
+  const { dateRange } = props;
+  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>
+  );
 }
index 457151fcb76891ebdc51a019dae44df996206d32..91386121e4e42f331c0041f401a424a07a9903ed 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should render 1`] = `
 <div
-  className="display-inline-block"
+  className="display-flex-end"
   id="quality-profile-changelog-form"
 >
   <DateRangeInput
index 9ed6b165b109b8fa9c8812fa541138d95e1cbd06..166d7717aee60547b93a9ed2dfef1b26a6356f70 100644 (file)
@@ -47,6 +47,7 @@ interface Props {
   maxDate?: Date;
   minDate?: Date;
   name?: string;
+  id?: string;
   onChange: (date: Date | undefined) => void;
   placeholder: string;
   value?: Date;
@@ -128,6 +129,7 @@ export default class DateInput extends React.PureComponent<Props, State> {
       name,
       className,
       inputClassName,
+      id,
       placeholder
     } = this.props;
     const { lastHovered, currentMonth, open } = this.state;
@@ -166,6 +168,7 @@ export default class DateInput extends React.PureComponent<Props, State> {
             className={classNames('date-input-control-input', inputClassName, {
               'is-filled': value !== undefined
             })}
+            id={id}
             innerRef={(node: HTMLInputElement | null) => (this.input = node)}
             name={name}
             onFocus={this.openCalendar}
index 4d3aee13173631528079bbcbf518dfb9d6af341c..a2f13e9b6354c2daffccd7dfc298d6b89c6ead56 100644 (file)
@@ -63,29 +63,43 @@ export default class DateRangeInput extends React.PureComponent<Props> {
     const { minDate, maxDate } = this.props;
 
     return (
-      <div className={classNames('display-inline-flex-center', this.props.className)}>
-        <DateInput
-          currentMonth={this.to}
-          data-test="from"
-          highlightTo={this.to}
-          minDate={minDate}
-          maxDate={maxDate && this.to ? min([maxDate, this.to]) : maxDate || this.to}
-          onChange={this.handleFromChange}
-          placeholder={translate('start_date')}
-          value={this.from}
-        />
-        <span className="note little-spacer-left little-spacer-right">{translate('to_')}</span>
-        <DateInput
-          currentMonth={this.from}
-          data-test="to"
-          highlightFrom={this.from}
-          minDate={minDate && this.from ? max([minDate, this.from]) : minDate || this.from}
-          maxDate={maxDate}
-          onChange={this.handleToChange}
-          placeholder={translate('end_date')}
-          ref={element => (this.toDateInput = element)}
-          value={this.to}
-        />
+      <div className={classNames('display-flex-end', this.props.className)}>
+        <div className="display-flex-column">
+          <label className="text-bold little-spacer-bottom" htmlFor="date-from">
+            {translate('start_date')}
+          </label>
+          <DateInput
+            currentMonth={this.to}
+            data-test="from"
+            id="date-from"
+            highlightTo={this.to}
+            minDate={minDate}
+            maxDate={maxDate && this.to ? min([maxDate, this.to]) : maxDate || this.to}
+            onChange={this.handleFromChange}
+            placeholder={translate('start_date')}
+            value={this.from}
+          />
+        </div>
+        <span className="note little-spacer-left little-spacer-right little-spacer-bottom">
+          {translate('to_')}
+        </span>
+        <div className="display-flex-column">
+          <label className="text-bold little-spacer-bottom" htmlFor="date-to">
+            {translate('end_date')}
+          </label>
+          <DateInput
+            currentMonth={this.from}
+            data-test="to"
+            id="date-to"
+            highlightFrom={this.from}
+            minDate={minDate && this.from ? max([minDate, this.from]) : minDate || this.from}
+            maxDate={maxDate}
+            onChange={this.handleToChange}
+            placeholder={translate('end_date')}
+            ref={element => (this.toDateInput = element)}
+            value={this.to}
+          />
+        </div>
       </div>
     );
   }
index dbc2f7cb5a2d2a7df71bc0edcf5ba743f3383883..19e4e6ab487dac1329a950b8e07c14f63e1c7ced 100644 (file)
 
 exports[`should render 1`] = `
 <div
-  className="display-inline-flex-center"
+  className="display-flex-end"
 >
-  <DateInput
-    currentMonth={2018-02-05T00:00:00.000Z}
-    data-test="from"
-    highlightTo={2018-02-05T00:00:00.000Z}
-    maxDate={2018-02-05T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="start_date"
-    value={2018-01-17T00:00:00.000Z}
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-from"
+    >
+      start_date
+    </label>
+    <DateInput
+      currentMonth={2018-02-05T00:00:00.000Z}
+      data-test="from"
+      highlightTo={2018-02-05T00:00:00.000Z}
+      id="date-from"
+      maxDate={2018-02-05T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="start_date"
+      value={2018-01-17T00:00:00.000Z}
+    />
+  </div>
   <span
-    className="note little-spacer-left little-spacer-right"
+    className="note little-spacer-left little-spacer-right little-spacer-bottom"
   >
     to_
   </span>
-  <DateInput
-    currentMonth={2018-01-17T00:00:00.000Z}
-    data-test="to"
-    highlightFrom={2018-01-17T00:00:00.000Z}
-    minDate={2018-01-17T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="end_date"
-    value={2018-02-05T00:00:00.000Z}
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-to"
+    >
+      end_date
+    </label>
+    <DateInput
+      currentMonth={2018-01-17T00:00:00.000Z}
+      data-test="to"
+      highlightFrom={2018-01-17T00:00:00.000Z}
+      id="date-to"
+      minDate={2018-01-17T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="end_date"
+      value={2018-02-05T00:00:00.000Z}
+    />
+  </div>
 </div>
 `;
 
 exports[`should render: with min/max 1`] = `
 <div
-  className="display-inline-flex-center"
+  className="display-flex-end"
 >
-  <DateInput
-    data-test="from"
-    maxDate={2018-02-05T00:00:00.000Z}
-    minDate={2018-01-17T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="start_date"
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-from"
+    >
+      start_date
+    </label>
+    <DateInput
+      data-test="from"
+      id="date-from"
+      maxDate={2018-02-05T00:00:00.000Z}
+      minDate={2018-01-17T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="start_date"
+    />
+  </div>
   <span
-    className="note little-spacer-left little-spacer-right"
+    className="note little-spacer-left little-spacer-right little-spacer-bottom"
   >
     to_
   </span>
-  <DateInput
-    data-test="to"
-    maxDate={2018-02-05T00:00:00.000Z}
-    minDate={2018-01-17T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="end_date"
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-to"
+    >
+      end_date
+    </label>
+    <DateInput
+      data-test="to"
+      id="date-to"
+      maxDate={2018-02-05T00:00:00.000Z}
+      minDate={2018-01-17T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="end_date"
+    />
+  </div>
 </div>
 `;
 
 exports[`should render: with min/max and value 1`] = `
 <div
-  className="display-inline-flex-center"
+  className="display-flex-end"
 >
-  <DateInput
-    currentMonth={2018-02-05T00:00:00.000Z}
-    data-test="from"
-    highlightTo={2018-02-05T00:00:00.000Z}
-    maxDate={2018-02-05T00:00:00.000Z}
-    minDate={2018-01-17T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="start_date"
-    value={2018-01-17T00:00:00.000Z}
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-from"
+    >
+      start_date
+    </label>
+    <DateInput
+      currentMonth={2018-02-05T00:00:00.000Z}
+      data-test="from"
+      highlightTo={2018-02-05T00:00:00.000Z}
+      id="date-from"
+      maxDate={2018-02-05T00:00:00.000Z}
+      minDate={2018-01-17T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="start_date"
+      value={2018-01-17T00:00:00.000Z}
+    />
+  </div>
   <span
-    className="note little-spacer-left little-spacer-right"
+    className="note little-spacer-left little-spacer-right little-spacer-bottom"
   >
     to_
   </span>
-  <DateInput
-    currentMonth={2018-01-17T00:00:00.000Z}
-    data-test="to"
-    highlightFrom={2018-01-17T00:00:00.000Z}
-    maxDate={2018-02-05T00:00:00.000Z}
-    minDate={2018-01-17T00:00:00.000Z}
-    onChange={[Function]}
-    placeholder="end_date"
-    value={2018-02-05T00:00:00.000Z}
-  />
+  <div
+    className="display-flex-column"
+  >
+    <label
+      className="text-bold little-spacer-bottom"
+      htmlFor="date-to"
+    >
+      end_date
+    </label>
+    <DateInput
+      currentMonth={2018-01-17T00:00:00.000Z}
+      data-test="to"
+      highlightFrom={2018-01-17T00:00:00.000Z}
+      id="date-to"
+      maxDate={2018-02-05T00:00:00.000Z}
+      minDate={2018-01-17T00:00:00.000Z}
+      onChange={[Function]}
+      placeholder="end_date"
+      value={2018-02-05T00:00:00.000Z}
+    />
+  </div>
 </div>
 `;