Error indicator
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import ErrorOutline from "@mui/icons-material/ErrorOutline";
|
||||
import {
|
||||
CircularProgress,
|
||||
Stack,
|
||||
Typography,
|
||||
type CircularProgressProps,
|
||||
} from "@mui/material";
|
||||
import { t } from "i18next";
|
||||
import type React from "react";
|
||||
|
||||
/**
|
||||
@@ -27,3 +29,21 @@ export const ActivityIndicator: React.FC<
|
||||
) : (
|
||||
<CircularProgress color="accent" size={32} {...rest} />
|
||||
);
|
||||
|
||||
/**
|
||||
* An error message indicator, styled to complement {@link ActivityIndicator}.
|
||||
*
|
||||
* If a child is provided, it is used as the error message to show (after being
|
||||
* wrapped in a suitable {@link Typography}). Otherwise the default generic
|
||||
* error message is shown.
|
||||
*/
|
||||
export const ErrorIndicator: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => (
|
||||
<Stack sx={{ gap: 2, alignItems: "center" }}>
|
||||
<ErrorOutline color="secondary" sx={{ color: "critical" }} />
|
||||
<Typography color="text.muted">
|
||||
{children ?? t("generic_error")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { ActivityIndicator } from "@/base/components/mui/ActivityIndicator";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
ErrorIndicator,
|
||||
} from "@/base/components/mui/ActivityIndicator";
|
||||
import { CenteredBox } from "@/base/components/mui/Container";
|
||||
import { FocusVisibleButton } from "@/base/components/mui/FocusVisibleButton";
|
||||
import { LoadingButton } from "@/base/components/mui/LoadingButton";
|
||||
@@ -250,10 +253,10 @@ const SuggestionsDialog: React.FC<SuggestionsDialogProps> = ({
|
||||
onClose,
|
||||
person,
|
||||
}) => {
|
||||
const { showMiniDialog } = useAppContext();
|
||||
const { showMiniDialog, onGenericError } = useAppContext();
|
||||
|
||||
const [phase, setPhase] = useState<
|
||||
"loading" | "failed" | "saving" | undefined
|
||||
"loading" | "fetch-failed" | "saving" | undefined
|
||||
>();
|
||||
const [suggestions, setSuggestions] = useState<PersonSuggestion[]>([]);
|
||||
const [unsavedChanges /*, setUnsavedChanges */] = useState(false);
|
||||
@@ -292,7 +295,7 @@ const SuggestionsDialog: React.FC<SuggestionsDialogProps> = ({
|
||||
resetPhaseAndClose();
|
||||
} catch (e) {
|
||||
log.error("Failed to save suggestion review", e);
|
||||
setPhase("failed");
|
||||
onGenericError(e);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -302,14 +305,28 @@ const SuggestionsDialog: React.FC<SuggestionsDialogProps> = ({
|
||||
setPhase("loading");
|
||||
|
||||
let ignore = false;
|
||||
void suggestionsForPerson(person).then(async (suggestions) => {
|
||||
setPhase(undefined);
|
||||
if (!ignore) setSuggestions(suggestions);
|
||||
});
|
||||
|
||||
const go = async () => {
|
||||
try {
|
||||
const suggestions = await suggestionsForPerson(person);
|
||||
if (!ignore) {
|
||||
setPhase(undefined);
|
||||
setSuggestions(suggestions);
|
||||
}
|
||||
} catch (e) {
|
||||
log.error("Failed to generate suggestions", e);
|
||||
if (!ignore) {
|
||||
setPhase("fetch-failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void go();
|
||||
|
||||
return () => {
|
||||
ignore = true;
|
||||
};
|
||||
}, [open, person]);
|
||||
}, [open, person, onGenericError]);
|
||||
|
||||
console.log({ open, person });
|
||||
|
||||
@@ -332,6 +349,10 @@ const SuggestionsDialog: React.FC<SuggestionsDialogProps> = ({
|
||||
{pt("Finding similar faces...")}
|
||||
</ActivityIndicator>
|
||||
</CenteredBox>
|
||||
) : phase == "fetch-failed" ? (
|
||||
<CenteredBox>
|
||||
<ErrorIndicator />
|
||||
</CenteredBox>
|
||||
) : suggestions.length == 0 ? (
|
||||
<CenteredBox>
|
||||
<Typography
|
||||
|
||||
Reference in New Issue
Block a user