Skip to content

Commit

Permalink
feat(ui): add analytics to all machine action forms
Browse files Browse the repository at this point in the history
  • Loading branch information
Caleb Ellis committed Nov 6, 2020
1 parent c9fb32b commit 1f189b9
Show file tree
Hide file tree
Showing 23 changed files with 693 additions and 141 deletions.
140 changes: 76 additions & 64 deletions ui/.betterer.results

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions ui/src/app/base/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ export type Sort = {
export type RouteParams = {
id: string;
};

export type AnalyticsEvent = {
action: string;
category: string;
label: string;
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import configureStore from "redux-mock-store";
import React from "react";
import type { RootState } from "app/store/root/types";

import * as hooks from "app/base/hooks";
import {
scripts as scriptsFactory,
machineAction as machineActionFactory,
machine as machineFactory,
generalState as generalStateFactory,
machine as machineFactory,
machineAction as machineActionFactory,
machineActionsState as machineActionsStateFactory,
machineState as machineStateFactory,
scriptsState as scriptsStateFactory,
rootState as rootStateFactory,
machineStatus as machineStatusFactory,
machineStatuses as machineStatusesFactory,
machineActionsState as machineActionsStateFactory,
rootState as rootStateFactory,
scripts as scriptsFactory,
scriptsState as scriptsStateFactory,
} from "testing/factories";
import CommissionForm from "./CommissionForm";

Expand All @@ -31,7 +32,7 @@ describe("CommissionForm", () => {
data: [
machineActionFactory({
name: "commission",
sentence: "commission",
title: "Commission",
}),
],
}),
Expand Down Expand Up @@ -247,4 +248,48 @@ describe("CommissionForm", () => {
},
]);
});

it("sends an analytics event on submit", () => {
const state = { ...initialState };
state.machine.selected = ["abc123"];
const mockSendAnalytics = jest.fn();
const mockUseSendAnalytics = (hooks.useSendAnalytics = jest.fn(
() => mockSendAnalytics
));
const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machines", key: "testKey" }]}
>
<CommissionForm setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

act(() =>
wrapper
.find("Formik")
.props()
.onSubmit({
enableSSH: true,
skipBMCConfig: true,
skipNetworking: true,
skipStorage: true,
updateFirmware: true,
configureHBA: true,
testingScripts: [state.scripts.items[0]],
commissioningScripts: [state.scripts.items[1]],
scriptInputs: { testingScript0: { url: "www.url.com" } },
})
);

expect(mockSendAnalytics).toHaveBeenCalled();
expect(mockSendAnalytics.mock.calls[0]).toEqual([
"Machine list",
"Submit action form",
"Commission",
]);
mockUseSendAnalytics.mockRestore();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
machine as machineActions,
scripts as scriptActions,
} from "app/base/actions";
import { useSendAnalytics } from "app/base/hooks";
import { useMachineActionForm } from "app/machines/hooks";
import { simpleSortByKey } from "app/utils";
import machineSelectors from "app/store/machine/selectors";
Expand Down Expand Up @@ -73,9 +74,12 @@ export const CommissionForm = ({ setSelectedAction }: Props): JSX.Element => {
);
const urlScripts = useSelector(scriptSelectors.testingWithUrl);
const testingScripts = useSelector(scriptSelectors.testing);
const { machinesToAction, processingCount } = useMachineActionForm(
"commission"
);
const sendAnalytics = useSendAnalytics();
const {
actionFormAnalytics,
machinesToAction,
processingCount,
} = useMachineActionForm("commission");

const preselectedTestingScripts = [
testingScripts.find((script) => script.name === "smartctl-validate"),
Expand Down Expand Up @@ -147,6 +151,11 @@ export const CommissionForm = ({ setSelectedAction }: Props): JSX.Element => {
)
);
});
sendAnalytics(
actionFormAnalytics.category,
actionFormAnalytics.action,
actionFormAnalytics.label
);
}}
processingCount={processingCount}
selectedCount={machinesToAction.length}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import {
configState as configStateFactory,
defaultMinHweKernelState as defaultMinHweKerelStateFactory,
generalState as generalStateFactory,
osInfoState as osInfoStateFactory,
rootState as rootStateFactory,
machine as machineFactory,
machineAction as machineActionFactory,
machineActionsState as machineActionsStateFactory,
machineState as machineStateFactory,
machineStatus as machineStatusFactory,
osInfoState as osInfoStateFactory,
rootState as rootStateFactory,
} from "testing/factories";

