Skip to content

Commit

Permalink
Web: Fix infinite loops during error occurs
Browse files Browse the repository at this point in the history
  • Loading branch information
postrowinski committed Apr 14, 2023
1 parent b779db3 commit 877b800
Show file tree
Hide file tree
Showing 30 changed files with 301 additions and 331 deletions.
6 changes: 3 additions & 3 deletions mwdb/web/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function AppRoutes() {
<Route path="pending" element={<UsersPendingList />} />
<Route path="users" element={<UsersList />} />
<Route path="user/new" element={<UserCreate />} />
<Route path="user/:login" element={<UserView />}>
<Route path="user/:login/*" element={<UserView />}>
<Route index element={<UserDetails />} />
<Route
path="capabilities"
Expand All @@ -191,7 +191,7 @@ function AppRoutes() {
</Route>
<Route path="groups" element={<GroupsList />} />
<Route path="group/new" element={<GroupCreate />} />
<Route path="group/:name" element={<GroupView />}>
<Route path="group/:name/*" element={<GroupView />}>
<Route index element={<GroupDetails />} />
<Route
path="capabilities"
Expand All @@ -206,7 +206,7 @@ function AppRoutes() {
<Route path="attributes" element={<AttributesList />} />
<Route path="attribute/new" element={<AttributeCreate />} />
<Route
path="attribute/:attributeKey"
path="attribute/:attributeKey/*"
element={<AttributeView />}
>
<Route index element={<AttributeDetails />} />
Expand Down
21 changes: 10 additions & 11 deletions mwdb/web/src/commons/ui/ObjectTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ export function ObjectTab(props) {
useEffect(() => {
if (context.tab !== props.tab) return;
context.setComponent(props.component || (() => []));
context.setActions(props.actions || []);
context.setActions(
props.actions?.map((action, index) => {
return {
...action,
key: index,
};
}) || []
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [context.tab]);

Expand All @@ -26,11 +33,7 @@ export function ObjectTab(props) {
context.tab === props.tab ? "active" : ""
}`}
>
{props.icon ? (
<FontAwesomeIcon icon={props.icon} size="1x" />
) : (
[]
)}
{props.icon && <FontAwesomeIcon icon={props.icon} size="1x" />}
{props.label || capitalize(props.tab)}
</Link>
</li>
Expand All @@ -45,11 +48,7 @@ export function ObjectAction(props) {
className="nav-link"
onClick={() => props.action && props.action()}
>
{props.icon ? (
<FontAwesomeIcon icon={props.icon} size="1x" />
) : (
[]
)}
{props.icon && <FontAwesomeIcon icon={props.icon} size="1x" />}
{capitalize(props.label)}
</Link>
</li>
Expand Down
42 changes: 21 additions & 21 deletions mwdb/web/src/commons/ui/SortedList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,27 @@ export default function SortedList(props) {
return (
<table className="table table-striped table-bordered">
<thead>
{columnNames.map((h, idx) => (
<th
key={idx}
onClick={(ev) => {
ev.preventDefault();
handleSort(idx);
}}
style={{ cursor: "pointer" }}
>
{h}
{!unsortable.includes(h) ? (
<FontAwesomeIcon
icon={sortIcon(idx)}
pull="right"
size="x"
/>
) : (
[]
)}
</th>
))}
<tr>
{columnNames.map((h, idx) => (
<th
key={idx}
onClick={(ev) => {
ev.preventDefault();
handleSort(idx);
}}
style={{ cursor: "pointer" }}
>
{h}
{!unsortable.includes(h) && (
<FontAwesomeIcon
icon={sortIcon(idx)}
pull="right"
size="sm"
/>
)}
</th>
))}
</tr>
</thead>
<tbody>
{props.items.length ? (
Expand Down
5 changes: 1 addition & 4 deletions mwdb/web/src/commons/ui/View.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@ export function useViewAlert() {
[navigate]
);

return useMemo(
() => ({ setAlert, redirectToAlert }),
[setAlert, redirectToAlert]
);
return { setAlert, redirectToAlert };
}

export default function View({ ident, children, fluid, style, showIf = true }) {
Expand Down
2 changes: 1 addition & 1 deletion mwdb/web/src/commons/ui/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function LimitTo({ children, count }) {
const more =
children.length > count
? [
<small className="text-muted">
<small className="text-muted" key={"more-children"}>
{" "}
and {children.length - 5} more
</small>,
Expand Down
17 changes: 8 additions & 9 deletions mwdb/web/src/components/AttributesAddModal.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useRef, useState, useEffect, useCallback } from "react";
import React, { useRef, useState, useEffect } from "react";
import { isEmpty } from "lodash";
import { toast } from "react-toastify";

import { api } from "@mwdb-web/commons/api";
Expand All @@ -21,6 +22,11 @@ export default function AttributesAddModal({ isOpen, onAdd, onRequestClose }) {
const [invalid, setInvalid] = useState(false);
const [error, setError] = useState(null);
const attributeForm = useRef(null);
const attributesAvailable = !isEmpty(attributeDefinitions);

useEffect(() => {
getAttributeDefinitions();
}, []);

function handleSubmit(ev) {
if (ev) ev.preventDefault();
Expand Down Expand Up @@ -63,7 +69,7 @@ export default function AttributesAddModal({ isOpen, onAdd, onRequestClose }) {
setError(null);
}

async function updateAttributeDefinitions() {
async function getAttributeDefinitions() {
try {
const response = await api.getAttributeDefinitions("set");
const keyDefinitions = response.data[
Expand All @@ -81,13 +87,6 @@ export default function AttributesAddModal({ isOpen, onAdd, onRequestClose }) {
}
}

const getAttributeDefinitions = useCallback(updateAttributeDefinitions, []);
const attributesAvailable = Object.keys(attributeDefinitions).length !== 0;

useEffect(() => {
getAttributeDefinitions();
}, [getAttributeDefinitions]);

return (
<ConfirmationModal
buttonStyle="btn-success"
Expand Down
40 changes: 15 additions & 25 deletions mwdb/web/src/components/ConfigStats.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useEffect } from "react";
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { toast } from "react-toastify";

Expand Down Expand Up @@ -40,17 +40,6 @@ export default function ConfigStats() {
const [sortOrder, setSortOrder] = useState([0, 1]);
const [filterValue, setFilterValue] = useState("*");

async function updateStats() {
try {
let response = await api.getConfigStats(filterValue);
setFamilies(response.data.families);
} catch (error) {
toast(getErrorMessage(error), {
type: "error",
});
}
}

const columns = ["family", "last_upload", "count"];
const sortCriterion = columns[sortOrder[0]];
const sortOrderVariable = sortOrder[1];
Expand All @@ -60,19 +49,20 @@ export default function ConfigStats() {
return 0;
});

const onSort = (sortOrder) => {
setSortOrder(sortOrder);
};

const onChangeFilter = (ev) => {
setFilterValue(ev.target.value);
};

const getStats = useCallback(updateStats, [filterValue]);

useEffect(() => {
getStats();
}, [getStats]);
}, [filterValue]);

async function getStats() {
try {
let response = await api.getConfigStats(filterValue);
setFamilies(response.data.families);
} catch (error) {
toast(getErrorMessage(error), {
type: "error",
});
}
}

return (
<View ident="configStats">
Expand All @@ -82,7 +72,7 @@ export default function ConfigStats() {
<select
className="custom-select"
value={filterValue}
onChange={onChangeFilter}
onChange={(ev) => setFilterValue(ev.target.value)}
>
<option value="*">all time</option>
<option value="24h">last 24 hours</option>
Expand All @@ -97,7 +87,7 @@ export default function ConfigStats() {
items={items}
columnNames={["Family", "Last upload", "Unique configs"]}
sortOrder={sortOrder}
onSort={onSort}
onSort={setSortOrder}
/>
</View>
);
Expand Down
17 changes: 8 additions & 9 deletions mwdb/web/src/components/Profile/ProfileView.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { NavLink, useParams, Outlet } from "react-router-dom";
import { isEmpty } from "lodash";

import { faUserCog } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
Expand Down Expand Up @@ -49,7 +50,11 @@ export default function ProfileView() {
const user = useParams().user || auth.user.login;
const [profile, setProfile] = useState();

async function updateProfile() {
useEffect(() => {
getProfile();
}, [user]);

async function getProfile() {
try {
const response = await api.getUserProfile(user);
setProfile(response.data);
Expand All @@ -61,13 +66,7 @@ export default function ProfileView() {
}
}

const getProfile = useCallback(updateProfile, [user, redirectToAlert]);

useEffect(() => {
getProfile();
}, [getProfile]);

if (!profile || profile.login !== user) return [];
if (isEmpty(profile) || profile.login !== user) return <></>;

return (
<View ident="profile" fluid>
Expand Down
36 changes: 17 additions & 19 deletions mwdb/web/src/components/Profile/Views/ProfileGroup.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import React, { useContext, useEffect, useState } from "react";
import { Link, Navigate, useParams, useOutletContext } from "react-router-dom";
import { isEmpty } from "lodash";

import { faUsersCog } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
Expand All @@ -26,7 +27,13 @@ export default function ProfileGroup() {
const { group: groupName } = useParams();
const [workspaces, setWorkspaces] = useState();

async function updateWorkspaces() {
const group = profile.groups.find((group) => group.name === groupName);

useEffect(() => {
getWorkspaces();
}, []);

async function getWorkspaces() {
try {
const response = await api.authGroups();
setWorkspaces(response.data["groups"]);
Expand All @@ -38,24 +45,15 @@ export default function ProfileGroup() {
}
}

const getWorkspaces = useCallback(updateWorkspaces, [redirectToAlert]);
if (isEmpty(workspaces)) return <></>;

useEffect(() => {
getWorkspaces();
}, [getWorkspaces]);

if (!workspaces) return [];

const group = profile.groups.find((group) => group.name === groupName);
if (!group)
return (
<Navigate
to="/profile"
state={{
error: `Group ${groupName} doesn't exist`,
}}
/>
);
if (isEmpty(group)) {
redirectToAlert({
target: "/profile",
error: `Group ${groupName} doesn't exist`,
});
return <></>;
}
// Merge it with workspace info
const workspace = workspaces.find((group) => group.name === groupName);

Expand Down

0 comments on commit 877b800

Please sign in to comment.