Skip to content

Commit

Permalink
feat: error handling/display for all pages and pipeline load block
Browse files Browse the repository at this point in the history
Signed-off-by: bbehnke <bradleybehnke@yahoo.com>

fix: errors tweak

fix: errors tweak
  • Loading branch information
bbehnke committed Oct 11, 2023
1 parent ba2b74f commit 3ce92f0
Show file tree
Hide file tree
Showing 25 changed files with 498 additions and 605 deletions.
37 changes: 35 additions & 2 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Drawer from "@mui/material/Drawer";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import CircularProgress from "@mui/material/CircularProgress";
import { Routes, Route } from "react-router-dom";
import { Routes, Route, useLocation } from "react-router-dom";
import { Breadcrumbs } from "./components/common/Breadcrumbs";
import { Cluster } from "./components/pages/Cluster";
import { Namespaces } from "./components/pages/Namespace";
Expand All @@ -23,7 +23,7 @@ import {
SlidingSidebarProps,
} from "./components/common/SlidingSidebar";
import { ErrorDisplay } from "./components/common/ErrorDisplay";
import { AppContextProps } from "./types/declarations/app";
import { AppContextProps, AppError } from "./types/declarations/app";
import logo from "./images/icon.png";
import textLogo from "./images/text-icon.png";

Expand All @@ -33,8 +33,17 @@ import "react-toastify/dist/ReactToastify.css";
export const AppContext = React.createContext<AppContextProps>({
systemInfo: undefined,
systemInfoError: undefined,
// eslint-disable-next-line @typescript-eslint/no-empty-function
setSidebarProps: () => {},
errors: [],
// eslint-disable-next-line @typescript-eslint/no-empty-function
addError: () => {},
// eslint-disable-next-line @typescript-eslint/no-empty-function
clearErrors: () => {},
});

const MAX_ERRORS = 6;

