From fb1073b0ae318562962f301d0160739718de9283 Mon Sep 17 00:00:00 2001
From: Alessio Biancalana <alessio.biancalana@suse.com>
Date: Wed, 15 Nov 2023 17:06:23 +0100
Subject: [PATCH 1/3] Pass props down to ASCS/ERS component

---
 .../components/ClusterDetails/ClusterDetailsPage.jsx   | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/assets/js/components/ClusterDetails/ClusterDetailsPage.jsx b/assets/js/components/ClusterDetails/ClusterDetailsPage.jsx
index f043c04a6a..de05aad30b 100644
--- a/assets/js/components/ClusterDetails/ClusterDetailsPage.jsx
+++ b/assets/js/components/ClusterDetails/ClusterDetailsPage.jsx
@@ -91,13 +91,23 @@ export function ClusterDetailsPage() {
     case 'ascs_ers':
       return (
         <AscsErsClusterDetails
+          clusterID={clusterID}
           clusterName={getClusterName(cluster)}
+          selectedChecks={cluster.selected_checks}
+          hasSelectedChecks={hasSelectedChecks}
           cibLastWritten={cluster.cib_last_written}
           provider={cluster.provider}
           hosts={clusterHosts}
           sapSystems={clusterSapSystems}
           details={cluster.details}
           catalog={catalog}
+          lastExecution={lastExecution}
+          onStartExecution={(_, hostList, checks, navigateFunction) =>
+            dispatch(
+              executionRequested(clusterID, hostList, checks, navigateFunction)
+            )
+          }
+          navigate={navigate}
         />
       );
     default:

From 652eabf20e4759ec7d814b87f29f30be62e826bd Mon Sep 17 00:00:00 2001
From: Alessio Biancalana <alessio.biancalana@suse.com>
Date: Wed, 15 Nov 2023 17:07:37 +0100
Subject: [PATCH 2/3] Add buttons for checks selection and navigation

---
 .../ClusterDetails/AscsErsClusterDetails.jsx  | 76 ++++++++++++++++++-
 1 file changed, 73 insertions(+), 3 deletions(-)

diff --git a/assets/js/components/ClusterDetails/AscsErsClusterDetails.jsx b/assets/js/components/ClusterDetails/AscsErsClusterDetails.jsx
index 7ee426b07a..b1bf87c231 100644
--- a/assets/js/components/ClusterDetails/AscsErsClusterDetails.jsx
+++ b/assets/js/components/ClusterDetails/AscsErsClusterDetails.jsx
@@ -1,6 +1,10 @@
 import React, { useState, useEffect } from 'react';
 import { get } from 'lodash';
+import { EOS_SETTINGS, EOS_CLEAR_ALL, EOS_PLAY_CIRCLE } from 'eos-icons-react';
 
+import { RUNNING_STATES } from '@state/lastExecutions';
+
+import Button from '@components/Button';
 import PageHeader from '@components/PageHeader';
 import BackButton from '@components/BackButton';
 import Table from '@components/Table';
@@ -10,6 +14,7 @@ import DottedPagination from '@components/DottedPagination';
 import ClusterNodeLink from '@components/ClusterDetails/ClusterNodeLink';
 import SapSystemLink from '@components/SapSystemLink';
 import { renderEnsaVersion } from '@components/SapSystemDetails';
+import Tooltip from '@components/Tooltip';
 
 import CheckResultsOverview from '@components/CheckResultsOverview';
 
@@ -65,13 +70,19 @@ const nodeDetailsConfig = {
 };
 
 function AscsErsClusterDetails({
+  clusterID,
   clusterName,
+  selectedChecks,
+  hasSelectedChecks,
   cibLastWritten,
   provider,
   hosts,
   sapSystems,
   details,
   catalog,
+  lastExecution,
+  onStartExecution,
+  navigate,
 }) {
   const [enrichedSapSystems, setEnrichedSapSystems] = useState([]);
   const [currentSapSystem, setCurrentSapSystem] = useState(null);
@@ -91,6 +102,15 @@ function AscsErsClusterDetails({
   const catalogLoading = get(catalog, 'loading');
   const catalogError = get(catalog, 'error');
 
+  const executionData = get(lastExecution, 'data');
+  const executionLoading = get(lastExecution, 'loading', true);
+  const executionError = get(lastExecution, 'error');
+
+  const startExecutionDisabled =
+    executionLoading ||
+    !hasSelectedChecks ||
+    RUNNING_STATES.includes(executionData?.status);
+
   return (
     <div>
       <BackButton url="/clusters">Back to Clusters</BackButton>
@@ -101,6 +121,51 @@ function AscsErsClusterDetails({
             <span className="font-bold">{clusterName}</span>
           </PageHeader>
         </div>
+        <div className="flex w-1/2 justify-end">
+          <div className="flex w-fit whitespace-nowrap">
+            <Button
+              type="primary-white"
+              className="inline-block mx-0.5 border-green-500 border"
+              size="small"
+              onClick={() => navigate(`/clusters/${clusterID}/settings`)}
+            >
+              <EOS_SETTINGS className="inline-block fill-jungle-green-500" />{' '}
+              Check Selection
+            </Button>
+
+            <Button
+              type="primary-white"
+              className="mx-0.5 border-green-500 border"
+              size="small"
+              onClick={() => navigate(`/clusters/${clusterID}/executions/last`)}
+            >
+              <EOS_CLEAR_ALL className="inline-block fill-jungle-green-500" />{' '}
+              Show Results
+            </Button>
+
+            <Tooltip
+              isEnabled={!hasSelectedChecks}
+              content="Select some Checks first!"
+              place="bottom"
+            >
+              <Button
+                type="primary"
+                className="mx-1"
+                onClick={() => {
+                  onStartExecution(clusterID, hosts, selectedChecks, navigate);
+                }}
+                disabled={startExecutionDisabled}
+              >
+                <EOS_PLAY_CIRCLE
+                  className={`${
+                    !startExecutionDisabled ? 'fill-white' : 'fill-gray-200'
+                  } inline-block align-sub`}
+                />{' '}
+                Start Execution
+              </Button>
+            </Tooltip>
+          </div>
+        </div>
       </div>
       <div className="flex xl:flex-row flex-col">
         <div className="mt-4 bg-white shadow rounded-lg py-8 px-8 xl:w-2/5 mr-4">
@@ -174,10 +239,15 @@ function AscsErsClusterDetails({
         </div>
         <div className="mt-4 bg-white shadow rounded-lg py-4 xl:w-1/4">
           <CheckResultsOverview
+            data={executionData}
             catalogDataEmpty={catalogData?.length === 0}
-            loading={catalogLoading}
-            error={catalogError}
-            onCheckClick={() => {}}
+            loading={catalogLoading || executionLoading}
+            error={catalogError || executionError}
+            onCheckClick={(health) =>
+              navigate(
+                `/clusters/${clusterID}/executions/last?health=${health}`
+              )
+            }
           />
         </div>
       </div>

From 999bc48e71b7edf0dfe9914cfd0e173b97fbfeec Mon Sep 17 00:00:00 2001
From: Alessio Biancalana <alessio.biancalana@suse.com>
Date: Wed, 15 Nov 2023 17:08:01 +0100
Subject: [PATCH 3/3] Add tests

---
 .../AscsErsClusterDetails.test.jsx            | 129 ++++++++++++++++++
 1 file changed, 129 insertions(+)

diff --git a/assets/js/components/ClusterDetails/AscsErsClusterDetails.test.jsx b/assets/js/components/ClusterDetails/AscsErsClusterDetails.test.jsx
index d64a881cdb..7481dee862 100644
--- a/assets/js/components/ClusterDetails/AscsErsClusterDetails.test.jsx
+++ b/assets/js/components/ClusterDetails/AscsErsClusterDetails.test.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
 
+import { faker } from '@faker-js/faker';
 import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import '@testing-library/jest-dom';
@@ -7,10 +8,13 @@ import '@testing-library/jest-dom';
 import { renderWithRouter } from '@lib/test-utils';
 
 import {
+  hostFactory,
   buildHostsFromAscsErsClusterDetails,
   buildSapSystemsFromAscsErsClusterDetails,
   ascsErsClusterDetailsFactory,
   clusterFactory,
+  checksExecutionCompletedFactory,
+  checksExecutionRunningFactory,
 } from '@lib/test-utils/factories';
 
 import { providerData } from '@components/ProviderLabel/ProviderLabel';
@@ -275,4 +279,129 @@ describe('ClusterDetails AscsErsClusterDetails component', () => {
       });
     });
   });
+
+  it('should suggest to the user to select some checks if the selection is empty', async () => {
+    const user = userEvent.setup();
+
+    const {
+      clusterID,
+      clusterName,
+      cib_last_written: cibLastWritten,
+      type: clusterType,
+      sid,
+      provider,
+      details,
+    } = clusterFactory.build({ type: 'ascs_ers' });
+
+    const hosts = hostFactory.buildList(2, { cluster_id: clusterID });
+
+    renderWithRouter(
+      <AscsErsClusterDetails
+        clusterID={clusterID}
+        clusterName={clusterName}
+        selectedChecks={[]}
+        hasSelectedChecks={false}
+        hosts={hosts}
+        clusterType={clusterType}
+        cibLastWritten={cibLastWritten}
+        sid={sid}
+        provider={provider}
+        sapSystems={[]}
+        details={details}
+        lastExecution={null}
+      />
+    );
+
+    const startExecutionButton = screen.getByText('Start Execution');
+    await user.hover(startExecutionButton);
+    expect(screen.queryByText('Select some Checks first!')).toBeVisible();
+  });
+
+  const executionId = faker.string.uuid();
+
+  const executionScenarios = [
+    {
+      name: 'Execution is being loaded from wanda',
+      selectedChecks: ['some'],
+      hasSelectedChecks: true,
+      lastExecution: { data: null, loading: true, error: null },
+    },
+    {
+      name: 'No checks were selected',
+      selectedChecks: [],
+      hasSelectedChecks: false,
+      lastExecution: {
+        data: checksExecutionCompletedFactory.build({
+          execution_id: executionId,
+        }),
+        loading: false,
+        error: null,
+      },
+    },
+    {
+      name: 'Execution is still running',
+      selectedChecks: ['A123'],
+      hasSelectedChecks: true,
+      lastExecution: {
+        data: checksExecutionRunningFactory.build({
+          execution_id: executionId,
+        }),
+        loading: false,
+        error: null,
+      },
+    },
+    {
+      name: 'Execution has been requested',
+      selectedChecks: ['A123'],
+      hasSelectedChecks: true,
+      lastExecution: {
+        data: {
+          execution_id: executionId,
+          status: 'requested',
+        },
+        loading: false,
+        error: null,
+      },
+    },
+  ];
+
+  it.each(executionScenarios)(
+    'should disable starting a new execution when $name',
+    ({ selectedChecks, hasSelectedChecks, lastExecution }) => {
+      const hanaCluster = clusterFactory.build({
+        type: 'ascs_ers',
+      });
+
+      const {
+        clusterID,
+        clusterName,
+        cib_last_written: cibLastWritten,
+        type: clusterType,
+        sid,
+        provider,
+        details,
+      } = hanaCluster;
+
+      const hosts = hostFactory.buildList(2, { cluster_id: clusterID });
+
+      renderWithRouter(
+        <AscsErsClusterDetails
+          clusterID={clusterID}
+          clusterName={clusterName}
+          selectedChecks={selectedChecks}
+          hasSelectedChecks={hasSelectedChecks}
+          hosts={hosts}
+          clusterType={clusterType}
+          cibLastWritten={cibLastWritten}
+          sid={sid}
+          provider={provider}
+          sapSystems={[]}
+          details={details}
+          lastExecution={lastExecution}
+        />
+      );
+
+      expect(screen.getByText('Start Execution')).toBeDisabled();
+    }
+  );
 });