* 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[];
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>
+ );
}
--- /dev/null
+/*
+ * 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}
+ />
+ );
+}
--- /dev/null
+// 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>
+`;
* 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 {
};
}
+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',