From 84321fe77444143dc038eba317dd836b398c818d Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Wed, 18 Oct 2023 13:53:22 -0700 Subject: [PATCH] display error when the aggregator bearer token is rejected --- app/src/aggregators/AggregatorDetail.tsx | 198 +----------------- .../aggregators/DeleteAggregatorButton.tsx | 56 +++++ .../aggregators/RenameAggregatorButton.tsx | 74 +++++++ .../aggregators/RotateBearerTokenButton.tsx | 83 ++++++++ 4 files changed, 220 insertions(+), 191 deletions(-) create mode 100644 app/src/aggregators/DeleteAggregatorButton.tsx create mode 100644 app/src/aggregators/RenameAggregatorButton.tsx create mode 100644 app/src/aggregators/RotateBearerTokenButton.tsx diff --git a/app/src/aggregators/AggregatorDetail.tsx b/app/src/aggregators/AggregatorDetail.tsx index 89486aac..52eb91b5 100644 --- a/app/src/aggregators/AggregatorDetail.tsx +++ b/app/src/aggregators/AggregatorDetail.tsx @@ -1,35 +1,19 @@ -import { - Await, - useFetcher, - useLoaderData, - useNavigation, - useParams, -} from "react-router-dom"; +import { Await, useLoaderData, useParams } from "react-router-dom"; import { Aggregator } from "../ApiClient"; import { AccountBreadcrumbs } from "../util"; import { LinkContainer } from "react-router-bootstrap"; import Breadcrumb from "react-bootstrap/Breadcrumb"; -import React, { Suspense, useEffect, useState } from "react"; +import React, { Suspense } from "react"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; -import { - ArrowRepeat, - CloudUpload, - Pencil, - PencilSquare, - Trash, -} from "react-bootstrap-icons"; +import { CloudUpload } from "react-bootstrap-icons"; import Table from "react-bootstrap/Table"; import D from "../logo/color/svg/small.svg"; import Placeholder from "react-bootstrap/Placeholder"; -import { - Button, - ButtonGroup, - FormControl, - FormGroup, - FormLabel, - Modal, -} from "react-bootstrap"; +import { ButtonGroup } from "react-bootstrap"; +import RotateBearerTokenButton from "./RotateBearerTokenButton"; +import RenameAggregatorButton from "./RenameAggregatorButton"; +import DeleteAggregatorButton from "./DeleteAggregatorButton"; function Breadcrumbs() { const { aggregator } = useLoaderData() as { @@ -174,171 +158,3 @@ export function WithAggregator({ ); } - -function RenameAggregatorButton() { - const navigation = useNavigation(); - - const [show, setShow] = useState(false); - const close = React.useCallback(() => setShow(false), []); - const open = React.useCallback(() => setShow(true), []); - const fetcher = useFetcher(); - - useEffect(() => { - if (fetcher.data) close(); - }, [fetcher, close]); - - return ( - <> - - - - - - Rename{" "} - {({ name }) => `"${name}"`} - - - - - Name - - {({ name }) => ( - - )} - - - - - - - - - - - ); -} - -function RotateBearerTokenButton() { - const navigation = useNavigation(); - - const [show, setShow] = useState(false); - const close = React.useCallback(() => setShow(false), []); - const open = React.useCallback(() => setShow(true), []); - const fetcher = useFetcher(); - - useEffect(() => { - if (fetcher.data) close(); - }, [fetcher, close]); - - return ( - <> - - - - - - Rotate Bearer Token for{" "} - {({ name }) => `"${name}"`} - - - - - New Bearer Token - - - - - - - - - - - ); -} - -function DeleteAggregatorButton() { - const navigation = useNavigation(); - - const [show, setShow] = useState(false); - const close = React.useCallback(() => setShow(false), []); - const open = React.useCallback(() => setShow(true), []); - const fetcher = useFetcher(); - - useEffect(() => { - if (fetcher.data) close(); - }, [fetcher, close]); - - return ( - <> - - - - - Delete {({ name }) => `"${name}"`}? - - - - This aggregator will immediately be removed from the interface and no - new tasks can be created with it. - - - - - - - - - - ); -} diff --git a/app/src/aggregators/DeleteAggregatorButton.tsx b/app/src/aggregators/DeleteAggregatorButton.tsx new file mode 100644 index 00000000..aa870ada --- /dev/null +++ b/app/src/aggregators/DeleteAggregatorButton.tsx @@ -0,0 +1,56 @@ +import { useFetcher, useNavigation } from "react-router-dom"; +import React, { useEffect, useState } from "react"; +import { Trash } from "react-bootstrap-icons"; +import { Button, Modal } from "react-bootstrap"; +import { WithAggregator } from "./AggregatorDetail"; + +export default function DeleteAggregatorButton() { + const navigation = useNavigation(); + + const [show, setShow] = useState(false); + const close = React.useCallback(() => setShow(false), []); + const open = React.useCallback(() => setShow(true), []); + const fetcher = useFetcher(); + + useEffect(() => { + if (fetcher.data) close(); + }, [fetcher, close]); + + return ( + <> + + + + + Delete {({ name }) => `"${name}"`}? + + + + This aggregator will immediately be removed from the interface and no + new tasks can be created with it. + + + + + + + + + + ); +} diff --git a/app/src/aggregators/RenameAggregatorButton.tsx b/app/src/aggregators/RenameAggregatorButton.tsx new file mode 100644 index 00000000..f9061cc3 --- /dev/null +++ b/app/src/aggregators/RenameAggregatorButton.tsx @@ -0,0 +1,74 @@ +import { useFetcher, useNavigation } from "react-router-dom"; +import React, { useEffect, useState } from "react"; +import { Pencil, PencilSquare } from "react-bootstrap-icons"; +import { + Button, + FormControl, + FormGroup, + FormLabel, + Modal, +} from "react-bootstrap"; +import { WithAggregator } from "./AggregatorDetail"; + +export default function RenameAggregatorButton() { + const navigation = useNavigation(); + + const [show, setShow] = useState(false); + const close = React.useCallback(() => setShow(false), []); + const open = React.useCallback(() => setShow(true), []); + const fetcher = useFetcher(); + + useEffect(() => { + if (fetcher.data) close(); + }, [fetcher, close]); + + return ( + <> + + + + + + Rename{" "} + {({ name }) => `"${name}"`} + + + + + Name + + {({ name }) => ( + + )} + + + + + + + + + + + ); +} diff --git a/app/src/aggregators/RotateBearerTokenButton.tsx b/app/src/aggregators/RotateBearerTokenButton.tsx new file mode 100644 index 00000000..14e66a62 --- /dev/null +++ b/app/src/aggregators/RotateBearerTokenButton.tsx @@ -0,0 +1,83 @@ +import { useFetcher, useNavigation } from "react-router-dom"; +import React, { useEffect, useState } from "react"; +import { ArrowRepeat } from "react-bootstrap-icons"; +import { + Button, + FormControl, + FormGroup, + FormLabel, + Modal, +} from "react-bootstrap"; +import { WithAggregator } from "./AggregatorDetail"; +import { UpdateAggregator, formikErrors } from "../ApiClient"; +import { FormikErrors } from "formik"; + +export default function RotateBearerTokenButton() { + const navigation = useNavigation(); + const [show, setShow] = useState(false); + const close = React.useCallback(() => setShow(false), []); + const open = React.useCallback(() => setShow(true), []); + const fetcher = useFetcher(); + const [errors, setErrors] = React.useState( + null as null | FormikErrors, + ); + + useEffect(() => { + if (fetcher.data) { + if ("error" in fetcher.data) { + setErrors(formikErrors(fetcher.data.error)); + } else { + close(); + setErrors(null); + } + } + }, [fetcher.data, close]); + + return ( + <> + + + + + + Rotate Bearer Token for{" "} + {({ name }) => `"${name}"`} + + + + + New Bearer Token + + + {errors?.bearer_token} + + + + + + + + + + + ); +}