]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-13643 Improve user feedback when there is no plugins
authorPhilippe Perrin <philippe.perrin@sonarsource.com>
Thu, 17 Sep 2020 15:10:09 +0000 (17:10 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 18 Sep 2020 20:07:18 +0000 (20:07 +0000)
server/sonar-web/src/main/js/apps/marketplace/App.tsx
server/sonar-web/src/main/js/apps/marketplace/__tests__/App-test.tsx
server/sonar-web/src/main/js/apps/marketplace/__tests__/__snapshots__/App-test.tsx.snap
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 27289b329c48a0409e4f87e354f75d477cef0891..1075118cb174525cb9a29a249629067fdd306177 100644 (file)
@@ -20,6 +20,7 @@
 import { sortBy, uniqBy } from 'lodash';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
+import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import {
   getAvailablePlugins,
@@ -135,16 +136,21 @@ export class App extends React.PureComponent<Props, State> {
           updateCenterActive={this.props.updateCenterActive}
           updateQuery={this.updateQuery}
         />
-        {loadingPlugins && <i className="spinner" />}
-        {!loadingPlugins && (
-          <PluginsList
-            pending={pendingPlugins}
-            plugins={filteredPlugins}
-            readOnly={!standaloneMode}
-            refreshPending={this.props.fetchPendingPlugins}
-          />
-        )}
-        {!loadingPlugins && <Footer total={filteredPlugins.length} />}
+        <DeferredSpinner loading={loadingPlugins}>
+          {filteredPlugins.length === 0 &&
+            translate('marketplace.plugin_list.no_plugins', query.filter)}
+          {filteredPlugins.length > 0 && (
+            <>
+              <PluginsList
+                pending={pendingPlugins}
+                plugins={filteredPlugins}
+                readOnly={!standaloneMode}
+                refreshPending={this.props.fetchPendingPlugins}
+              />
+              <Footer total={filteredPlugins.length} />
+            </>
+          )}
+        </DeferredSpinner>
       </div>
     );
   }
index ed16e97c18963ccfea481fb8c762136a00439e9d..2d390431bb7ee8360f7177197d0f6d06eedf1642 100644 (file)
@@ -29,19 +29,25 @@ import {
 import { mockLocation, mockRouter } from '../../../helpers/testMocks';
 import { App } from '../App';
 
-jest.mock('../../../api/plugins', () => ({
-  getAvailablePlugins: jest.fn().mockResolvedValue({ plugins: [] }),
-  getInstalledPlugins: jest.fn().mockResolvedValue([]),
-  getInstalledPluginsWithUpdates: jest.fn().mockResolvedValue([]),
-  getPluginUpdates: jest.fn().mockResolvedValue([])
-}));
+jest.mock('../../../api/plugins', () => {
+  const plugin = jest.requireActual('../../../helpers/mocks/plugins').mockPlugin();
+
+  return {
+    getAvailablePlugins: jest.fn().mockResolvedValue({ plugins: [plugin] }),
+    getInstalledPlugins: jest.fn().mockResolvedValue([]),
+    getInstalledPluginsWithUpdates: jest.fn().mockResolvedValue([]),
+    getPluginUpdates: jest.fn().mockResolvedValue([])
+  };
+});
 
 beforeEach(jest.clearAllMocks);
 
-it('should render correctly', () => {
+it('should render correctly', async () => {
   const wrapper = shallowRender();
   expect(wrapper).toMatchSnapshot('loading');
-  expect(wrapper.setState({ loadingPlugins: false })).toMatchSnapshot('loaded');
+
+  await waitAndUpdate(wrapper);
+  expect(wrapper).toMatchSnapshot('loaded');
 });
 
 it('should fetch plugin info', async () => {
index 8b49373723e2bf7ff0592be9da21fab3e8cd3037..09a6bc145c14c93e71af4bb8b3e6c1115d99babf 100644 (file)
@@ -39,21 +39,32 @@ exports[`should render correctly: loaded 1`] = `
     updateCenterActive={false}
     updateQuery={[Function]}
   />
-  <PluginsList
-    pending={
-      Object {
-        "installing": Array [],
-        "removing": Array [],
-        "updating": Array [],
+  <DeferredSpinner
+    loading={false}
+  >
+    <PluginsList
+      pending={
+        Object {
+          "installing": Array [],
+          "removing": Array [],
+          "updating": Array [],
+        }
       }
-    }
-    plugins={Array []}
-    readOnly={true}
-    refreshPending={[MockFunction]}
-  />
-  <Footer
-    total={0}
-  />
+      plugins={
+        Array [
+          Object {
+            "key": "sonar-foo",
+            "name": "Sonar Foo",
+          },
+        ]
+      }
+      readOnly={true}
+      refreshPending={[MockFunction]}
+    />
+    <Footer
+      total={1}
+    />
+  </DeferredSpinner>
 </div>
 `;
 
@@ -96,8 +107,10 @@ exports[`should render correctly: loading 1`] = `
     updateCenterActive={false}
     updateQuery={[Function]}
   />
-  <i
-    className="spinner"
-  />
+  <DeferredSpinner
+    loading={true}
+  >
+    marketplace.plugin_list.no_plugins.all
+  </DeferredSpinner>
 </div>
 `;
index 7d61696fff8d7a8c6e5b07c5f4fa5fdbd8c0ae4c..afb4e3092de2ce6eed0ced8864f31bfd7a5fd4e3 100644 (file)
@@ -2558,6 +2558,9 @@ marketplace.page.you_are_running.enterprise=You are currently running an Enterpr
 marketplace.page.you_are_running.datacenter=You are currently running a Data Center Edition.
 marketplace.page.plugins=Plugins
 marketplace.page.plugins.description=Plugins available in the MarketPlace are not provided or supported by SonarSource. Please reach out directly to their maintainers for support.
+marketplace.plugin_list.no_plugins.all=No installed plugins or updates available
+marketplace.plugin_list.no_plugins.installed=No installed plugins
+marketplace.plugin_list.no_plugins.updates=No plugin updates available
 marketplace.instance_needs_to_be_restarted_to={instance} needs to be restarted in order to
 marketplace.install_x_plugins=install {nb} plugins
 marketplace.update_x_plugins=update {nb} plugins