chore(ui): use FC for function components

This commit is contained in:
Łukasz Mierzwa
2021-04-04 19:52:45 +01:00
committed by Łukasz Mierzwa
parent c85a47ae13
commit ab36d3bfbc
5 changed files with 105 additions and 124 deletions

View File

@@ -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<AppProps> = observer(
({ defaultFilters, uiDefaults }) => {
const [alertStore] = useState<AlertStore>(new AlertStore(null));
const [silenceFormStore] = useState<SilenceFormStore>(
new SilenceFormStore()
);
const [settingsStore] = useState<Settings>(new Settings(uiDefaults));
const App: FC<AppProps> = observer(({ defaultFilters, uiDefaults }) => {
const [alertStore] = useState<AlertStore>(new AlertStore(null));
const [silenceFormStore] = useState<SilenceFormStore>(new SilenceFormStore());
const [settingsStore] = useState<Settings>(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 (
<ErrorBoundary>
<span data-theme={`${settingsStore.themeConfig.config.theme}`} />
<ThemeContext.Provider
value={{
isDark:
settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.auto.value &&
prefersColorScheme
? prefersDark
: settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.dark.value,
reactSelectStyles:
settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.auto.value &&
prefersColorScheme
? prefersDark
? ReactSelectStyles(ReactSelectColors.Dark)
: ReactSelectStyles(ReactSelectColors.Light)
: settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.dark.value
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 = () => {};
};
}, [onPopState]);
const prefersColorScheme = useMediaPredicate("(prefers-color-scheme)");
const prefersDark = useMediaPredicate("(prefers-color-scheme: dark)");
return (
<ErrorBoundary>
<span data-theme={`${settingsStore.themeConfig.config.theme}`} />
<ThemeContext.Provider
value={{
isDark:
settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.auto.value && prefersColorScheme
? prefersDark
: settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.dark.value,
reactSelectStyles:
settingsStore.themeConfig.config.theme ===
settingsStore.themeConfig.options.auto.value && prefersColorScheme
? prefersDark
? ReactSelectStyles(ReactSelectColors.Dark)
: ReactSelectStyles(ReactSelectColors.Light),
animations: {
duration: settingsStore.themeConfig.config.animations ? 500 : 0,
},
}}
>
<BodyTheme />
<React.Suspense fallback={null}>
<NavBar
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
<Grid
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
<FaviconBadge alertStore={alertStore} />
</React.Suspense>
</ThemeContext.Provider>
</ErrorBoundary>
);
}
);
: 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,
},
}}
>
<BodyTheme />
<React.Suspense fallback={null}>
<NavBar
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
<Grid
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
<FaviconBadge alertStore={alertStore} />
</React.Suspense>
</ThemeContext.Provider>
</ErrorBoundary>
);
});
export { App };

View File

@@ -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 }) => (
<div className="d-flex flex-row justify-content-between">
<div>{text}</div>
<div>
@@ -14,7 +11,7 @@ const Trigger: FunctionComponent<{ text: string; isOpen: boolean }> = ({
</div>
);
const Accordion: FunctionComponent<{
const Accordion: FC<{
text: string;
content: ReactNode;
defaultIsOpen?: boolean;

View File

@@ -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<string>(formatLabel(timestamp));
useEffect(() => {

View File

@@ -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;

View File

@@ -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<InternalErrorProps> = (props) => (
const InternalError: FC<InternalErrorProps> = (props) => (
<div className="text-placeholder screen-center">
<div className="container-fluid text-center">
<h1 className="display-1">
@@ -78,7 +73,9 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
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