diff --git a/ui/src/App.tsx b/ui/src/App.tsx index afcbadca0..173abaafd 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -1,9 +1,4 @@ -import React, { - FunctionComponent, - useState, - useEffect, - useCallback, -} from "react"; +import React, { FC, useState, useEffect, useCallback } from "react"; import { observer } from "mobx-react-lite"; @@ -34,108 +29,102 @@ interface AppProps { uiDefaults: UIDefaults | null; } -const App: FunctionComponent = observer( - ({ defaultFilters, uiDefaults }) => { - const [alertStore] = useState(new AlertStore(null)); - const [silenceFormStore] = useState( - new SilenceFormStore() - ); - const [settingsStore] = useState(new Settings(uiDefaults)); +const App: FC = observer(({ defaultFilters, uiDefaults }) => { + const [alertStore] = useState(new AlertStore(null)); + const [silenceFormStore] = useState(new SilenceFormStore()); + const [settingsStore] = useState(new Settings(uiDefaults)); - useEffect(() => { - let filters; - // parse and decode request query args - const p: { - params: { - q: string[]; - m?: string; - }; - defaultsUsed: boolean; - } = DecodeLocationSearch(window.location.search); - // p.defaultsUsed means that karma URI didn't have ?q=foo query args - if (p.defaultsUsed) { - // no ?q=foo set, use defaults saved by the user or from backend config - if (settingsStore.savedFilters.config.present) { - filters = settingsStore.savedFilters.config.filters; - } else { - filters = defaultFilters; - } - } else { - // user passed ?q=foo, use it as initial filters - filters = p.params.q; - } - alertStore.filters.setFilters(filters); - - if (p.params.m && silenceFormStore.data.fromBase64(p.params.m)) { - silenceFormStore.toggle.show(); - } - }, [alertStore, defaultFilters, settingsStore]); // eslint-disable-line react-hooks/exhaustive-deps - - const onPopState = useCallback( - (event: PopStateEvent) => { - event.preventDefault(); - const p = DecodeLocationSearch(window.location.search); - alertStore.filters.setWithoutLocation(p.params.q); - }, - [alertStore] - ); - - useEffect(() => { - window.onpopstate = onPopState; - return () => { - window.onpopstate = () => {}; + useEffect(() => { + let filters; + // parse and decode request query args + const p: { + params: { + q: string[]; + m?: string; }; - }, [onPopState]); + defaultsUsed: boolean; + } = DecodeLocationSearch(window.location.search); + // p.defaultsUsed means that karma URI didn't have ?q=foo query args + if (p.defaultsUsed) { + // no ?q=foo set, use defaults saved by the user or from backend config + if (settingsStore.savedFilters.config.present) { + filters = settingsStore.savedFilters.config.filters; + } else { + filters = defaultFilters; + } + } else { + // user passed ?q=foo, use it as initial filters + filters = p.params.q; + } + alertStore.filters.setFilters(filters); - const prefersColorScheme = useMediaPredicate("(prefers-color-scheme)"); - const prefersDark = useMediaPredicate("(prefers-color-scheme: dark)"); + if (p.params.m && silenceFormStore.data.fromBase64(p.params.m)) { + silenceFormStore.toggle.show(); + } + }, [alertStore, defaultFilters, settingsStore]); // eslint-disable-line react-hooks/exhaustive-deps - return ( - - - { + event.preventDefault(); + const p = DecodeLocationSearch(window.location.search); + alertStore.filters.setWithoutLocation(p.params.q); + }, + [alertStore] + ); + + useEffect(() => { + window.onpopstate = onPopState; + return () => { + window.onpopstate = () => {}; + }; + }, [onPopState]); + + const prefersColorScheme = useMediaPredicate("(prefers-color-scheme)"); + const prefersDark = useMediaPredicate("(prefers-color-scheme: dark)"); + + return ( + + + - - - - - - - - - ); - } -); + : ReactSelectStyles(ReactSelectColors.Light) + : settingsStore.themeConfig.config.theme === + settingsStore.themeConfig.options.dark.value + ? ReactSelectStyles(ReactSelectColors.Dark) + : ReactSelectStyles(ReactSelectColors.Light), + animations: { + duration: settingsStore.themeConfig.config.animations ? 500 : 0, + }, + }} + > + + + + + + + + + ); +}); export { App }; diff --git a/ui/src/Components/Accordion/index.tsx b/ui/src/Components/Accordion/index.tsx index a5926425b..ce9c03d75 100644 --- a/ui/src/Components/Accordion/index.tsx +++ b/ui/src/Components/Accordion/index.tsx @@ -1,11 +1,8 @@ -import React, { FunctionComponent, ReactNode, useState } from "react"; +import React, { FC, ReactNode, useState } from "react"; import { ToggleIcon } from "Components/ToggleIcon"; -const Trigger: FunctionComponent<{ text: string; isOpen: boolean }> = ({ - text, - isOpen, -}) => ( +const Trigger: FC<{ text: string; isOpen: boolean }> = ({ text, isOpen }) => (
{text}
@@ -14,7 +11,7 @@ const Trigger: FunctionComponent<{ text: string; isOpen: boolean }> = ({
); -const Accordion: FunctionComponent<{ +const Accordion: FC<{ text: string; content: ReactNode; defaultIsOpen?: boolean; diff --git a/ui/src/Components/DateFromNow/index.tsx b/ui/src/Components/DateFromNow/index.tsx index 49992c8f7..274b11a86 100644 --- a/ui/src/Components/DateFromNow/index.tsx +++ b/ui/src/Components/DateFromNow/index.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent, useState, useEffect } from "react"; +import React, { FC, useState, useEffect } from "react"; import parseISO from "date-fns/parseISO"; import differenceInSeconds from "date-fns/differenceInSeconds"; @@ -15,9 +15,7 @@ const formatLabel = (timestamp: string) => { }); }; -export const DateFromNow: FunctionComponent<{ timestamp: string }> = ({ - timestamp, -}) => { +export const DateFromNow: FC<{ timestamp: string }> = ({ timestamp }) => { const [label, setLabel] = useState(formatLabel(timestamp)); useEffect(() => { diff --git a/ui/src/Components/ToggleIcon/index.tsx b/ui/src/Components/ToggleIcon/index.tsx index 269ab5436..4c127d5a8 100644 --- a/ui/src/Components/ToggleIcon/index.tsx +++ b/ui/src/Components/ToggleIcon/index.tsx @@ -1,9 +1,9 @@ -import React, { FunctionComponent } from "react"; +import React, { FC } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; -const ToggleIcon: FunctionComponent<{ +const ToggleIcon: FC<{ isOpen: boolean; className?: string; onClick?: () => void; diff --git a/ui/src/ErrorBoundary.tsx b/ui/src/ErrorBoundary.tsx index 8d67aeed7..517971ec9 100644 --- a/ui/src/ErrorBoundary.tsx +++ b/ui/src/ErrorBoundary.tsx @@ -1,9 +1,4 @@ -import React, { - Component, - StatelessComponent, - ReactNode, - ErrorInfo, -} from "react"; +import React, { Component, FC, ReactNode, ErrorInfo } from "react"; import { captureException } from "@sentry/browser"; @@ -16,7 +11,7 @@ interface InternalErrorProps { progressLeft: number; } -const InternalError: StatelessComponent = (props) => ( +const InternalError: FC = (props) => (

@@ -78,7 +73,9 @@ class ErrorBoundary extends Component { componentDidCatch(error: Error, { componentStack }: ErrorInfo): void { if (this.state.cachedError === null) { this.setState({ cachedError: error }); - captureException(error, { contexts: { react: { componentStack } } }); + captureException(error, { + contexts: { react: { componentStack } }, + }); } // reload after 60s, this is to fix wall monitors automatically // but only if the timer isn't set yet