]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10487 Improve UX of filter option in Quality Profiles page
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Fri, 4 Jan 2019 16:51:43 +0000 (17:51 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Jan 2019 08:42:57 +0000 (09:42 +0100)
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesListHeader.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index c6bae822049da915c0c58706554298feab1757e9..279ca353277df84d5c569cc91713b1311915382e 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { IndexLink } from 'react-router';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { Option } from 'react-select';
+import { translate } from '../../../helpers/l10n';
 import { getProfilesPath, getProfilesForLanguagePath } from '../utils';
-import Dropdown from '../../../components/controls/Dropdown';
-import DropdownIcon from '../../../components/icons-components/DropdownIcon';
+import Select from '../../../components/controls/Select';
+import { withRouter, Router } from '../../../components/hoc/withRouter';
 
 interface Props {
   currentFilter?: string;
   languages: Array<{ key: string; name: string }>;
   organization: string | null;
+  router: Pick<Router, 'replace'>;
 }
 
-export default function ProfilesListHeader({ currentFilter, languages, organization }: Props) {
-  if (languages.length < 2) {
-    return null;
-  }
+export class ProfilesListHeader extends React.PureComponent<Props> {
+  handleChange = (option: { value: string } | null) => {
+    const { organization, router } = this.props;
 
-  const currentLanguage = currentFilter && languages.find(l => l.key === currentFilter);
+    router.replace(
+      !option
+        ? getProfilesPath(organization)
+        : getProfilesForLanguagePath(option.value, organization)
+    );
+  };
 
-  // if unknown language, then
-  if (currentFilter && !currentLanguage) {
-    return null;
-  }
+  render() {
+    const { currentFilter, languages } = this.props;
+    if (languages.length < 2) {
+      return null;
+    }
+
+    const options: Option[] = languages.map(language => ({
+      label: language.name,
+      value: language.key
+    }));
 
-  const label = currentLanguage
-    ? translateWithParameters('quality_profiles.x_Profiles', currentLanguage.name)
-    : translate('quality_profiles.all_profiles');
+    const currentLanguage = currentFilter && options.find(l => l.value === currentFilter);
 
-  return (
-    <header className="quality-profiles-list-header clearfix">
-      <Dropdown
-        className="display-inline-block"
-        overlay={
-          <ul className="menu">
-            <li>
-              <IndexLink to={getProfilesPath(organization)}>
-                {translate('quality_profiles.all_profiles')}
-              </IndexLink>
-            </li>
-            {languages.map(language => (
-              <li key={language.key}>
-                <IndexLink
-                  className="js-language-filter-option"
-                  data-language={language.key}
-                  to={getProfilesForLanguagePath(language.key, organization)}>
-                  {language.name}
-                </IndexLink>
-              </li>
-            ))}
-          </ul>
-        }>
-        <a className="dropdown-toggle link-no-underline js-language-filter" href="#">
-          <span className="text-middle">{label}</span>
-          <DropdownIcon className="little-spacer-left text-middle" />
-        </a>
-      </Dropdown>
-    </header>
-  );
+    return (
+      <header className="quality-profiles-list-header clearfix">
+        <span className="spacer-right">{translate('quality_profiles.filter_by')}:</span>
+        <Select
+          className="input-medium"
+          clearable={true}
+          onChange={this.handleChange}
+          options={options}
+          value={currentLanguage}
+        />
+      </header>
+    );
+  }
 }
+
+export default withRouter(ProfilesListHeader);
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx
new file mode 100644 (file)
index 0000000..efb9372
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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 { shallow } from 'enzyme';
+import { ProfilesListHeader } from '../ProfilesListHeader';
+import { mockRouter } from '../../../../helpers/testUtils';
+
+it('should render correctly', () => {
+  const wrapper = shallowRender();
+  expect(wrapper).toMatchSnapshot();
+});
+
+function shallowRender(props: Partial<ProfilesListHeader['props']> = {}) {
+  return shallow(
+    <ProfilesListHeader
+      languages={[{ key: 'js', name: 'JavaScript' }, { key: 'java', name: 'Java' }]}
+      organization="foo"
+      router={mockRouter()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap
new file mode 100644 (file)
index 0000000..95e39f0
--- /dev/null
@@ -0,0 +1,31 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<header
+  className="quality-profiles-list-header clearfix"
+>
+  <span
+    className="spacer-right"
+  >
+    quality_profiles.filter_by
+    :
+  </span>
+  <Select
+    className="input-medium"
+    clearable={true}
+    onChange={[Function]}
+    options={
+      Array [
+        Object {
+          "label": "JavaScript",
+          "value": "js",
+        },
+        Object {
+          "label": "Java",
+          "value": "java",
+        },
+      ]
+    }
+  />
+</header>
+`;
index 425c67656a91aedee14f9e4d2cee8492f7d2fa6d..e527a0e54d678b72a4d5dc764562bcf2c0878d50 100644 (file)
@@ -1142,6 +1142,7 @@ projects_management.project_has_been_successfully_created=Project {project} has
 
 quality_profiles.new_profile=New Profile
 quality_profiles.compare_with=Compare with
+quality_profiles.filter_by=Filter profiles by
 quality_profiles.restore_profile=Restore Profile
 quality_profiles.restore_profile.success={1} rule(s) restored in profile "{0}"
 quality_profiles.restore_profile.warning={1} rule(s) restored, {2} rule(s) ignored in profile "{0}"