function App() {
// TODO remove, used for testing ns only installation
// const { systemInfo, error: systemInfoError } = {
Expand All @@ -52,7 +61,14 @@ function App() {
const [sidebarCloseIndicator, setSidebarCloseIndicator] = useState<
string | undefined
>();
const [errors, setErrors] = useState<AppError[]>([]);
const { systemInfo, error: systemInfoError, loading } = useSystemInfoFetch();
const location = useLocation();

useEffect(() => {
// Route changed
setErrors([]);
}, [location]);

// Resize observer to keep page width in state. To be used by other dependent components.
useEffect(() => {
Expand Down Expand Up @@ -87,6 +103,20 @@ function App() {
setSidebarCloseIndicator("id" + Math.random().toString(16).slice(2));
}, []);

const handleAddError = useCallback((error: string) => {
setErrors((prev) => {
prev.unshift({
message: error,
date: new Date(),
});
return prev.slice(0, MAX_ERRORS);
});
}, []);

const handleClearErrors = useCallback(() => {
setErrors([]);
}, []);

const routes = useMemo(() => {
if (loading) {
// System info loading
Expand Down Expand Up @@ -171,6 +201,9 @@ function App() {
systemInfoError,
sidebarProps,
setSidebarProps,
errors,
addError: handleAddError,
clearErrors: handleClearErrors,
}}
>
<ScopedCssBaseline>
Expand Down
43 changes: 43 additions & 0 deletions ui/src/components/common/ErrorIndicator/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { useContext, useCallback } from "react";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import { AppContextProps } from "../../../types/declarations/app";
import { AppContext } from "../../../App";
import { SidebarType } from "../SlidingSidebar";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import ErrorIcon from "@mui/icons-material/Error";

import "./style.css";

export function ErrorIndicator() {
const { errors, setSidebarProps } = useContext<AppContextProps>(AppContext);

const onErrorClick = useCallback(() => {
setSidebarProps({
type: SidebarType.ERRORS,
slide: false,
});
}, []);

return (
<Paper
elevation={1}
sx={{
cursor: "pointer",
padding: "0.25rem 0.5rem",
}}
onClick={onErrorClick}
>
<Box sx={{ display: "flex", flexDirection: "row", alignItems: "center" }}>
{errors && errors.length ? (
<ErrorIcon sx={{ color: "#D52B1E" }} />
) : (
<ErrorOutlineIcon sx={{ color: "#6B6C72" }} />
)}
{errors.length ? (
<span className="error-indicator-text">Error occurred</span>
) : undefined}
</Box>
</Paper>
);
}
4 changes: 4 additions & 0 deletions ui/src/components/common/ErrorIndicator/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.error-indicator-text {
margin-left: 0.5rem;
min-width: 6.5625rem;
}
12 changes: 3 additions & 9 deletions ui/src/components/common/SlidingSidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
GeneratorDetails,
GeneratorDetailsProps,
} from "./partials/GeneratorDetails";
import { Errors, ErrorsProps } from "./partials/Errors";
import { Errors } from "./partials/Errors";
import { PiplineCreate } from "./partials/PipelineCreate";
import { PiplineUpdate } from "./partials/PipelineUpdate";
import { ISBCreate } from "./partials/ISBCreate";
Expand Down Expand Up @@ -79,7 +79,6 @@ export interface SlidingSidebarProps {
vertexDetailsProps?: VertexDetailsProps;
edgeDetailsProps?: EdgeDetailsProps;
generatorDetailsProps?: GeneratorDetailsProps;
errorsProps?: ErrorsProps;
specEditorProps?: SpecEditorSidebarProps;
parentCloseIndicator?: string;
}
Expand All @@ -92,13 +91,12 @@ export function SlidingSidebar({
vertexDetailsProps,
edgeDetailsProps,
generatorDetailsProps,
errorsProps,
specEditorProps,
parentCloseIndicator,
}: SlidingSidebarProps) {
const { setSidebarProps } = useContext<AppContextProps>(AppContext);
const [width, setWidth] = useState<number>(
errorsProps
type === SidebarType.ERRORS
? MIN_WIDTH_BY_TYPE[SidebarType.ERRORS]
: (pageWidth * 0.75)
);
Expand Down Expand Up @@ -243,10 +241,7 @@ export function SlidingSidebar({
}
return <GeneratorDetails {...generatorDetailsProps} />;
case SidebarType.ERRORS:
if (!errorsProps) {
break;
}
return <Errors {...errorsProps} />;
return <Errors />;
default:
break;
}
Expand All @@ -258,7 +253,6 @@ export function SlidingSidebar({
vertexDetailsProps,
edgeDetailsProps,
generatorDetailsProps,
errorsProps,
]);

return (
Expand Down
83 changes: 50 additions & 33 deletions ui/src/components/common/SlidingSidebar/partials/Errors/index.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,71 @@
import React, { useMemo } from "react";
import React, { useCallback, useContext, useMemo } from "react";
import Box from "@mui/material/Box";
import { Slide, ToastContainer } from "react-toastify";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import { AppContextProps } from "../../../../../types/declarations/app";
import { AppContext } from "../../../../../App";

import "./style.css";

export interface ErrorsProps {
errors: boolean;
}
export function Errors() {
const { errors, clearErrors } = useContext<AppContextProps>(AppContext);

const handleClear = useCallback(() => {
clearErrors();
}, [clearErrors]);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function Errors({ errors }: ErrorsProps) {
const header = useMemo(() => {
const headerContainerStyle = {
const content = useMemo(() => {
const paperStyle = {
display: "flex",
flexDirection: "row",
flexDirection: "column",
padding: "1rem",
};
const textClass = "vertex-details-header-text";

return (
<Box sx={headerContainerStyle}>
<span className={textClass}>Errors</span>
</Box>
<Grid
container
spacing={2}
sx={{ marginTop: "0.5rem", justifyContent: "center" }}
>
{!errors.length && (
<Grid item xs={12}>
<Paper elevation={0} sx={paperStyle}>
No errors
</Paper>
</Grid>
)}
{errors.map((error) => (
<Grid item xs={12}>
<Paper elevation={0} sx={paperStyle}>
<span className="errors-message-text">{error.message}</span>
<span>{error.date.toLocaleTimeString()}</span>
</Paper>
</Grid>
))}
{!!errors.length && (
<Button
sx={{ marginTop: "1rem" }}
onClick={handleClear}
variant="outlined"
color="primary"
>
Clear
</Button>
)}
</Grid>
);
}, []);
}, [errors]);

return (
<Box
sx={{
display: "flex",
flexDirection: "column",
height: "100%",
borderColor: "divider",
}}
>
<Box sx={{ marginTop: "1rem", borderBottom: 1, borderColor: "divider" }}>
{header}
</Box>
<ToastContainer
position="bottom-right"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
limit={11}
closeOnClick={false}
rtl={false}
draggable={true}
pauseOnHover={true}
transition={Slide}
theme="light"
/>
<span className="errors-header-text">Errors</span>
{content}
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
.vertex-details-header-text {
.errors-header-text {
font-size: 1.25rem;
font-style: normal;
font-weight: 500;
}

.errors-message-text {
color: #D52B1E;
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ export function PiplineCreate({
active: !!createdPipelineId,
});

// Call update complete on dismount if pipeline was created
useEffect(() => {
return () => {
if (createdPipelineId) {
onUpdateComplete && onUpdateComplete();
}
};
}, [createdPipelineId, onUpdateComplete]);

// Track creation process and close on completion
useEffect(() => {
if (!createdPipelineId) {
Expand Down
9 changes: 7 additions & 2 deletions ui/src/components/pages/Cluster/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from "react";
import React, { useContext, useMemo } from "react";
import Box from "@mui/material/Box";
import CircularProgress from "@mui/material/CircularProgress";
import {
Expand All @@ -9,20 +9,24 @@ import {
import { ClusterNamespaceListing } from "./partials/ClusterNamespaceListing";
import { ErrorDisplay } from "../../common/ErrorDisplay";
import { useClusterSummaryFetch } from "../../../utils/fetchWrappers/clusterSummaryFetch";
import { AppContextProps } from "../../../types/declarations/app";
import { AppContext } from "../../../App";

import "./style.css";

export function Cluster() {
const { addError } = useContext<AppContextProps>(AppContext);
const { data, loading, error } = useClusterSummaryFetch({
loadOnRefresh: false,
addError,
});

const summarySections: SummarySection[] = useMemo(() => {
if (loading) {
return [
{
type: SummarySectionType.CUSTOM,
customComponent: <CircularProgress />,
customComponent: <CircularProgress key="cluster-summary-loading" />,
},
];
}
Expand All @@ -32,6 +36,7 @@ export function Cluster() {
type: SummarySectionType.CUSTOM,
customComponent: (
<ErrorDisplay
key="cluster-summary-error"
title="Error loading cluster summary"
message={error}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Pagination from "@mui/material/Pagination";
import Grid from "@mui/material/Grid";
import { DebouncedSearchInput } from "../../../../common/DebouncedSearchInput";
import { NamespaceCard } from "../NamespaceCard";
import { ErrorIndicator } from "../../../../common/ErrorIndicator";
import {
ClusterNamespaceListingProps,
ClusterNamespaceSummary,
Expand Down Expand Up @@ -113,11 +114,20 @@ export function ClusterNamespaceListing({
<Box
sx={{ display: "flex", flexDirection: "column", padding: "0 2.625rem" }}
>
<Box sx={{ display: "flex", flexDirection: "row" }}>
<Box
sx={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<DebouncedSearchInput
placeHolder="Search for namespace"
onChange={setSearch}
/>
<Box>
<ErrorIndicator />
</Box>
</Box>
<Box sx={{ display: "flex", flexDirection: "row", marginTop: "2rem" }}>
<span className="cluster-ns-listing-table-title">Namespaces</span>
Expand Down
Loading

0 comments on commit 3ce92f0

Please sign in to comment.