]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13385 Sort plugins on Marketplace alphabetically
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Mon, 15 Jun 2020 11:56:38 +0000 (13:56 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 19 Jun 2020 20:04:42 +0000 (20:04 +0000)
server/sonar-web/src/main/js/apps/marketplace/PluginsList.tsx
server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/mocks/plugins.ts

index 4c1933ac58745b38aea9fc4072d39798e75748d3..992a40b51f220c0e16ef6668c58797c2f0db9c6e 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 { sortBy } from 'lodash';
 import * as React from 'react';
-import {
-  InstalledPlugin,
-  isAvailablePlugin,
-  isInstalledPlugin,
-  PendingPlugin,
-  Plugin
-} from '../../types/plugins';
+import { isAvailablePlugin, isInstalledPlugin, PendingPlugin, Plugin } from '../../types/plugins';
 import PluginAvailable from './components/PluginAvailable';
 import PluginInstalled from './components/PluginInstalled';
 
-interface Props {
+export interface PluginsListProps {
   plugins: Plugin[];
   pending: {
     installing: PendingPlugin[];
@@ -39,61 +34,53 @@ interface Props {
   refreshPending: () => void;
 }
 
-export default class PluginsList extends React.PureComponent<Props> {
-  getPluginStatus = (plugin: Plugin): string | undefined => {
-    const { installing, updating, removing } = this.props.pending;
-    if (installing.find(p => p.key === plugin.key)) {
-      return 'installing';
-    }
-    if (updating.find(p => p.key === plugin.key)) {
-      return 'updating';
-    }
-    if (removing.find(p => p.key === plugin.key)) {
-      return 'removing';
-    }
-    return undefined;
-  };
+function getPluginStatus(plugin: Plugin, pending: PluginsListProps['pending']): string | undefined {
+  const { installing, updating, removing } = pending;
+  if (installing.find(p => p.key === plugin.key)) {
+    return 'installing';
+  }
+  if (updating.find(p => p.key === plugin.key)) {
+    return 'updating';
+  }
+  if (removing.find(p => p.key === plugin.key)) {
+    return 'removing';
+  }
+  return undefined;
+}
 
-  renderPlugin = (plugin: Plugin, installedPlugins: InstalledPlugin[]) => {
-    const status = this.getPluginStatus(plugin);
-    if (isInstalledPlugin(plugin)) {
-      return (
-        <PluginInstalled
-          plugin={plugin}
-          readOnly={this.props.readOnly}
-          refreshPending={this.props.refreshPending}
-          status={status}
-        />
-      );
-    }
-    if (isAvailablePlugin(plugin)) {
-      return (
-        <PluginAvailable
-          installedPlugins={installedPlugins}
-          plugin={plugin}
-          readOnly={this.props.readOnly}
-          refreshPending={this.props.refreshPending}
-          status={status}
-        />
-      );
-    }
-    return null;
-  };
+export default function PluginsList(props: PluginsListProps) {
+  const { pending, plugins, readOnly } = props;
+  const installedPlugins = plugins.filter(isInstalledPlugin);
+  return (
+    <div className="boxed-group boxed-group-inner" id="marketplace-plugins">
+      <ul>
+        {sortBy(plugins, ({ name }) => name).map(plugin => (
+          <li className="panel panel-vertical" key={plugin.key}>
+            <table className="marketplace-plugin-table">
+              <tbody>
+                {isInstalledPlugin(plugin) && (
+                  <PluginInstalled
+                    plugin={plugin}
+                    readOnly={readOnly}
+                    refreshPending={props.refreshPending}
+                    status={getPluginStatus(plugin, pending)}
+                  />
+                )}
 
-  render() {
-    const installedPlugins = this.props.plugins.filter(isInstalledPlugin);
-    return (
-      <div className="boxed-group boxed-group-inner" id="marketplace-plugins">
-        <ul>
-          {this.props.plugins.map(plugin => (
-            <li className="panel panel-vertical" key={plugin.key}>
-              <table className="marketplace-plugin-table">
-                <tbody>{this.renderPlugin(plugin, installedPlugins)}</tbody>
-              </table>
-            </li>
-          ))}
-        </ul>
-      </div>
-    );
-  }
+                {isAvailablePlugin(plugin) && (
+                  <PluginAvailable
+                    installedPlugins={installedPlugins}
+                    plugin={plugin}
+                    readOnly={readOnly}
+                    refreshPending={props.refreshPending}
+                    status={getPluginStatus(plugin, pending)}
+                  />
+                )}
+              </tbody>
+            </table>
+          </li>
+        ))}
+      </ul>
+    </div>
+  );
 }
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/__tests__/PluginsList-test.tsx
new file mode 100644 (file)
index 0000000..6ea3753
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 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 { mockAvailablePlugin, mockPendingPlugin } from '../../../helpers/mocks/plugins';
+import PluginsList, { PluginsListProps } from '../PluginsList';
+
+it('should render correctly', () => {
+  expect(shallowRender()).toMatchSnapshot('default');
+  expect(
+    shallowRender({
+      pending: {
+        installing: [mockPendingPlugin({ key: 'sonar-foo' })],
+        updating: [mockPendingPlugin({ key: 'sonar-bar' })],
+        removing: [mockPendingPlugin({ key: 'sonar-baz' })]
+      }
+    })
+  ).toMatchSnapshot('with status');
+});
+
+function shallowRender(props: Partial<PluginsListProps> = {}) {
+  return shallow<PluginsListProps>(
+    <PluginsList
+      plugins={[
+        mockAvailablePlugin({ key: 'sonar-foo' }),
+        mockAvailablePlugin({ key: 'sonar-bar', name: 'Sonar Bar' }),
+        mockAvailablePlugin({ key: 'sonar-baz', name: 'Sonar Baz' })
+      ]}
+      pending={{ installing: [], updating: [], removing: [] }}
+      readOnly={false}
+      refreshPending={jest.fn()}
+      {...props}
+    />
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/PluginsList-test.tsx.snap
new file mode 100644 (file)
index 0000000..bac4352
--- /dev/null
@@ -0,0 +1,204 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly: default 1`] = `
+<div
+  className="boxed-group boxed-group-inner"
+  id="marketplace-plugins"
+>
+  <ul>
+    <li
+      className="panel panel-vertical"
+      key="sonar-bar"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-bar",
+                "name": "Sonar Bar",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+          />
+        </tbody>
+      </table>
+    </li>
+    <li
+      className="panel panel-vertical"
+      key="sonar-baz"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-baz",
+                "name": "Sonar Baz",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+          />
+        </tbody>
+      </table>
+    </li>
+    <li
+      className="panel panel-vertical"
+      key="sonar-foo"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-foo",
+                "name": "Sonar Foo",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+          />
+        </tbody>
+      </table>
+    </li>
+  </ul>
+</div>
+`;
+
+exports[`should render correctly: with status 1`] = `
+<div
+  className="boxed-group boxed-group-inner"
+  id="marketplace-plugins"
+>
+  <ul>
+    <li
+      className="panel panel-vertical"
+      key="sonar-bar"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-bar",
+                "name": "Sonar Bar",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+            status="updating"
+          />
+        </tbody>
+      </table>
+    </li>
+    <li
+      className="panel panel-vertical"
+      key="sonar-baz"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-baz",
+                "name": "Sonar Baz",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+            status="removing"
+          />
+        </tbody>
+      </table>
+    </li>
+    <li
+      className="panel panel-vertical"
+      key="sonar-foo"
+    >
+      <table
+        className="marketplace-plugin-table"
+      >
+        <tbody>
+          <PluginAvailable
+            installedPlugins={Array []}
+            plugin={
+              Object {
+                "key": "sonar-foo",
+                "name": "Sonar Foo",
+                "release": Object {
+                  "date": "2020-01-01",
+                  "version": "8.2",
+                },
+                "update": Object {
+                  "requires": Array [],
+                  "status": "available",
+                },
+              }
+            }
+            readOnly={false}
+            refreshPending={[MockFunction]}
+            status="installing"
+          />
+        </tbody>
+      </table>
+    </li>
+  </ul>
+</div>
+`;
index bdaf34528d1148113d41d61bc105f9b241dff114..d701cf970bf8a6ccc9fa68b24091a8bb3fb4751a 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-import { AvailablePlugin, InstalledPlugin, Plugin, Release, Update } from '../../types/plugins';
+import {
+  AvailablePlugin,
+  InstalledPlugin,
+  PendingPlugin,
+  Plugin,
+  Release,
+  Update
+} from '../../types/plugins';
 
 export function mockPlugin(overrides: Partial<Plugin> = {}): Plugin {
   return {
@@ -28,6 +35,16 @@ export function mockPlugin(overrides: Partial<Plugin> = {}): Plugin {
   };
 }
 
+export function mockPendingPlugin(overrides: Partial<PendingPlugin> = {}): PendingPlugin {
+  return {
+    key: 'sonar-foo',
+    name: 'Sonar Foo',
+    version: '1.0',
+    implementationBuild: '1.0.0.1234',
+    ...overrides
+  };
+}
+
 export function mockInstalledPlugin(overrides: Partial<InstalledPlugin> = {}): InstalledPlugin {
   return {
     key: 'sonar-bar',