Merge pull request #1074 from prymitive/more-ts

chore(ui): migrate App component to typescript
This commit is contained in:
Łukasz Mierzwa
2019-10-24 22:07:19 +01:00
committed by GitHub
3 changed files with 59 additions and 44 deletions

View File

@@ -1,5 +1,4 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Provider } from "mobx-react";
@@ -14,24 +13,27 @@ import { ErrorBoundary } from "./ErrorBoundary";
import "./App.scss";
class App extends Component {
static propTypes = {
defaultFilters: PropTypes.arrayOf(PropTypes.string).isRequired,
uiDefaults: PropTypes.exact({
Refresh: PropTypes.number.isRequired,
HideFiltersWhenIdle: PropTypes.bool.isRequired,
ColorTitlebar: PropTypes.bool.isRequired,
MinimalGroupWidth: PropTypes.number.isRequired,
AlertsPerGroup: PropTypes.number.isRequired,
CollapseGroups: PropTypes.oneOf([
"expanded",
"collapsed",
"collapsedOnMobile"
]).isRequired
})
};
interface UIDefaults {
Refresh: number;
HideFiltersWhenIdle: boolean;
ColorTitlebar: boolean;
MinimalGroupWidth: number;
AlertsPerGroup: number;
CollapseGroups: "expanded" | "collapsed" | "collapsedOnMobile";
}
constructor(props) {
interface AppProps {
defaultFilters: Array<string>;
uiDefaults: UIDefaults;
}
class App extends Component<AppProps, {}> {
alertStore: AlertStore;
silenceFormStore: SilenceFormStore;
settingsStore: Settings;
filters: Array<string> = [];
constructor(props: AppProps) {
super(props);
const { defaultFilters, uiDefaults } = this.props;

View File

@@ -52,7 +52,7 @@ describe("<ErrorBoundary />", () => {
});
it("componentDidCatch passes scope to sentry", () => {
const sentrySpy = jest.spyOn(Sentry, "configureScope");
const sentrySpy = jest.spyOn(Sentry, "captureException");
Sentry.init({ dsn: "https://foobar@localhost/123456" });
const tree = mount(

View File

@@ -1,12 +1,22 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import React, {
Component,
StatelessComponent,
ReactNode,
ErrorInfo
} from "react";
import * as Sentry from "@sentry/browser";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBomb } from "@fortawesome/free-solid-svg-icons/faBomb";
const InternalError = ({ message, secondsLeft, progressLeft }) => (
interface InternalErrorProps {
message: ReactNode;
secondsLeft: number;
progressLeft: number;
}
const InternalError: StatelessComponent<InternalErrorProps> = props => (
<div className="jumbotron text-center bg-primary my-4">
<div className="container-fluid">
<h1 className="display-1 my-5">
@@ -14,10 +24,10 @@ const InternalError = ({ message, secondsLeft, progressLeft }) => (
<span className="text-muted">Internal error</span>
</h1>
<p className="lead text-white bg-secondary px-1 py-3 rounded">
{message}
{props.message}
</p>
<p className="text-muted d-inline-block">
This page will auto refresh in {secondsLeft}s
This page will auto refresh in {props.secondsLeft}s
<span
className="progress bg-secondary mx-auto"
style={{ height: "2px" }}
@@ -25,31 +35,36 @@ const InternalError = ({ message, secondsLeft, progressLeft }) => (
<span
className="progress-bar bg-info"
role="progressbar"
style={{ width: `${progressLeft}%` }}
aria-valuenow={progressLeft}
aria-valuemin="0"
aria-valuemax="100"
style={{ width: `${props.progressLeft}%` }}
aria-valuenow={props.progressLeft}
aria-valuemin={0}
aria-valuemax={100}
></span>
</span>
</p>
</div>
</div>
);
InternalError.propTypes = {
message: PropTypes.node.isRequired,
secondsLeft: PropTypes.number.isRequired,
progressLeft: PropTypes.number.isRequired
};
class ErrorBoundary extends Component {
static propTypes = {
children: PropTypes.any
interface ErrorBoundaryProps {
children: React.ReactNode;
}
interface ErrorBoundaryState {
cachedError: Error | null;
reloadSeconds: number;
}
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
timer: ReturnType<typeof setInterval> | null;
state: Readonly<ErrorBoundaryState> = {
cachedError: null,
reloadSeconds: 60
};
constructor(props) {
constructor(props: ErrorBoundaryProps) {
super(props);
this.timer = null;
this.state = { cachedError: null, reloadSeconds: 60 };
}
reloadApp = () => {
@@ -60,14 +75,12 @@ class ErrorBoundary extends Component {
}
};
componentDidCatch(error, errorInfo) {
componentDidCatch(error: Error | null, errorInfo: ErrorInfo) {
this.setState({ cachedError: error });
Sentry.configureScope(scope => {
Object.keys(errorInfo).forEach(key => {
scope.setExtra(key, errorInfo[key]);
});
Sentry.withScope(scope => {
scope.setExtras(errorInfo);
Sentry.captureException(error);
});
Sentry.captureException(error);
// reload after 60s, this is to fix wall monitors automatically
// but only if the timer isn't set yet
if (this.timer === null) {