Skip to content

Commit

Permalink
UI: Unified error/success handling via useViewAlert (#374)
Browse files Browse the repository at this point in the history
  • Loading branch information
psrok1 committed May 17, 2021
1 parent 2832fb1 commit b6039cc
Show file tree
Hide file tree
Showing 20 changed files with 181 additions and 238 deletions.
41 changes: 39 additions & 2 deletions mwdb/web/src/commons/ui/View.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { useLocation } from "react-router-dom";
import { Alert } from "./ErrorBoundary";
import { useHistory, useLocation } from "react-router-dom";
import { Alert, getErrorMessage } from "./ErrorBoundary";
import { Extendable } from "../extensions";

function ViewAlert(props) {
Expand All @@ -14,6 +14,43 @@ function ViewAlert(props) {
);
}

export function useViewAlert() {
const history = useHistory();

function setAlert({ success, error: rawError, warning, state }) {
const { pathname, search } = history.location;
const error = rawError && getErrorMessage(rawError);
history.replace(
{ pathname, search },
{
...history.location.state,
...(state || {}),
success,
error,
warning,
}
);
}

function redirectToAlert({
success,
error: rawError,
warning,
target,
state,
}) {
const error = rawError && getErrorMessage(rawError);
history.push(target, {
...(state || {}),
success,
error,
warning,
});
}

return { setAlert, redirectToAlert };
}

export default function View(props) {
/**
* View component for all main views. Views shouldn't be nested.
Expand Down
2 changes: 1 addition & 1 deletion mwdb/web/src/commons/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export {
} from "./ProtectedRoute";
export { default as RefString } from "./RefString";
export { default as SortedList } from "./SortedList";
export { default as View } from "./View";
export { default as View, useViewAlert } from "./View";
export { default as ActionCopyToClipboard } from "./ActionCopyToClipboard";

export { Tag, TagList } from "./Tag";
Expand Down
19 changes: 7 additions & 12 deletions mwdb/web/src/components/Profile/ProfileView.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import {
NavLink,
Route,
Switch,
useHistory,
useParams,
} from "react-router-dom";
import { NavLink, Route, Switch, useParams } from "react-router-dom";

import { faUserCog } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

import api from "@mwdb-web/commons/api";
import { AuthContext } from "@mwdb-web/commons/auth";
import { View, getErrorMessage } from "@mwdb-web/commons/ui";
import { View } from "@mwdb-web/commons/ui";

import ProfileDetails from "./Views/ProfileDetails";
import ProfileAPIKeys from "./Views/ProfileAPIKeys";
import ProfileCapabilities from "./Views/ProfileCapabilities";
import ProfileResetPassword from "./Views/ProfileResetPassword";
import ProfileGroup from "./Views/ProfileGroup";
import ProfileGroups from "./Views/ProfileGroups";
import { useViewAlert } from "../../commons/ui";

function ProfileNav() {
return (
Expand Down Expand Up @@ -48,7 +43,7 @@ function ProfileNav() {

export default function ProfileView() {
const auth = useContext(AuthContext);
const history = useHistory();
const viewAlert = useViewAlert();
const user = useParams().user || auth.user.login;
const [profile, setProfile] = useState();

Expand All @@ -57,9 +52,9 @@ export default function ProfileView() {
const response = await api.getUserProfile(user);
setProfile(response.data);
} catch (error) {
history.push({
pathname: "/profile",
state: { error: getErrorMessage(error) },
viewAlert.redirectToAlert({
target: "/profile",
error,
});
}
}
Expand Down
35 changes: 12 additions & 23 deletions mwdb/web/src/components/Profile/Views/ProfileAPIKeys.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { CopyToClipboard } from "react-copy-to-clipboard";
import { useHistory, useLocation } from "react-router-dom";
import { useLocation } from "react-router-dom";

import {
faCopy,
Expand All @@ -15,13 +15,13 @@ import api from "@mwdb-web/commons/api";
import {
ConfirmationModal,
DateString,
getErrorMessage,
ShowIf,
useViewAlert,
} from "@mwdb-web/commons/ui";

export default function ProfileAPIKeys({ profile, updateProfile }) {
const history = useHistory();
const location = useLocation();
const viewAlert = useViewAlert();
const [currentApiToken, setCurrentApiToken] = useState({});
const [apiKeyToRemove, setApiKeyToRemove] = useState();
const [removeModalOpened, setRemoveModalOpened] = useState(false);
Expand All @@ -34,10 +34,7 @@ export default function ProfileAPIKeys({ profile, updateProfile }) {
const response = await api.apiKeyGetToken(apiKeyId);
setCurrentApiToken(response.data);
} catch (error) {
history.push({
pathname: location.pathname,
state: { error: getErrorMessage(error) },
});
viewAlert.setAlert({ error });
}
}

Expand All @@ -46,18 +43,14 @@ export default function ProfileAPIKeys({ profile, updateProfile }) {
const response = await api.apiKeyAdd(profile.login);
setCurrentApiToken(response.data);
updateProfile();
history.push({
pathname: location.pathname,
viewAlert.setAlert({
success: "New API key successfully added",
state: {
success: "New API key successfully added",
addedKey: response.data.id,
},
});
} catch (error) {
history.push({
pathname: location.pathname,
state: { error: getErrorMessage(error) },
});
viewAlert.setAlert({ error });
}
}

Expand All @@ -68,17 +61,14 @@ export default function ProfileAPIKeys({ profile, updateProfile }) {
setApiKeyToRemove(undefined);
updateProfile();
setRemoveModalOpened(false);
history.push({
pathname: location.pathname,
viewAlert.setAlert({
success: "API key successfully removed",
state: {
success: "API key successfully removed",
addedKey: null,
},
});
} catch (error) {
history.push({
pathname: location.pathname,
state: { error: getErrorMessage(error) },
});
viewAlert.setAlert({ error });
}
}

Expand All @@ -105,8 +95,7 @@ export default function ProfileAPIKeys({ profile, updateProfile }) {
{profile.api_keys.map((apiKey) => (
<div
className={`card ${
history.location.state &&
history.location.state.addedKey === apiKey.id
location.state && location.state.addedKey === apiKey.id
? "border-success"
: ""
}`}
Expand Down
14 changes: 6 additions & 8 deletions mwdb/web/src/components/Profile/Views/ProfileGroup.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import { Link, Redirect, useParams, useHistory } from "react-router-dom";
import { Link, Redirect, useParams } from "react-router-dom";

import { faUsersCog } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

import api from "@mwdb-web/commons/api";
import { AuthContext, Capability } from "@mwdb-web/commons/auth";
import { makeSearchLink } from "@mwdb-web/commons/helpers";
import { GroupBadge, ShowIf, getErrorMessage } from "@mwdb-web/commons/ui";
import { GroupBadge, ShowIf, useViewAlert } from "@mwdb-web/commons/ui";

function ProfileItem(props) {
if (!props.value) return [];
Expand All @@ -21,7 +21,7 @@ function ProfileItem(props) {

export default function ProfileGroup({ profile }) {
const auth = useContext(AuthContext);
const history = useHistory();
const viewAlert = useViewAlert();
const { group: groupName } = useParams();
const [workspaces, setWorkspaces] = useState();

Expand All @@ -30,11 +30,9 @@ export default function ProfileGroup({ profile }) {
const response = await api.authGroups();
setWorkspaces(response.data["groups"]);
} catch (error) {
history.push({
pathname: "/profile",
state: {
error: getErrorMessage(error),
},
viewAlert.redirectToAlert({
target: "/profile",
error,
});
}
}
Expand Down
14 changes: 5 additions & 9 deletions mwdb/web/src/components/Profile/Views/ProfileGroups.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import React, { useCallback, useEffect, useState } from "react";
import { useHistory } from "react-router-dom";

import api from "@mwdb-web/commons/api";
import { getErrorMessage } from "@mwdb-web/commons/ui";
import { GroupBadge } from "../../../commons/ui";
import { GroupBadge, useViewAlert } from "../../../commons/ui";

export default function ProfileGroups({ profile }) {
const history = useHistory();
const viewAlert = useViewAlert();
const [workspaces, setWorkspaces] = useState();

async function updateWorkspaces() {
try {
const response = await api.authGroups();
setWorkspaces(response.data["groups"]);
} catch (error) {
history.push({
pathname: "/profile",
state: {
error: getErrorMessage(error),
},
viewAlert.redirectToAlert({
target: "/profile",
error,
});
}
}
Expand Down
23 changes: 8 additions & 15 deletions mwdb/web/src/components/Profile/Views/ProfileResetPassword.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import React, { useState } from "react";
import { Link, useHistory } from "react-router-dom";
import { Link } from "react-router-dom";

import api from "@mwdb-web/commons/api";
import { ShowIf, getErrorMessage } from "@mwdb-web/commons/ui";
import { ShowIf, useViewAlert } from "@mwdb-web/commons/ui";

export default function ProfileResetPassword({ profile }) {
const [pending, setPending] = useState(false);
const history = useHistory();
const viewAlert = useViewAlert();

async function resetPassword() {
setPending(true);
try {
await api.authRequestPasswordChange();
history.push({
pathname: "/profile",
state: {
success:
"Password reset link was successfully sent to your e-mail address.",
},
viewAlert.redirectToAlert({
target: "/profile",
success:
"Password reset link was successfully sent to your e-mail address.",
});
} catch (error) {
history.push({
pathname: "/profile",
state: {
error: getErrorMessage(error),
},
});
viewAlert.setAlert({ error });
}
}

Expand Down
9 changes: 2 additions & 7 deletions mwdb/web/src/components/Settings/SettingsView.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,9 @@ function SettingsNav() {
);
}

export default function SettingsView(props) {
export default function SettingsView() {
return (
<View
ident="settings"
error={props.error}
success={props.success}
fluid
>
<View ident="settings" fluid>
<div className="row">
<div className="col-sm-2">
<SettingsNav />
Expand Down
11 changes: 8 additions & 3 deletions mwdb/web/src/components/Settings/Views/AccessControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ConfirmationModal,
GroupBadge,
ShowIf,
useViewAlert,
} from "@mwdb-web/commons/ui";

function GroupAppliesTo({ group }) {
Expand Down Expand Up @@ -195,6 +196,7 @@ function CapabilityChangeCard({ groups, onSubmit }) {

export default function AccessControl() {
const [groups, setGroups] = useState(null);
const viewAlert = useViewAlert();

const [isChangeModalOpen, setChangeModalOpen] = useState(false);
const [disabledModalButton, setDisabledModalButton] = useState(false);
Expand All @@ -211,7 +213,7 @@ export default function AccessControl() {
);
setGroups(groupList);
} catch (error) {
console.error(error);
viewAlert.setAlert({ error });
}
}

Expand All @@ -220,8 +222,11 @@ export default function AccessControl() {
setDisabledModalButton(true);
await api.updateGroup(group, undefined, capabilities);
await updateGroups();
} catch (e) {
// todo
viewAlert.setAlert({
success: `Group '${group}' capabilities successfully changed`,
});
} catch (error) {
viewAlert.setAlert({ error });
} finally {
setDisabledModalButton(false);
setChangeModalOpen(false);
Expand Down

0 comments on commit b6039cc

Please sign in to comment.