const mockStore = configureStore();
Expand Down Expand Up @@ -48,6 +50,14 @@ describe("DeployForm", () => {
data: "ga-18.04",
loaded: true,
}),
machineActions: machineActionsStateFactory({
data: [
machineActionFactory({
name: "deploy",
title: "Deploy",
}),
],
}),
osInfo: osInfoStateFactory({
data: {
osystems: [
Expand Down Expand Up @@ -338,10 +348,13 @@ describe("DeployForm", () => {
]);
});

it("sends an event if cloud-init is set", () => {
it("sends an analytics event without cloud-init user data set", () => {
const state = { ...initialState };
state.machine.selected = ["abc123"];
const useSendMock = jest.spyOn(hooks, "useSendAnalytics");
const mockSendAnalytics = jest.fn();
const mockUseSendAnalytics = (hooks.useSendAnalytics = jest.fn(
() => mockSendAnalytics
));
const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
Expand All @@ -352,6 +365,45 @@ describe("DeployForm", () => {
</MemoryRouter>
</Provider>
);

act(() =>
wrapper.find("Formik").props().onSubmit({
includeUserData: true,
installKVM: false,
kernel: "",
oSystem: "ubuntu",
release: "bionic",
userData: "",
})
);

expect(mockSendAnalytics).toHaveBeenCalled();
expect(mockSendAnalytics.mock.calls[0]).toEqual([
"Machine list",
"Submit action form",
"Deploy",
]);
mockUseSendAnalytics.mockRestore();
});

it("sends an analytics event with cloud-init user data set", () => {
const state = { ...initialState };
state.machine.selected = ["abc123"];
const mockSendAnalytics = jest.fn();
const mockUseSendAnalytics = (hooks.useSendAnalytics = jest.fn(
() => mockSendAnalytics
));
const store = mockStore(state);
const wrapper = mount(
<Provider store={store}>
<MemoryRouter
initialEntries={[{ pathname: "/machines", key: "testKey" }]}
>
<DeployForm setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);

act(() =>
wrapper.find("Formik").props().onSubmit({
includeUserData: true,
Expand All @@ -362,6 +414,13 @@ describe("DeployForm", () => {
userData: "test script",
})
);
expect(useSendMock).toHaveBeenCalled();

expect(mockSendAnalytics).toHaveBeenCalled();
expect(mockSendAnalytics.mock.calls[0]).toEqual([
"Machine list",
"Submit action form with cloud-init user data",
"Deploy",
]);
mockUseSendAnalytics.mockRestore();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ export const DeployForm = ({ setSelectedAction }: Props): JSX.Element => {
generalSelectors.defaultMinHweKernel.loaded
);
const osInfoLoaded = useSelector(generalSelectors.osInfo.loaded);
const { machinesToAction, processingCount } = useMachineActionForm("deploy");
const sendAnalytics = useSendAnalytics();
const {
actionFormAnalytics,
machinesToAction,
processingCount,
} = useMachineActionForm("deploy");

useEffect(() => {
dispatch(generalActions.fetchDefaultMinHweKernel());
Expand All @@ -77,8 +82,6 @@ export const DeployForm = ({ setSelectedAction }: Props): JSX.Element => {
initialRelease = default_release;
}

const sendAnalytics = useSendAnalytics();

return (
<ActionForm
actionName="deploy"
Expand Down Expand Up @@ -107,9 +110,15 @@ export const DeployForm = ({ setSelectedAction }: Props): JSX.Element => {
};
if (hasUserData) {
sendAnalytics(
"Machine list deploy form",
"Has cloud-init config",
"Cloud-init user data"
actionFormAnalytics.category,
"Submit action form with cloud-init user data",
actionFormAnalytics.label
);
} else {
sendAnalytics(
actionFormAnalytics.category,
actionFormAnalytics.action,
actionFormAnalytics.label
);
}
machinesToAction.forEach((machine) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { MemoryRouter } from "react-router-dom";
import React from "react";
import { Provider } from "react-redux";

import { machine as machineFactory } from "testing/factories";
import {
generalState as generalStateFactory,
machine as machineFactory,
} from "testing/factories";
import { TSFixMe } from "app/base/types";
import DeployForm from "../../DeployForm";

Expand Down Expand Up @@ -61,7 +64,7 @@ describe("DeployFormFields", () => {
loaded: true,
loading: false,
},
general: {
general: generalStateFactory({
defaultMinHweKernel: {
data: "",
errors: {},
Expand Down Expand Up @@ -106,7 +109,7 @@ describe("DeployFormFields", () => {
loaded: true,
loading: false,
},
},
}),
machine: {
errors: {},
loading: false,
Expand Down Expand Up @@ -147,11 +150,7 @@ describe("DeployFormFields", () => {
wrapper = mount(
<Provider store={store}>
<MemoryRouter initialEntries={[{ pathname: "/" }]}>
<DeployForm
processing={false}
setProcessing={jest.fn()}
setSelectedAction={jest.fn()}
/>
<DeployForm setSelectedAction={jest.fn()} />
</MemoryRouter>
</Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from "react";

import { kebabToCamelCase } from "app/utils";
import { machine as machineActions } from "app/base/actions";
import { useSendAnalytics } from "app/base/hooks";
import { useMachineActionForm } from "app/machines/hooks";
import machineSelectors from "app/store/machine/selectors";
import ActionForm from "app/base/components/ActionForm";
Expand All @@ -29,9 +30,12 @@ const fieldlessActions = [
export const FieldlessForm = ({ selectedAction, setSelectedAction }) => {
const dispatch = useDispatch();
const errors = useSelector(machineSelectors.errors);
const { machinesToAction, processingCount } = useMachineActionForm(
selectedAction.name
);
const sendAnalytics = useSendAnalytics();
const {
actionFormAnalytics,
machinesToAction,
processingCount,
} = useMachineActionForm(selectedAction.name);

return (
<ActionForm
Expand All @@ -47,6 +51,11 @@ export const FieldlessForm = ({ selectedAction, setSelectedAction }) => {
machinesToAction.forEach((machine) => {
dispatch(machineActions[actionMethod](machine.system_id));
});
sendAnalytics(
actionFormAnalytics.category,
actionFormAnalytics.action,
actionFormAnalytics.label
);
}
}}
processingCount={processingCount}
Expand Down
Loading

0 comments on commit 1f189b9

Please sign in to comment.