Skip to content

Commit

Permalink
Transition start execution running (#1056)
Browse files Browse the repository at this point in the history
* Add setExecutionRequsted reducer function

* Include the new reducer in the saga

* Add some new cluster selector functions

* Dispatch execution requested with correct payload

* Manage loading state executions

* Navigate to correct wanda views in the fe

* Add test to execution trigger component

* Fix urlencode serialization

* Apply eslint fixes

* Use factorized/faked data in the trigger checks comp tests

* Replace usingWanda by usingNewChecksEngine
  • Loading branch information
arbulu89 committed Dec 19, 2022
1 parent 8772b43 commit ae6f0b8
Show file tree
Hide file tree
Showing 19 changed files with 281 additions and 48 deletions.
1 change: 1 addition & 0 deletions assets/js/components/ClusterDetails/ChecksSelectionNew.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function ChecksSelectionNew({ clusterId, cluster }) {
{localSavingSuccess && selectedChecks.length > 0 && (
<SuggestTriggeringChecksExecutionAfterSettingsUpdated
clusterId={clusterId}
usingNewChecksEngine
onClose={() => setLocalSavingSuccess(null)}
/>
)}
Expand Down
7 changes: 5 additions & 2 deletions assets/js/components/ClusterDetails/ClusterDetailsNew.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export function ClusterDetailsNew() {
type="primary-white"
className="w-1/4 mx-0.5 border-green-500 border"
size="small"
onClick={() => navigate(`/clusters/${clusterID}/settings_new`)}
onClick={() => navigate(`/clusters_new/${clusterID}/settings`)}
>
<EOS_SETTINGS className="inline-block fill-jungle-green-500" />{' '}
Settings
Expand All @@ -133,7 +133,9 @@ export function ClusterDetailsNew() {
type="primary-white"
className="w-1/4 mx-0.5 border-green-500 border"
size="small"
onClick={() => navigate(`/clusters/${clusterID}/checks/results`)}
onClick={() =>
navigate(`/clusters_new/${clusterID}/executions/last`)
}
>
<EOS_CLEAR_ALL className="inline-block fill-jungle-green-500" />{' '}
Show Results
Expand All @@ -142,6 +144,7 @@ export function ClusterDetailsNew() {
cssClasses="rounded relative w-1/4 ml-0.5 disabled:bg-slate-50 disabled:text-slate-500 disabled:border-gray-400"
clusterId={clusterID}
disabled={!hasSelectedChecks}
usingNewChecksEngine
>
<EOS_PLAY_CIRCLE
className={classNames('inline-block fill-jungle-green-500', {
Expand Down
14 changes: 11 additions & 3 deletions assets/js/components/ClusterDetails/ClusterSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ import { truncatedClusterNameClasses } from './ClusterDetails';

export const UNKNOWN_PROVIDER = 'unknown';

export function ClusterSettings({ newChecksSelectionView = false }) {
export function ClusterSettings({ usingNewChecksEngine = false }) {
const { clusterID } = useParams();

const cluster = useSelector(getCluster(clusterID));

const tabsSettings = {
'Checks Selection': newChecksSelectionView ? (
'Checks Selection': usingNewChecksEngine ? (
<ChecksSelectionNew clusterId={clusterID} cluster={cluster} />
) : (
<ChecksSelection clusterId={clusterID} cluster={cluster} />
Expand All @@ -40,7 +40,13 @@ export function ClusterSettings({ newChecksSelectionView = false }) {

return (
<div className="w-full px-2 sm:px-0">
<BackButton url={`/clusters/${clusterID}`}>
<BackButton
url={
usingNewChecksEngine
? `/clusters_new/${clusterID}`
: `/clusters/${clusterID}`
}
>
Back to Cluster Details
</BackButton>
<div className="flex mb-2">
Expand Down Expand Up @@ -117,6 +123,7 @@ export function SavingFailedAlert({ onClose = () => {}, children }) {

export function SuggestTriggeringChecksExecutionAfterSettingsUpdated({
clusterId,
usingNewChecksEngine = false,
onClose = () => {},
}) {
return (
Expand All @@ -131,6 +138,7 @@ export function SuggestTriggeringChecksExecutionAfterSettingsUpdated({
<TriggerChecksExecutionRequest
cssClasses="tn-checks-start-execute rounded-full group flex rounded-full items-center text-sm px-2 bg-jungle-green-500 text-white"
clusterId={clusterId}
usingNewChecksEngine={usingNewChecksEngine}
>
<EOS_PLAY_CIRCLE color="green" />
</TriggerChecksExecutionRequest>
Expand Down
12 changes: 3 additions & 9 deletions assets/js/components/ExecutionResults/ExecutionResults.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useState } from 'react';

import classNames from 'classnames';

Expand Down Expand Up @@ -47,7 +47,6 @@ function ExecutionResults({
catalogLoading,
catalog,
catalogError,
executionLoading,
executionData,
executionError,
onCatalogRefresh = () => {},
Expand All @@ -56,12 +55,7 @@ function ExecutionResults({
const [selectedCheck, setSelectedCheck] = useState(null);
const [modalOpen, setModalOpen] = useState(false);

useEffect(() => {
onCatalogRefresh();
onLastExecutionUpdate();
}, []);

if (catalogLoading || executionLoading) {
if (catalogLoading) {
return <LoadingBox text="Loading checks execution..." />;
}

Expand Down Expand Up @@ -100,7 +94,7 @@ function ExecutionResults({
{getCheckDescription(catalog, selectedCheck)}
</ReactMarkdown>
</Modal>
<BackButton url={`/clusters/${clusterID}`}>
<BackButton url={`/clusters_new/${clusterID}`}>
Back to Cluster Details
</BackButton>
<div className="flex mb-4 justify-between">
Expand Down
33 changes: 19 additions & 14 deletions assets/js/components/ExecutionResults/ExecutionResultsPage.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import { getCatalog } from '@state/selectors/catalog';
import { getLastExecution } from '@state/selectors/lastExecutions';
import { getCluster } from '@state/selectors';
import { updateCatalog } from '@state/actions/catalog';
import { updateLastExecution } from '@state/actions/lastExecutions';
import ExecutionResults from './ExecutionResults';

Expand All @@ -24,6 +25,20 @@ function ExecutionResultsPage() {
} = useSelector(getCatalog());
const lastExecution = useSelector(getLastExecution(clusterID));

useEffect(() => {
dispatch(updateCatalog());
}, []);

useEffect(() => {
if (lastExecution?.data?.status !== 'running') {
dispatch(updateLastExecution(clusterID));
}
}, []);

if (!cluster) {
return <div>Loading...</div>;
}

if (!lastExecution) {
return (
<h1 className="font-light font-sans text-center text-4xl text-gray-700">
Expand All @@ -32,30 +47,20 @@ function ExecutionResultsPage() {
);
}

const {
loading: executionLoading,
data: executionData,
error: executionError,
} = lastExecution;
const { data: executionData, error: executionError } = lastExecution;

return (
<ExecutionResults
clusterID={clusterID}
hostnames={hostnames}
clusterName={cluster?.name}
cloudProvider={cluster?.provider}
onCatalogRefresh={() =>
dispatch({
type: 'UPDATE_CATALOG',
payload: { provider: cluster?.provider },
})
}
onCatalogRefresh={() => dispatch(updateCatalog())}
onLastExecutionUpdate={() => dispatch(updateLastExecution(clusterID))}
catalogLoading={catalogLoading}
catalog={catalog}
catalogError={catalogError}
executionData={executionLoading}
ecutionData={executionData}
executionData={executionData}
executionError={executionError}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import React from 'react';
import classNames from 'classnames';
import { useDispatch } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';

export function TriggerChecksExecutionRequest({
import {
getClusterHostIDs,
getClusterSelectedChecks,
} from '@state/selectors/cluster';
import { executionRequested } from '@state/actions/lastExecutions';

function TriggerChecksExecutionRequest({
clusterId,
cssClasses,
usingNewChecksEngine = false,
children,
...props
}) {
const dispatch = useDispatch();
const navigate = useNavigate();
const hosts = useSelector(getClusterHostIDs(clusterId));
const checks = useSelector(getClusterSelectedChecks(clusterId));

return (
<button
Expand All @@ -20,13 +29,12 @@ export function TriggerChecksExecutionRequest({
)}
type="button"
onClick={() => {
dispatch({
type: 'REQUEST_CHECKS_EXECUTION',
payload: {
clusterID: clusterId,
},
});
navigate(`/clusters/${clusterId}/checks/results`);
dispatch(executionRequested(clusterId, hosts, checks));
navigate(
usingNewChecksEngine
? `/clusters_new/${clusterId}/executions/last`
: `/clusters/${clusterId}/checks/results`
);
}}
{...props}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';

import { screen, act } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { faker } from '@faker-js/faker';
import { withState, renderWithRouter } from '@lib/test-utils';

import { clusterFactory, hostFactory } from '@lib/test-utils/factories';

import TriggerChecksExecutionRequest from './TriggerChecksExecutionRequest';

describe('TriggerChecksExecutionRequest', () => {
it('should dispatch execution requested on click', async () => {
const user = userEvent.setup();
const cluster1 = clusterFactory.build({
selected_checks: [faker.datatype.uuid(), faker.datatype.uuid()],
});
const cluster2 = clusterFactory.build({
selected_checks: [faker.datatype.uuid(), faker.datatype.uuid()],
});
const { id: clusterID1, selected_checks: clusterSelectedChecks1 } =
cluster1;
const { id: clusterID2 } = cluster2;

const host1 = hostFactory.build({ cluster_id: clusterID1 });
const host2 = hostFactory.build({ cluster_id: clusterID1 });
const host3 = hostFactory.build({ cluster_id: clusterID2 });
const { id: hostID1 } = host1;
const { id: hostID2 } = host2;

const initialState = {
clustersList: {
clusters: [cluster1, cluster2],
},
hostsList: {
hosts: [host1, host2, host3],
},
};

const [statefulView, store] = withState(
<TriggerChecksExecutionRequest
clusterId={clusterID1}
usingNewChecksEngine
/>,
initialState
);

await act(async () => renderWithRouter(statefulView));

const button = screen.getByRole('button');
await user.click(button);

const actions = store.getActions();
const expectedActions = [
{
type: 'EXECUTION_REQUESTED',
payload: {
clusterID: clusterID1,
hosts: [hostID1, hostID2],
checks: clusterSelectedChecks1,
},
},
];
expect(actions).toEqual(expectedActions);
});
});
2 changes: 1 addition & 1 deletion assets/js/lib/serialization/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const keysToCamel = function keysToCamel(o) {
export const urlEncode = function urlEncode(params) {
const str = [];
Object.entries(params).forEach(([key, value]) => {
str.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[value])}`);
str.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
});
return str.join('&');
};
10 changes: 10 additions & 0 deletions assets/js/lib/serialization/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { urlEncode } from '.';

describe('Serialization', () => {
it('should encode the given params as url', async () => {
const url = urlEncode({ a: 'b', c: 'd', e: 'f' });
const expected = 'a=b&c=d&e=f';

expect(url).toEqual(expected);
});
});
5 changes: 5 additions & 0 deletions assets/js/lib/test-utils/factories/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ export const catalogFactory = Factory.define(() => ({
error: null,
}));

export const hostFactory = Factory.define(() => ({
id: faker.datatype.uuid(),
cluster_id: faker.datatype.uuid(),
}));

export const hostnameFactory = Factory.define(() => ({
id: faker.datatype.uuid(),
hostname: faker.hacker.noun(),
Expand Down
4 changes: 2 additions & 2 deletions assets/js/state/actions/cluster.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const checksSelectedAction = 'CHECKS_SELECTED';
export const CHECKS_SELECTED = 'CHECKS_SELECTED';

export const checksSelected = (selectedChecks, clusterID) => ({
type: checksSelectedAction,
type: CHECKS_SELECTED,
payload: { checks: selectedChecks, clusterID },
});
6 changes: 6 additions & 0 deletions assets/js/state/actions/lastExecutions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
export const UPDATE_LAST_EXECUTION = 'UPDATE_LAST_EXECUTION';
export const EXECUTION_REQUESTED = 'EXECUTION_REQUESTED';

export const updateLastExecution = (groupID) => ({
type: UPDATE_LAST_EXECUTION,
payload: { groupID },
});

export const executionRequested = (clusterID, hosts, checks) => ({
type: EXECUTION_REQUESTED,
payload: { clusterID, hosts, checks },
});
16 changes: 16 additions & 0 deletions assets/js/state/lastExecutions.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ export const lastExecutionsSlice = createSlice({
error,
};

state[groupID] = lastExecutionState;
},
setExecutionRequested: (state, { payload }) => {
const { clusterID: groupID, hosts, checks } = payload;

const targets = hosts.map((host) => ({ agent_id: host, checks }));

const lastExecutionState = {
...initialExecutionState,
data: {
status: 'running',
targets,
},
};

state[groupID] = lastExecutionState;
},
},
Expand All @@ -55,6 +70,7 @@ export const {
setLastExecution,
setLastExecutionEmpty,
setLastExecutionError,
setExecutionRequested,
} = lastExecutionsSlice.actions;

export default lastExecutionsSlice.reducer;

0 comments on commit ae6f0b8

Please sign in to comment.