diff --git a/package-lock.json b/package-lock.json
index e8165d0c..056dce4d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "vrt-frontend",
- "version": "1.4.0",
+ "version": "1.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -9463,6 +9463,15 @@
"sort-keys": "^1.0.0"
}
},
+ "notistack": {
+ "version": "0.9.17",
+ "resolved": "https://registry.npmjs.org/notistack/-/notistack-0.9.17.tgz",
+ "integrity": "sha512-nypTN6sEe+q98wMaxF/UwatA1yAq948+bZOo9JKYR+tU65DW0ipWyx8DseJ3UJYvb6VDD+Fqo83qwayQ46bEEA==",
+ "requires": {
+ "clsx": "^1.1.0",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
diff --git a/package.json b/package.json
index 584584ea..f81fc370 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"@testing-library/user-event": "^7.2.1",
"konva": "^4.2.2",
"material-ui-popup-state": "^1.6.1",
+ "notistack": "^0.9.17",
"qs": "^6.9.4",
"react": "^16.13.1",
"react-debounce-input": "^3.2.2",
diff --git a/src/App.jsx b/src/App.jsx
index 00482241..a5c1b08d 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,4 +1,5 @@
import React from "react";
+import { SnackbarProvider } from 'notistack';
import "./App.css";
import Header from "./components/Header";
import {
@@ -12,20 +13,22 @@ import { SocketProvider } from "./contexts/socket.context";
function App() {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/components/BuildList.tsx b/src/components/BuildList.tsx
index be953f5c..04186446 100644
--- a/src/components/BuildList.tsx
+++ b/src/components/BuildList.tsx
@@ -23,6 +23,7 @@ import {
import { BuildStatusChip } from "./BuildStatusChip";
import { SkeletonList } from "./SkeletonList";
import { formatDateTime } from "../_helpers/format.helper";
+import { useSnackbar } from "notistack";
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -42,6 +43,7 @@ const BuildList: FunctionComponent = () => {
const history = useHistory();
const { buildList, selectedBuildId, loading } = useBuildState();
const buildDispatch = useBuildDispatch();
+ const { enqueueSnackbar } = useSnackbar();
return (
@@ -98,7 +100,17 @@ const BuildList: FunctionComponent = () => {
>
{
- deleteBuild(buildDispatch, build.id);
+ deleteBuild(buildDispatch, build.id)
+ .then((b) =>
+ enqueueSnackbar(`${b.id} removed`, {
+ variant: "success",
+ })
+ )
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}}
>
diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx
index b1c41a85..be94d224 100644
--- a/src/components/LoginForm.tsx
+++ b/src/components/LoginForm.tsx
@@ -11,15 +11,21 @@ import {
} from "@material-ui/core";
import { useAuthDispatch, login } from "../contexts";
import { routes } from "../constants";
+import { useSnackbar } from "notistack";
const LoginForm = () => {
+ const { enqueueSnackbar } = useSnackbar();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const dispatch = useAuthDispatch();
const handleSubmit = (event: FormEvent) => {
event.preventDefault();
- login(dispatch, email, password);
+ login(dispatch, email, password).catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
};
return (
diff --git a/src/components/RegisterForm.tsx b/src/components/RegisterForm.tsx
index 50830347..99cb3f77 100644
--- a/src/components/RegisterForm.tsx
+++ b/src/components/RegisterForm.tsx
@@ -9,8 +9,10 @@ import {
} from "@material-ui/core";
import { useAuthDispatch, login } from "../contexts";
import { usersService } from "../services";
+import { useSnackbar } from "notistack";
const RegisterForm = () => {
+ const { enqueueSnackbar } = useSnackbar();
const [email, setEmail] = useState("");
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
@@ -21,7 +23,12 @@ const RegisterForm = () => {
event.preventDefault();
usersService
.register(firstName, lastName, email, password)
- .then(() => login(dispatch, email, password));
+ .then(() => login(dispatch, email, password))
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
};
return (
diff --git a/src/components/TestDetailsModal.tsx b/src/components/TestDetailsModal.tsx
index 380a0f10..5b7d4a2a 100644
--- a/src/components/TestDetailsModal.tsx
+++ b/src/components/TestDetailsModal.tsx
@@ -40,6 +40,7 @@ import { routes } from "../constants";
import { useTestRunDispatch, updateTestRun, selectTestRun } from "../contexts";
import { DrawArea } from "./DrawArea";
import { CommentsPopper } from "./CommentsPopper";
+import { useSnackbar } from "notistack";
const useStyles = makeStyles((theme) => ({
imageContainer: {
@@ -57,6 +58,7 @@ const TestDetailsModal: React.FunctionComponent<{
}> = ({ testRun }) => {
const classes = useStyles();
const history = useHistory();
+ const { enqueueSnackbar } = useSnackbar();
const testRunDispatch = useTestRunDispatch();
const stageWidth = (window.innerWidth / 2) * 0.9;
@@ -177,6 +179,16 @@ const TestDetailsModal: React.FunctionComponent<{
.then((testRun) => {
updateTestRun(testRunDispatch, testRun);
})
+ .then(() =>
+ enqueueSnackbar("Approved", {
+ variant: "success",
+ })
+ )
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ )
}
>
Approve
@@ -186,9 +198,21 @@ const TestDetailsModal: React.FunctionComponent<{
) => {
- deleteProject(projectDispatch, project.id);
+ deleteProject(projectDispatch, project.id)
+ .then((project) => {
+ enqueueSnackbar(`${project.name} deleted`, {
+ variant: "success",
+ });
+ })
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}}
>
diff --git a/src/pages/ProjectPage.tsx b/src/pages/ProjectPage.tsx
index 7d627aaa..3fbf1196 100644
--- a/src/pages/ProjectPage.tsx
+++ b/src/pages/ProjectPage.tsx
@@ -27,6 +27,7 @@ import {
selectTestRun,
getTestRunList,
} from "../contexts";
+import { useSnackbar } from "notistack";
const getQueryParams = (guery: string) => {
const queryParams = qs.parse(guery, { ignoreQueryPrefix: true });
@@ -67,6 +68,7 @@ const ProjectPage = () => {
const { projectId } = useParams();
const location = useLocation();
const history = useHistory();
+ const { enqueueSnackbar } = useSnackbar();
const { buildList, selectedBuildId } = useBuildState();
const buildDispatch = useBuildDispatch();
const {
@@ -87,15 +89,23 @@ const ProjectPage = () => {
useEffect(() => {
if (projectId) {
- getBuildList(buildDispatch, projectId);
+ getBuildList(buildDispatch, projectId).catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}
- }, [projectId, buildDispatch]);
+ }, [projectId, buildDispatch, enqueueSnackbar]);
useEffect(() => {
if (selectedBuildId) {
- getTestRunList(testRunDispatch, selectedBuildId);
+ getTestRunList(testRunDispatch, selectedBuildId).catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}
- }, [selectedBuildId, testRunDispatch]);
+ }, [selectedBuildId, testRunDispatch, enqueueSnackbar]);
useEffect(() => {
const queryParams = getQueryParams(location.search);
diff --git a/src/pages/TestVariationDetailsPage.tsx b/src/pages/TestVariationDetailsPage.tsx
index b4641fb0..e1a80776 100644
--- a/src/pages/TestVariationDetailsPage.tsx
+++ b/src/pages/TestVariationDetailsPage.tsx
@@ -20,6 +20,7 @@ import {
useTestRunDispatch,
selectTestRun,
} from "../contexts";
+import { useSnackbar } from "notistack";
const useStyles = makeStyles({
media: {
@@ -31,6 +32,7 @@ const useStyles = makeStyles({
const TestVariationDetailsPage: React.FunctionComponent = () => {
const classes = useStyles();
const history = useHistory();
+ const { enqueueSnackbar } = useSnackbar();
const buildDispatch = useBuildDispatch();
const testRunDispatch = useTestRunDispatch();
const { testVariationId } = useParams();
@@ -38,11 +40,18 @@ const TestVariationDetailsPage: React.FunctionComponent = () => {
React.useEffect(() => {
if (testVariationId) {
- testVariationService.getDetails(testVariationId).then((item) => {
- setTestVariation(item);
- });
+ testVariationService
+ .getDetails(testVariationId)
+ .then((item) => {
+ setTestVariation(item);
+ })
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}
- }, [testVariationId]);
+ }, [testVariationId, enqueueSnackbar]);
return (
diff --git a/src/pages/TestVariationListPage.tsx b/src/pages/TestVariationListPage.tsx
index 8f617f4a..8d83b9cb 100644
--- a/src/pages/TestVariationListPage.tsx
+++ b/src/pages/TestVariationListPage.tsx
@@ -7,8 +7,10 @@ import { Container, Box, Grid, Typography } from "@material-ui/core";
import ProjectSelect from "../components/ProjectSelect";
import Filters from "../components/Filters";
import { TestVariationMergeForm } from "../components/TestVariationMergeForm";
+import { useSnackbar } from "notistack";
const TestVariationListPage: React.FunctionComponent = () => {
+ const { enqueueSnackbar } = useSnackbar();
const { projectId = "" } = useParams();
const [testVariations, setTestVariations] = React.useState(
[]
@@ -25,11 +27,18 @@ const TestVariationListPage: React.FunctionComponent = () => {
React.useEffect(() => {
if (projectId) {
- testVariationService.getList(projectId).then((testVariations) => {
- setTestVariations(testVariations);
- });
+ testVariationService
+ .getList(projectId)
+ .then((testVariations) => {
+ setTestVariations(testVariations);
+ })
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
}
- }, [projectId]);
+ }, [projectId, enqueueSnackbar]);
React.useEffect(() => {
setFilteredItems(
@@ -46,9 +55,19 @@ const TestVariationListPage: React.FunctionComponent = () => {
}, [query, branchName, os, device, browser, viewport, testVariations]);
const handleDelete = (id: string) => {
- testVariationService.remove(id).then((item) => {
- setTestVariations(testVariations.filter((i) => i.id !== item.id));
- });
+ testVariationService
+ .remove(id)
+ .then((item) => {
+ setTestVariations(testVariations.filter((i) => i.id !== item.id));
+ enqueueSnackbar("Deleted", {
+ variant: "success",
+ });
+ })
+ .catch((err) =>
+ enqueueSnackbar(err, {
+ variant: "error",
+ })
+ );
};
return (
diff --git a/src/services/builds.service.ts b/src/services/builds.service.ts
index 801e96d2..f1ebdae1 100644
--- a/src/services/builds.service.ts
+++ b/src/services/builds.service.ts
@@ -20,7 +20,7 @@ function getList(projectId: string): Promise {
);
}
-function remove(id: string): Promise {
+function remove(id: string): Promise {
const requestOptions = {
method: "DELETE",
headers: authHeader(),
diff --git a/src/services/projects.service.ts b/src/services/projects.service.ts
index f4446849..7f3c2b26 100644
--- a/src/services/projects.service.ts
+++ b/src/services/projects.service.ts
@@ -18,7 +18,7 @@ function getAll(): Promise {
return fetch(`${API_URL}/projects`, requestOptions).then(handleResponse);
}
-function remove(id: string): Promise {
+function remove(id: string): Promise {
const requestOptions = {
method: "DELETE",
headers: authHeader(),
diff --git a/src/services/testRun.service.ts b/src/services/testRun.service.ts
index 9e28358a..12e6f609 100644
--- a/src/services/testRun.service.ts
+++ b/src/services/testRun.service.ts
@@ -15,7 +15,7 @@ export const testRunService = {
setComment,
};
-function getList(buildId: string): Promise {
+async function getList(buildId: string): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -27,7 +27,7 @@ function getList(buildId: string): Promise {
).then(handleResponse);
}
-function remove(id: string): Promise {
+async function remove(id: string): Promise {
const requestOptions = {
method: "DELETE",
headers: authHeader(),
@@ -38,7 +38,7 @@ function remove(id: string): Promise {
);
}
-function recalculateDiff(id: string): Promise {
+async function recalculateDiff(id: string): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -50,7 +50,7 @@ function recalculateDiff(id: string): Promise {
).then(handleResponse);
}
-function approve(id: string, merge: boolean): Promise {
+async function approve(id: string, merge: boolean): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -62,7 +62,7 @@ function approve(id: string, merge: boolean): Promise {
).then(handleResponse);
}
-function reject(id: string): Promise {
+async function reject(id: string): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -73,7 +73,7 @@ function reject(id: string): Promise {
);
}
-function setIgnoreAreas(
+async function setIgnoreAreas(
id: string,
ignoreAreas: IgnoreArea[]
): Promise {
@@ -89,7 +89,7 @@ function setIgnoreAreas(
).then(handleResponse);
}
-function setComment(id: string, comment: string): Promise {
+async function setComment(id: string, comment: string): Promise {
const requestOptions = {
method: "PUT",
headers: { "Content-Type": "application/json", ...authHeader() },
diff --git a/src/services/testVariation.service.ts b/src/services/testVariation.service.ts
index d405a5c3..acbd31df 100644
--- a/src/services/testVariation.service.ts
+++ b/src/services/testVariation.service.ts
@@ -14,7 +14,7 @@ export const testVariationService = {
remove,
};
-function getList(projectId: String): Promise {
+async function getList(projectId: String): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -26,7 +26,7 @@ function getList(projectId: String): Promise {
).then(handleResponse);
}
-function getDetails(id: String): Promise {
+async function getDetails(id: String): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -37,7 +37,7 @@ function getDetails(id: String): Promise {
);
}
-function setIgnoreAreas(
+async function setIgnoreAreas(
variationId: string,
ignoreAreas: IgnoreArea[]
): Promise {
@@ -53,7 +53,7 @@ function setIgnoreAreas(
).then(handleResponse);
}
-function setComment(id: string, comment: string): Promise {
+async function setComment(id: string, comment: string): Promise {
const requestOptions = {
method: "PUT",
headers: { "Content-Type": "application/json", ...authHeader() },
@@ -65,7 +65,7 @@ function setComment(id: string, comment: string): Promise {
);
}
-function merge(projectId: String, branchName: String): Promise {
+async function merge(projectId: String, branchName: String): Promise {
const requestOptions = {
method: "GET",
headers: authHeader(),
@@ -77,7 +77,7 @@ function merge(projectId: String, branchName: String): Promise {
).then(handleResponse);
}
-function remove(id: String): Promise {
+async function remove(id: String): Promise {
const requestOptions = {
method: "DELETE",
headers: authHeader(),
diff --git a/src/services/users.service.ts b/src/services/users.service.ts
index d9bc5657..d8ae61d6 100644
--- a/src/services/users.service.ts
+++ b/src/services/users.service.ts
@@ -42,7 +42,7 @@ function register(firstName: string, lastName: string, email: string, password:
});
}
-function update({ id, firstName, lastName, email }: { id: string, firstName: string, lastName: string, email: string }): Promise {
+function update({ firstName, lastName, email }: { firstName: string, lastName: string, email: string }): Promise {
const requestOptions = {
method: "PUT",
headers: { "Content-Type": "application/json", ...authHeader() },