diff --git a/package-lock.json b/package-lock.json
index 1ddc5412..1fb7ea5f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9116,6 +9116,11 @@
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
},
+ "deep-diff": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz",
+ "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg=="
+ },
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -10613,6 +10618,11 @@
}
}
},
+ "exenv": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
+ "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
+ },
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -12694,6 +12704,11 @@
}
}
},
+ "is-lite": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.8.1.tgz",
+ "integrity": "sha512-ekSwuewzOmwFnzzAOWuA5fRFPqOeTrLIL3GWT7hdVVi+oLuD+Rau8gCmkb94vH5hjXc1Q/CfIW/y/td1RrNQIg=="
+ },
"is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@@ -16192,6 +16207,11 @@
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "nested-property": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz",
+ "integrity": "sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA=="
+ },
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
@@ -18553,6 +18573,40 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
"integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew=="
},
+ "react-floater": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.3.tgz",
+ "integrity": "sha512-d1wAEph+xRxQ0RJ3woMmYLlZHTaCIsja7Bv6JNo2ezsVUgdMan4CxOR4Do4/xgpmRFfsQMdlygexLAZZypWirw==",
+ "requires": {
+ "deepmerge": "^4.2.2",
+ "exenv": "^1.2.2",
+ "is-lite": "^0.8.1",
+ "popper.js": "^1.16.0",
+ "react-proptype-conditional-require": "^1.0.4",
+ "tree-changes": "^0.5.1"
+ },
+ "dependencies": {
+ "nested-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-1.0.1.tgz",
+ "integrity": "sha512-BnBBoo/8bBNRdAnJc7+m79oWk7dXwW1+vCesaEQhfDGVwXGLMvmI4NwYgLTW94R/x+R2s/yr2g/hB/4w/YSAvA=="
+ },
+ "popper.js": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
+ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
+ },
+ "tree-changes": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.5.1.tgz",
+ "integrity": "sha512-O873xzV2xRZ6N059Mn06QzmGKEE21LlvIPbsk2G+GS9ZX5OCur6PIwuuh0rWpAPvLWQZPj0XObyG27zZyLHUzw==",
+ "requires": {
+ "deep-diff": "^1.0.2",
+ "nested-property": "1.0.1"
+ }
+ }
+ }
+ },
"react-form-validator-core": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/react-form-validator-core/-/react-form-validator-core-1.0.0.tgz",
@@ -18577,6 +18631,23 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-joyride": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/react-joyride/-/react-joyride-2.3.1.tgz",
+ "integrity": "sha512-MmyhECU3V+4kZAJrcDPPXcXxaoTpwc7g+E7Cq6QZ5IqJZrWYSVvpVCfudQcdcf6BsNbgawRhvCvbQyeWoPtNig==",
+ "requires": {
+ "deep-diff": "^1.0.2",
+ "deepmerge": "^4.2.2",
+ "exenv": "^1.2.2",
+ "is-lite": "^0.8.1",
+ "nested-property": "^4.0.0",
+ "react-floater": "^0.7.3",
+ "react-is": "^16.13.1",
+ "scroll": "^3.0.1",
+ "scrollparent": "^2.0.1",
+ "tree-changes": "^0.7.1"
+ }
+ },
"react-konva": {
"version": "16.13.0-3",
"resolved": "https://registry.npmjs.org/react-konva/-/react-konva-16.13.0-3.tgz",
@@ -18600,6 +18671,11 @@
"react-form-validator-core": "1.0.0"
}
},
+ "react-proptype-conditional-require": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz",
+ "integrity": "sha1-acLVdB5t9eCPIw82u8KUTuEiJVU="
+ },
"react-reconciler": {
"version": "0.25.1",
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.25.1.tgz",
@@ -19819,6 +19895,16 @@
"ajv-keywords": "^3.5.2"
}
},
+ "scroll": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz",
+ "integrity": "sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg=="
+ },
+ "scrollparent": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz",
+ "integrity": "sha1-cV1bnMV3YPsivczDvvtb/gaxoxc="
+ },
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -20922,9 +21008,9 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
},
"tar": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
- "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
+ "version": "6.1.6",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.6.tgz",
+ "integrity": "sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g==",
"requires": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
@@ -21300,6 +21386,15 @@
"punycode": "^2.1.1"
}
},
+ "tree-changes": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.7.1.tgz",
+ "integrity": "sha512-sPIt8PKDi0OQTglr7lsetcB9DU19Ls/ZgFSjFvK6DWJGisAn4sOxtjpmQfuqjexQE4UU9U53LNmataL1kRJ3Uw==",
+ "requires": {
+ "fast-deep-equal": "^3.1.3",
+ "is-lite": "^0.8.1"
+ }
+ },
"tryer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
@@ -22057,8 +22152,7 @@
},
"ssri": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
- "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
+ "resolved": "",
"requires": {
"figgy-pudding": "^3.5.1"
}
diff --git a/package.json b/package.json
index 85c2b84a..e44c7e86 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"react-debounce-input": "^3.2.2",
"react-dom": "^16.13.1",
"react-hotkeys-hook": "^2.4.0",
+ "react-joyride": "^2.3.1",
"react-konva": "^16.13.0-3",
"react-material-ui-form-validator": "^2.1.1",
"react-router-dom": "^5.2.0",
diff --git a/src/App.jsx b/src/App.jsx
index 94bf8867..c0ebb34c 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -8,6 +8,7 @@ import {
BuildProvider,
TestRunProvider,
SocketProvider,
+ HelpProvider,
} from "./contexts";
import Router from "./Router";
@@ -19,12 +20,14 @@ function App() {
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/src/_test/test.moun.helper.tsx b/src/_test/test.moun.helper.tsx
index a08bcc22..002258c0 100644
--- a/src/_test/test.moun.helper.tsx
+++ b/src/_test/test.moun.helper.tsx
@@ -5,6 +5,7 @@ import {
UserProvider,
BuildProvider,
TestRunProvider,
+ HelpProvider,
} from "../contexts";
import { MemoryRouter, Route } from "react-router-dom";
import { MemoryRouterProps } from "react-router";
@@ -26,7 +27,9 @@ export const mountVrtComponent = ({
- {component}
+
+ {component}
+
diff --git a/src/components/BuildDetails.tsx b/src/components/BuildDetails.tsx
index 6a001e31..47901b52 100644
--- a/src/components/BuildDetails.tsx
+++ b/src/components/BuildDetails.tsx
@@ -9,6 +9,7 @@ import {
import { BuildStatusChip } from "./BuildStatusChip";
import { formatDateTime } from "../_helpers/format.helper";
import { useBuildState } from "../contexts";
+import { LOCATOR_BUILD_DETAILS } from '../constants/help';
const BuildDetails: React.FunctionComponent = () => {
const { selectedBuild } = useBuildState();
@@ -20,7 +21,7 @@ const BuildDetails: React.FunctionComponent = () => {
const loadingAnimation = selectedBuild.isRunning && ;
return (
-
+
diff --git a/src/components/Filters.tsx b/src/components/Filters.tsx
index 81bc61e2..5647aea5 100644
--- a/src/components/Filters.tsx
+++ b/src/components/Filters.tsx
@@ -10,6 +10,7 @@ import {
} from "@material-ui/core";
import { TestRun, TestVariation } from "../types";
import { DebounceInput } from "react-debounce-input";
+import { LOCATOR_RESET_FILTER } from "../constants/help";
interface IProps {
items: (TestRun | TestVariation)[];
@@ -239,7 +240,7 @@ const Filters: React.FunctionComponent = ({
)}
{branchNameList && branchNameList.length > 0 && (
-
+
Branch
diff --git a/src/components/GuidedTour.tsx b/src/components/GuidedTour.tsx
new file mode 100644
index 00000000..febc74aa
--- /dev/null
+++ b/src/components/GuidedTour.tsx
@@ -0,0 +1,69 @@
+import React, { FunctionComponent } from "react";
+import Joyride, { CallBackProps, STATUS } from "react-joyride";
+import { IconButton, Avatar } from "@material-ui/core";
+import { HelpOutline } from "@material-ui/icons";
+import { useHelpState } from "../contexts";
+
+const GuidedTour: FunctionComponent = () => {
+ const [run, setRun] = React.useState(false);
+ const { helpSteps } = useHelpState();
+
+ const getHelpSteps = React.useCallback(() => {
+ const firstStep = helpSteps[0];
+ //Below line is to prevent application breaking if element is not present for any reason (e.g. if the user deletes build or if there is no data.)
+ if (
+ firstStep &&
+ document.getElementById(firstStep.target.toString().slice(1))
+ ) {
+ helpSteps.forEach((e) => {
+ e.disableBeacon = true;
+ e.hideCloseButton = true;
+ });
+ return helpSteps;
+ }
+ return [];
+ }, [helpSteps]);
+
+ const handleJoyrideCallback = (data: CallBackProps) => {
+ const { status } = data;
+ const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED];
+
+ if (finishedStatuses.includes(status)) {
+ setRun(false);
+ }
+ };
+
+ const handleClickStart = (e: React.MouseEvent) => {
+ e.preventDefault();
+ setRun(true);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default GuidedTour;
diff --git a/src/components/Header.spec.tsx b/src/components/Header.spec.tsx
index efceff16..7dbda17a 100644
--- a/src/components/Header.spec.tsx
+++ b/src/components/Header.spec.tsx
@@ -1,36 +1,25 @@
/* global cy */
import React from "react";
-import { mount } from "@cypress/react";
import Header from "./Header";
-import { UserProvider } from "../contexts";
-import { BrowserRouter } from "react-router-dom";
import { haveUserLogged } from "../_test/precondition.helper";
-import { TEST_USER } from "../_test/test.data.helper";
+import { TEST_PROJECT, TEST_USER } from "../_test/test.data.helper";
+import { mountVrtComponent } from "../_test/test.moun.helper";
+import { projectStub } from "../_test/stub.helper";
describe("Header", () => {
describe("image", () => {
it("Guest", () => {
localStorage.clear();
- mount(
-
-
-
-
-
- );
+ mountVrtComponent({ component: });
cy.get("#__cy_root").vrtTrack("Header. Guest");
});
it("Logged", () => {
haveUserLogged(TEST_USER);
- mount(
-
-
-
-
-
- );
+ projectStub.getAll([TEST_PROJECT]);
+
+ mountVrtComponent({ component: });
cy.get("#__cy_root").vrtTrack("Header. Logged");
});
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 5f86d24c..290688e2 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -12,6 +12,7 @@ import { Link } from "react-router-dom";
import { useUserDispatch, useUserState, logout } from "../contexts";
import { routes } from "../constants";
import logo from "../static/logo.png";
+import GuidedTour from "./GuidedTour";
const Header: FunctionComponent = () => {
const [menuRef, setMenuRef] = React.useState(null);
@@ -78,15 +79,18 @@ const Header: FunctionComponent = () => {
- {loggedIn && (
- ) =>
- setMenuRef(event.currentTarget)
- }
- >
- {`${user?.firstName[0]}${user?.lastName[0]}`}
-
- )}
+
+
+ {loggedIn && (
+ ) =>
+ setMenuRef(event.currentTarget)
+ }
+ >
+ {`${user?.firstName[0]}${user?.lastName[0]}`}
+
+ )}
+
diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx
index 21cd591e..3b7c7429 100644
--- a/src/components/LoginForm.tsx
+++ b/src/components/LoginForm.tsx
@@ -9,7 +9,7 @@ import {
Typography,
} from "@material-ui/core";
import { useUserDispatch, login } from "../contexts";
-import { routes } from "../constants";
+import { LOCATOR_LOGIN_FORM, routes } from "../constants";
import { useSnackbar } from "notistack";
import { TextValidator, ValidatorForm } from "react-material-ui-form-validator";
@@ -33,7 +33,7 @@ const LoginForm = () => {
return (
-
+
= ({
/>
-
diff --git a/src/constants/help.ts b/src/constants/help.ts
new file mode 100644
index 00000000..4b1306ff
--- /dev/null
+++ b/src/constants/help.ts
@@ -0,0 +1,79 @@
+import { Step } from "react-joyride";
+
+export const LOCATOR_LOGIN_FORM = "loginform-1";
+export const LOCATOR_BUILD_DETAILS = "build-details";
+export const LOCATOR_RESET_FILTER = "reset-filter";
+export const LOCATOR_TEST_VARIATION_SELECT_BRANCH = "select-branch";
+export const LOCATOR_PROJECT_LIST_PAGE_PROJECT_LIST = "projectlist-1";
+export const LOCATOR_PROJECT_PAGE_SELECT_PROJECT = "select-project";
+export const LOCATOR_PROJECT_PAGE_BUILD_LIST = "build-list";
+export const LOCATOR_PROJECT_PAGE_BUILD_DETAILS = "build-details";
+export const LOCATOR_PROJECT_PAGE_TEST_RUN_LIST = "test-run-list";
+export const LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_PROJECT = "select-project";
+export const LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_BRANCH = "select-branch";
+export const LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_RESET_FILTER =
+ "reset-filter";
+
+export const LOGIN_PAGE_STEPS: Step[] = [
+ {
+ target: `#${LOCATOR_LOGIN_FORM}`,
+ content:
+ "Default admin account: visual-regression-tracker@example.com / 123456. Make sure to change default password.",
+ },
+ {
+ target: `#${LOCATOR_LOGIN_FORM}`,
+ content: "Create new account without restrictions.",
+ },
+];
+
+export const PROJECT_LIST_PAGE_STEPS: Step[] = [
+ {
+ target: `#${LOCATOR_PROJECT_LIST_PAGE_PROJECT_LIST}`,
+ content:
+ "Default project is created after first start, feel free to edit/add/delete projects.",
+ title: "Project List",
+ },
+];
+
+export const PROJECT_PAGE_STEPS: Step[] = [
+ {
+ target: "#" + LOCATOR_PROJECT_PAGE_SELECT_PROJECT,
+ content: "Select the project for which you want to view details.",
+ },
+ {
+ target: "#" + LOCATOR_PROJECT_PAGE_BUILD_LIST,
+ content: "List of Builds",
+ },
+ {
+ target: "#" + LOCATOR_PROJECT_PAGE_BUILD_LIST,
+ content:
+ "If you see 'No Builds', please run your image comparison from any client.",
+ },
+ {
+ target: "#" + LOCATOR_PROJECT_PAGE_BUILD_DETAILS,
+ content: "Breif details for selected build.",
+ },
+ {
+ target: "#" + LOCATOR_PROJECT_PAGE_TEST_RUN_LIST,
+ content: "TestRuns for selected build.",
+ },
+];
+
+export const TEST_VARIATION_LIST_PAGE = [
+ {
+ target: "#" + LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_PROJECT,
+ title:
+ "Shows all the historical record of baselines by Name + Branch + OS + Browser + Viewport + Device",
+ content: "Select the project you want to act on.",
+ },
+ {
+ target: "#" + LOCATOR_TEST_VARIATION_SELECT_BRANCH,
+ title: "Merge from one branch to another",
+ content:
+ "Select the branch from/to which you want to merge the variations.",
+ },
+ {
+ target: "#" + LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_RESET_FILTER,
+ content: "Only filtered items are displayed/merged to the target branch.",
+ },
+];
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 3e2e87b6..1d59c57e 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -1,2 +1,3 @@
export * from "./routes";
export * from "./project";
+export * from "./help";
diff --git a/src/contexts/help.context.tsx b/src/contexts/help.context.tsx
new file mode 100644
index 00000000..741d1b54
--- /dev/null
+++ b/src/contexts/help.context.tsx
@@ -0,0 +1,69 @@
+import React from "react";
+import { Step } from "react-joyride";
+
+interface ISetStepAction {
+ type: "setSteps";
+ payload: Array;
+}
+
+type IAction = ISetStepAction;
+
+type Dispatch = (action: IAction) => void;
+type State = {
+ helpSteps: Array;
+};
+
+type HelpProviderProps = { children: React.ReactNode };
+
+const StateContext = React.createContext(undefined);
+const DispatchContext = React.createContext(undefined);
+
+const initialState: State = {
+ helpSteps: [],
+};
+
+function reducer(state: State, action: IAction): State {
+ switch (action.type) {
+ case "setSteps":
+ return {
+ ...state,
+ helpSteps: action.payload,
+ };
+ default:
+ return state;
+ }
+}
+
+function HelpProvider({ children }: HelpProviderProps) {
+ const [state, dispatch] = React.useReducer(reducer, initialState);
+
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+function useHelpState() {
+ const context = React.useContext(StateContext);
+ if (context === undefined) {
+ throw new Error("must be used within a HelpContext");
+ }
+ return context;
+}
+
+function useHelpDispatch() {
+ const context = React.useContext(DispatchContext);
+ if (context === undefined) {
+ throw new Error("must be used within a HelpContext");
+ }
+ return context;
+}
+
+function setHelpSteps(dispatch: Dispatch, data: Array) {
+ dispatch({ type: "setSteps", payload: data });
+}
+
+export { HelpProvider, useHelpDispatch, useHelpState, setHelpSteps };
diff --git a/src/contexts/index.ts b/src/contexts/index.ts
index c2e448ad..690917a4 100644
--- a/src/contexts/index.ts
+++ b/src/contexts/index.ts
@@ -3,3 +3,4 @@ export * from "./build.context";
export * from "./project.context";
export * from "./testRun.context";
export * from "./socket.context";
+export * from "./help.context";
diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx
index c1295cae..0322aa30 100644
--- a/src/pages/LoginPage.tsx
+++ b/src/pages/LoginPage.tsx
@@ -2,13 +2,15 @@ import React, { useEffect } from "react";
import { Grid } from "@material-ui/core";
import LoginForm from "../components/LoginForm";
import { useHistory, useLocation } from "react-router-dom";
-import { useUserState } from "../contexts";
-import { routes } from "../constants";
+import { setHelpSteps, useHelpDispatch, useUserState } from "../contexts";
+import { LOGIN_PAGE_STEPS, routes } from "../constants";
const LoginPage = () => {
const history = useHistory();
const location = useLocation<{ from: string }>();
const { loggedIn } = useUserState();
+ const helpDispatch = useHelpDispatch();
+
const { from } = location.state || {
from: { pathname: routes.HOME },
};
@@ -17,6 +19,10 @@ const LoginPage = () => {
if (loggedIn) history.replace(from);
});
+ useEffect(() => {
+ setHelpSteps(helpDispatch, LOGIN_PAGE_STEPS);
+ });
+
return (
{
const { enqueueSnackbar } = useSnackbar();
const projectState = useProjectState();
const projectDispatch = useProjectDispatch();
+ const helpDispatch = useHelpDispatch();
const [createDialogOpen, setCreateDialogOpen] = React.useState(false);
const [updateDialogOpen, setUpdateDialogOpen] = React.useState(false);
const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false);
+ useEffect(() => {
+ setHelpSteps(helpDispatch, PROJECT_LIST_PAGE_STEPS);
+ });
+
const toggleCreateDialogOpen = () => {
setCreateDialogOpen(!createDialogOpen);
};
@@ -139,7 +150,7 @@ const ProjectsListPage = () => {
{projectState.projectList.map((project) => (
-
+
Id: {project.id}
Name: {project.name}
diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx
index 3553675c..311530ee 100644
--- a/src/pages/ProjectPage.tsx
+++ b/src/pages/ProjectPage.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect } from "react";
import { Grid, Box, makeStyles } from "@material-ui/core";
import { useParams, useHistory } from "react-router-dom";
import BuildList from "../components/BuildList";
@@ -6,6 +6,13 @@ import ProjectSelect from "../components/ProjectSelect";
import TestRunList from "../components/TestRunList";
import BuildDetails from "../components/BuildDetails";
import { TestDetailsDialog } from "../components/TestDetailsDialog";
+import { useHelpDispatch, setHelpSteps } from "../contexts";
+import {
+ PROJECT_PAGE_STEPS,
+ LOCATOR_PROJECT_PAGE_BUILD_LIST,
+ LOCATOR_PROJECT_PAGE_SELECT_PROJECT,
+ LOCATOR_PROJECT_PAGE_TEST_RUN_LIST,
+} from "../constants";
const useStyles = makeStyles((theme) => ({
root: {
@@ -17,18 +24,23 @@ const ProjectPage = () => {
const classes = useStyles();
const { projectId } = useParams<{ projectId: string }>();
const history = useHistory();
+ const helpDispatch = useHelpDispatch();
+
+ useEffect(() => {
+ setHelpSteps(helpDispatch, PROJECT_PAGE_STEPS);
+ });
return (
-
+
history.push(id)}
/>
-
+
@@ -36,7 +48,7 @@ const ProjectPage = () => {
-
+
diff --git a/src/pages/TestVariationListPage.tsx b/src/pages/TestVariationListPage.tsx
index 4a8c08c6..66c03044 100644
--- a/src/pages/TestVariationListPage.tsx
+++ b/src/pages/TestVariationListPage.tsx
@@ -8,10 +8,16 @@ import ProjectSelect from "../components/ProjectSelect";
import Filters from "../components/Filters";
import { TestVariationMergeForm } from "../components/TestVariationMergeForm";
import { useSnackbar } from "notistack";
+import { setHelpSteps, useHelpDispatch } from "../contexts/help.context";
+import {
+ LOCATOR_TEST_VARIATION_LIST_PAGE_SELECT_PROJECT,
+ TEST_VARIATION_LIST_PAGE,
+} from "../constants";
const TestVariationListPage: React.FunctionComponent = () => {
const history = useHistory();
const { enqueueSnackbar } = useSnackbar();
+ const helpDispatch = useHelpDispatch();
const { projectId = "" } = useParams<{ projectId: string }>();
const [testVariations, setTestVariations] = React.useState(
[]
@@ -27,6 +33,10 @@ const TestVariationListPage: React.FunctionComponent = () => {
const [branchName, setBranchName] = React.useState("");
const [filteredItems, setFilteredItems] = React.useState([]);
+ React.useEffect(() => {
+ setHelpSteps(helpDispatch, TEST_VARIATION_LIST_PAGE);
+ });
+
React.useEffect(() => {
if (projectId) {
testVariationService
@@ -55,7 +65,16 @@ const TestVariationListPage: React.FunctionComponent = () => {
(browser ? t.browser === browser : true) // by browser
)
);
- }, [query, branchName, os, device, browser, viewport, customTags, testVariations]);
+ }, [
+ query,
+ branchName,
+ os,
+ device,
+ browser,
+ viewport,
+ customTags,
+ testVariations,
+ ]);
const handleDelete = (id: string) => {
testVariationService
@@ -77,7 +96,7 @@ const TestVariationListPage: React.FunctionComponent = () => {
-
+
history.push(id)}