Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transition start execution running #1056

Merged
merged 11 commits into from
Dec 19, 2022
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 },
});
Comment on lines +9 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just requestExecution?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid this discussion now. We already have a tech debt ticket to talk about present/past term in the actions/events, etc

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;