From a051331680b21f20201a47601d69505a4cfa9e40 Mon Sep 17 00:00:00 2001
From: muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com>
Date: Sat, 19 Nov 2022 15:21:09 +0530
Subject: Transform service components to ts (#778)
---
.../services/content/ConnectionLostBanner.js | 104 -----------
.../services/content/ConnectionLostBanner.tsx | 99 +++++++++++
.../content/ErrorHandlers/WebviewErrorHandler.js | 75 --------
.../services/content/ErrorHandlers/styles.ts | 25 ---
src/components/services/content/ServiceDisabled.js | 43 -----
.../services/content/ServiceDisabled.tsx | 41 +++++
src/components/services/content/ServiceView.js | 190 --------------------
src/components/services/content/ServiceView.tsx | 192 +++++++++++++++++++++
src/components/services/content/Services.tsx | 22 +--
.../services/content/WebviewCrashHandler.js | 84 ---------
.../services/content/WebviewCrashHandler.tsx | 90 ++++++++++
.../services/content/WebviewErrorHandler.tsx | 96 +++++++++++
12 files changed, 529 insertions(+), 532 deletions(-)
delete mode 100644 src/components/services/content/ConnectionLostBanner.js
create mode 100644 src/components/services/content/ConnectionLostBanner.tsx
delete mode 100644 src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
delete mode 100644 src/components/services/content/ErrorHandlers/styles.ts
delete mode 100644 src/components/services/content/ServiceDisabled.js
create mode 100644 src/components/services/content/ServiceDisabled.tsx
delete mode 100644 src/components/services/content/ServiceView.js
create mode 100644 src/components/services/content/ServiceView.tsx
delete mode 100644 src/components/services/content/WebviewCrashHandler.js
create mode 100644 src/components/services/content/WebviewCrashHandler.tsx
create mode 100644 src/components/services/content/WebviewErrorHandler.tsx
(limited to 'src/components/services/content')
diff --git a/src/components/services/content/ConnectionLostBanner.js b/src/components/services/content/ConnectionLostBanner.js
deleted file mode 100644
index f2f70ca2e..000000000
--- a/src/components/services/content/ConnectionLostBanner.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { observer } from 'mobx-react';
-import injectSheet from 'react-jss';
-import { defineMessages, injectIntl } from 'react-intl';
-
-import { mdiAlert } from '@mdi/js';
-import { LIVE_API_FERDIUM_WEBSITE } from '../../../config';
-import Icon from '../../ui/icon';
-
-const messages = defineMessages({
- text: {
- id: 'connectionLostBanner.message',
- defaultMessage: 'Oh no! Ferdium lost the connection to {name}.',
- },
- moreInformation: {
- id: 'connectionLostBanner.informationLink',
- defaultMessage: 'What happened?',
- },
- cta: {
- id: 'connectionLostBanner.cta',
- defaultMessage: 'Reload Service',
- },
-});
-
-let buttonTransition = 'none';
-
-if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) {
- buttonTransition = 'opacity 0.25s';
-}
-
-const styles = theme => ({
- root: {
- background: theme.colorBackground,
- borderRadius: theme.borderRadius,
- position: 'absolute',
- zIndex: 300,
- height: 50,
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- bottom: 10,
- right: 10,
- justifyContent: 'center',
- padding: 10,
- fontSize: 12,
- },
- link: {
- display: 'inline-flex',
- opacity: 0.7,
- },
- button: {
- transition: buttonTransition,
- color: theme.colorText,
- border: [1, 'solid', theme.colorText],
- borderRadius: theme.borderRadiusSmall,
- padding: 4,
- fontSize: 12,
- marginLeft: 15,
-
- '&:hover': {
- opacity: 0.8,
- },
- },
- icon: {
- marginRight: 10,
- fill: theme.styleTypes.danger.accent,
- },
-});
-
-class ConnectionLostBanner extends Component {
- static propTypes = {
- classes: PropTypes.object.isRequired,
- name: PropTypes.string.isRequired,
- reload: PropTypes.func.isRequired,
- };
-
- render() {
- const { classes, name, reload } = this.props;
-
- const { intl } = this.props;
-
- return (
-
- );
- }
-}
-
-export default injectIntl(injectSheet(styles)(observer(ConnectionLostBanner)));
diff --git a/src/components/services/content/ConnectionLostBanner.tsx b/src/components/services/content/ConnectionLostBanner.tsx
new file mode 100644
index 000000000..88731f3b9
--- /dev/null
+++ b/src/components/services/content/ConnectionLostBanner.tsx
@@ -0,0 +1,99 @@
+import { Component, ReactElement } from 'react';
+import { observer } from 'mobx-react';
+import withStyles, { WithStylesProps } from 'react-jss';
+import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
+import { mdiAlert } from '@mdi/js';
+import { LIVE_API_FERDIUM_WEBSITE } from '../../../config';
+import Icon from '../../ui/icon';
+
+const messages = defineMessages({
+ text: {
+ id: 'connectionLostBanner.message',
+ defaultMessage: 'Oh no! Ferdium lost the connection to {name}.',
+ },
+ moreInformation: {
+ id: 'connectionLostBanner.informationLink',
+ defaultMessage: 'What happened?',
+ },
+ cta: {
+ id: 'connectionLostBanner.cta',
+ defaultMessage: 'Reload Service',
+ },
+});
+
+const buttonTransition =
+ window && window.matchMedia('(prefers-reduced-motion: no-preference)')
+ ? 'opacity 0.25s'
+ : 'none';
+
+const styles = theme => ({
+ root: {
+ background: theme.colorBackground,
+ borderRadius: theme.borderRadius,
+ position: 'absolute',
+ zIndex: 300,
+ height: 50,
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ bottom: 10,
+ right: 10,
+ justifyContent: 'center',
+ padding: 10,
+ fontSize: 12,
+ },
+ link: {
+ display: 'inline-flex',
+ opacity: 0.7,
+ },
+ button: {
+ transition: buttonTransition,
+ color: theme.colorText,
+ border: [1, 'solid', theme.colorText],
+ borderRadius: theme.borderRadiusSmall,
+ padding: 4,
+ fontSize: 12,
+ marginLeft: 15,
+
+ '&:hover': {
+ opacity: 0.8,
+ },
+ },
+ icon: {
+ marginRight: 10,
+ fill: theme.styleTypes.danger.accent,
+ },
+});
+
+interface IProps extends WithStylesProps, WrappedComponentProps {
+ name: string;
+ reload: () => void;
+}
+
+@observer
+class ConnectionLostBanner extends Component {
+ render(): ReactElement {
+ const { classes, name, reload, intl } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+export default injectIntl(withStyles(styles)(ConnectionLostBanner));
diff --git a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
deleted file mode 100644
index a658bec8b..000000000
--- a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { observer } from 'mobx-react';
-import { defineMessages, injectIntl } from 'react-intl';
-import injectSheet from 'react-jss';
-
-import Button from '../../../ui/button';
-
-import styles from './styles';
-import { H1 } from '../../../ui/headline';
-
-const messages = defineMessages({
- headline: {
- id: 'service.errorHandler.headline',
- defaultMessage: 'Oh no!',
- },
- text: {
- id: 'service.errorHandler.text',
- defaultMessage: '{name} has failed to load.',
- },
- action: {
- id: 'service.errorHandler.action',
- defaultMessage: 'Reload {name}',
- },
- editAction: {
- id: 'service.errorHandler.editAction',
- defaultMessage: 'Edit {name}',
- },
- errorMessage: {
- id: 'service.errorHandler.message',
- defaultMessage: 'Error',
- },
-});
-
-class WebviewErrorHandler extends Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- reload: PropTypes.func.isRequired,
- edit: PropTypes.func.isRequired,
- errorMessage: PropTypes.string.isRequired,
- classes: PropTypes.object.isRequired,
- };
-
- render() {
- const { name, reload, edit, errorMessage, classes } = this.props;
- const { intl } = this.props;
-
- return (
-
-
{intl.formatMessage(messages.headline)}
-
{intl.formatMessage(messages.text, { name })}
-
- {intl.formatMessage(messages.errorMessage)}:{' '}
- {errorMessage}
-
-
-
-
- );
- }
-}
-
-export default injectIntl(
- injectSheet(styles, { injectTheme: true })(observer(WebviewErrorHandler)),
-);
diff --git a/src/components/services/content/ErrorHandlers/styles.ts b/src/components/services/content/ErrorHandlers/styles.ts
deleted file mode 100644
index 9e2509ee5..000000000
--- a/src/components/services/content/ErrorHandlers/styles.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export default theme => ({
- component: {
- left: 0,
- position: 'absolute',
- top: 0,
- width: '100%',
- zIndex: 0,
- alignItems: 'center',
- background: theme.colorWebviewErrorHandlerBackground,
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- textAlign: 'center',
- },
- buttonContainer: {
- display: 'flex',
- flexDirection: 'row',
- height: 'auto',
- margin: [40, 0, 20],
-
- '& button': {
- margin: [0, 10, 0, 10],
- },
- },
-});
diff --git a/src/components/services/content/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js
deleted file mode 100644
index d874a354e..000000000
--- a/src/components/services/content/ServiceDisabled.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { observer } from 'mobx-react';
-import { defineMessages, injectIntl } from 'react-intl';
-
-import Button from '../../ui/button';
-import { H1 } from '../../ui/headline';
-
-const messages = defineMessages({
- headline: {
- id: 'service.disabledHandler.headline',
- defaultMessage: '{name} is disabled',
- },
- action: {
- id: 'service.disabledHandler.action',
- defaultMessage: 'Enable {name}',
- },
-});
-
-class ServiceDisabled extends Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- enable: PropTypes.func.isRequired,
- };
-
- render() {
- const { name, enable } = this.props;
- const { intl } = this.props;
-
- return (
-
-
{intl.formatMessage(messages.headline, { name })}
- enable()}
- />
-
- );
- }
-}
-
-export default injectIntl(observer(ServiceDisabled));
diff --git a/src/components/services/content/ServiceDisabled.tsx b/src/components/services/content/ServiceDisabled.tsx
new file mode 100644
index 000000000..2f0d439ec
--- /dev/null
+++ b/src/components/services/content/ServiceDisabled.tsx
@@ -0,0 +1,41 @@
+import { Component, ReactElement } from 'react';
+import { observer } from 'mobx-react';
+import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
+import Button from '../../ui/button';
+import { H1 } from '../../ui/headline';
+
+const messages = defineMessages({
+ headline: {
+ id: 'service.disabledHandler.headline',
+ defaultMessage: '{name} is disabled',
+ },
+ action: {
+ id: 'service.disabledHandler.action',
+ defaultMessage: 'Enable {name}',
+ },
+});
+
+interface IProps extends WrappedComponentProps {
+ name: string;
+ enable: () => void;
+}
+
+@observer
+class ServiceDisabled extends Component {
+ render(): ReactElement {
+ const { name, enable, intl } = this.props;
+
+ return (
+
+
{intl.formatMessage(messages.headline, { name })}
+ enable()}
+ />
+
+ );
+ }
+}
+
+export default injectIntl(ServiceDisabled);
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js
deleted file mode 100644
index cae16ef49..000000000
--- a/src/components/services/content/ServiceView.js
+++ /dev/null
@@ -1,190 +0,0 @@
-/* eslint-disable react/jsx-no-useless-fragment */
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { autorun } from 'mobx';
-import { observer, inject } from 'mobx-react';
-import classnames from 'classnames';
-import TopBarProgress from 'react-topbar-progress-indicator';
-
-import ServiceModel from '../../../models/Service';
-import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl';
-import WebviewLoader from '../../ui/WebviewLoader';
-import WebviewCrashHandler from './WebviewCrashHandler';
-import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler';
-import ServiceDisabled from './ServiceDisabled';
-import ServiceWebview from './ServiceWebview';
-import SettingsStore from '../../../stores/SettingsStore';
-import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen';
-import { CUSTOM_WEBSITE_RECIPE_ID } from '../../../config';
-
-class ServiceView extends Component {
- static propTypes = {
- service: PropTypes.instanceOf(ServiceModel).isRequired,
- setWebviewReference: PropTypes.func.isRequired,
- detachService: PropTypes.func.isRequired,
- reload: PropTypes.func.isRequired,
- edit: PropTypes.func.isRequired,
- enable: PropTypes.func.isRequired,
- isActive: PropTypes.bool,
- stores: PropTypes.shape({
- settings: PropTypes.instanceOf(SettingsStore).isRequired,
- }).isRequired,
- isSpellcheckerEnabled: PropTypes.bool.isRequired,
- };
-
- static defaultProps = {
- isActive: false,
- };
-
- state = {
- forceRepaint: false,
- targetUrl: '',
- statusBarVisible: false,
- };
-
- hibernationTimer = null;
-
- autorunDisposer = null;
-
- forceRepaintTimeout = null;
-
- componentDidMount() {
- this.autorunDisposer = autorun(() => {
- if (this.props.service.isActive) {
- this.setState({ forceRepaint: true });
- this.forceRepaintTimeout = setTimeout(() => {
- this.setState({ forceRepaint: false });
- }, 100);
- }
- });
- }
-
- componentWillUnmount() {
- this.autorunDisposer();
- clearTimeout(this.forceRepaintTimeout);
- clearTimeout(this.hibernationTimer);
- }
-
- render() {
- const {
- detachService,
- service,
- setWebviewReference,
- reload,
- edit,
- enable,
- stores,
- isSpellcheckerEnabled,
- } = this.props;
-
- const { navigationBarBehaviour, navigationBarManualActive } =
- stores.settings.app;
-
- const showNavBar =
- navigationBarBehaviour === 'always' ||
- (navigationBarBehaviour === 'custom' &&
- service.recipe.id === CUSTOM_WEBSITE_RECIPE_ID) ||
- navigationBarManualActive;
-
- const webviewClasses = classnames({
- services__webview: true,
- 'services__webview-wrapper': true,
- 'is-active': service.isActive,
- 'services__webview--force-repaint': this.state.forceRepaint,
- });
-
- let statusBar = null;
- if (this.state.statusBarVisible) {
- statusBar = ;
- }
-
- return (
-
- {service.isActive && service.isEnabled && (
- <>
- {service.hasCrashed && (
-
- )}
- {service.isEnabled &&
- service.isLoading &&
- service.isFirstLoad &&
- !service.isHibernating &&
- !service.isServiceAccessRestricted && (
-
- )}
- {service.isProgressbarEnabled &&
- service.isLoadingPage &&
- !service.isFirstLoad &&
}
- {service.isError && (
-
- )}
- >
- )}
- {!service.isEnabled ? (
- <>
- {service.isActive && (
-
- )}
- >
- ) : (
- <>
- {!service.isHibernating ? (
- <>
- {showNavBar &&
}
-
- >
- ) : (
-
-
- 😴
-
-
-
- This service is currently hibernating.
-
- Try switching services or reloading Ferdium.
-
- )}
- >
- )}
- {statusBar}
-
- );
- }
-}
-
-export default inject('stores', 'actions')(observer(ServiceView));
diff --git a/src/components/services/content/ServiceView.tsx b/src/components/services/content/ServiceView.tsx
new file mode 100644
index 000000000..e41184431
--- /dev/null
+++ b/src/components/services/content/ServiceView.tsx
@@ -0,0 +1,192 @@
+import { Component } from 'react';
+import { autorun, IReactionDisposer } from 'mobx';
+import { observer, inject } from 'mobx-react';
+import classnames from 'classnames';
+import TopBarProgress from 'react-topbar-progress-indicator';
+import ServiceModel from '../../../models/Service';
+import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl';
+import WebviewLoader from '../../ui/WebviewLoader';
+import WebviewCrashHandler from './WebviewCrashHandler';
+import WebviewErrorHandler from './WebviewErrorHandler';
+import ServiceDisabled from './ServiceDisabled';
+import ServiceWebview from './ServiceWebview';
+import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen';
+import { CUSTOM_WEBSITE_RECIPE_ID } from '../../../config';
+import { RealStores } from '../../../stores';
+
+interface IProps {
+ service: ServiceModel;
+ setWebviewRef: () => void;
+ detachService: () => void;
+ reload: () => void;
+ edit: () => void;
+ enable: () => void;
+ // isActive?: boolean; // TODO - [TECH DEBT][PROP NOT USED IN COMPONENT] check it
+ stores?: RealStores;
+ isSpellcheckerEnabled: boolean;
+}
+
+interface IState {
+ forceRepaint: boolean;
+ targetUrl: string;
+ statusBarVisible: boolean;
+}
+
+@inject('stores', 'actions')
+@observer
+class ServiceView extends Component {
+ // hibernationTimer = null; // TODO - [TS DEBT] class property not reassigned, need to find its purpose
+
+ autorunDisposer: IReactionDisposer | undefined;
+
+ forceRepaintTimeout: NodeJS.Timeout | undefined;
+
+ constructor(props: IProps) {
+ super(props);
+
+ this.state = {
+ forceRepaint: false,
+ targetUrl: '',
+ statusBarVisible: false,
+ };
+ }
+
+ componentDidMount() {
+ this.autorunDisposer = autorun(() => {
+ if (this.props.service.isActive) {
+ this.setState({ forceRepaint: true });
+ this.forceRepaintTimeout = setTimeout(() => {
+ this.setState({ forceRepaint: false });
+ }, 100);
+ }
+ });
+ }
+
+ componentWillUnmount() {
+ this.autorunDisposer!();
+ clearTimeout(this.forceRepaintTimeout!);
+ // clearTimeout(this.hibernationTimer); // TODO - [TS DEBT] class property not reassigned, need to find its purpose
+ }
+
+ render() {
+ const {
+ detachService,
+ service,
+ setWebviewRef,
+ reload,
+ edit,
+ enable,
+ stores,
+ isSpellcheckerEnabled,
+ } = this.props;
+
+ const { navigationBarBehaviour, navigationBarManualActive } =
+ stores!.settings.app;
+
+ const showNavBar =
+ navigationBarBehaviour === 'always' ||
+ (navigationBarBehaviour === 'custom' &&
+ service.recipe.id === CUSTOM_WEBSITE_RECIPE_ID) ||
+ navigationBarManualActive;
+
+ const webviewClasses = classnames({
+ services__webview: true,
+ 'services__webview-wrapper': true,
+ 'is-active': service.isActive,
+ 'services__webview--force-repaint': this.state.forceRepaint,
+ });
+
+ const statusBar = this.state.statusBarVisible ? (
+
+ ) : null;
+
+ return (
+
+ {service.isActive && service.isEnabled && (
+ <>
+ {service.hasCrashed && (
+
+ )}
+ {service.isEnabled &&
+ service.isLoading &&
+ service.isFirstLoad &&
+ !service.isHibernating &&
+ !service.isServiceAccessRestricted && (
+
+ )}
+ {service.isProgressbarEnabled &&
+ service.isLoadingPage &&
+ !service.isFirstLoad &&
}
+ {service.isError && (
+
+ )}
+ >
+ )}
+ {!service.isEnabled ? (
+ <>
+ {service.isActive && (
+
+ )}
+ >
+ ) : (
+ <>
+ {!service.isHibernating ? (
+ <>
+ {showNavBar &&
}
+
+ >
+ ) : (
+
+
+ 😴
+
+
+
+ This service is currently hibernating.
+
+ Try switching services or reloading Ferdium.
+
+ )}
+ >
+ )}
+ {statusBar}
+
+ );
+ }
+}
+
+export default ServiceView;
diff --git a/src/components/services/content/Services.tsx b/src/components/services/content/Services.tsx
index 53cddd907..fa26edaa6 100644
--- a/src/components/services/content/Services.tsx
+++ b/src/components/services/content/Services.tsx
@@ -42,8 +42,8 @@ interface IProps extends WrappedComponentProps, WithStylesProps {
services?: Service[];
setWebviewReference: () => void;
detachService: () => void;
- handleIPCMessage: () => void;
- openWindow: () => void;
+ // handleIPCMessage: () => void; // TODO - [TECH DEBT] later check it
+ // openWindow: () => void; // TODO - [TECH DEBT] later check it
reload: (options: { serviceId: string }) => void;
openSettings: (options: { path: string }) => void;
update: (options: {
@@ -61,7 +61,7 @@ interface IState {
@observer
class Services extends Component {
- _confettiTimeout: number | null = null;
+ confettiTimeout: number | null = null;
constructor(props: IProps) {
super(props);
@@ -72,7 +72,7 @@ class Services extends Component {
}
componentDidMount(): void {
- this._confettiTimeout = window.setTimeout(() => {
+ this.confettiTimeout = window.setTimeout(() => {
this.setState({
showConfetti: false,
});
@@ -80,18 +80,18 @@ class Services extends Component {
}
componentWillUnmount(): void {
- if (this._confettiTimeout) {
- clearTimeout(this._confettiTimeout);
+ if (this.confettiTimeout) {
+ clearTimeout(this.confettiTimeout);
}
}
render(): ReactElement {
const {
services = [],
- handleIPCMessage,
+ // handleIPCMessage, // TODO - [TECH DEBT] later check it
setWebviewReference,
detachService,
- openWindow,
+ // openWindow, // TODO - [TECH DEBT] later check it
reload,
openSettings,
update,
@@ -136,10 +136,10 @@ class Services extends Component {
reload({ serviceId: service.id })}
edit={() => openSettings({ path: `services/edit/${service.id}` })}
enable={() =>
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
deleted file mode 100644
index 0e6e61be8..000000000
--- a/src/components/services/content/WebviewCrashHandler.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import { Component } from 'react';
-import PropTypes from 'prop-types';
-import { observer } from 'mobx-react';
-import { defineMessages, injectIntl } from 'react-intl';
-import ms from 'ms';
-
-import Button from '../../ui/button';
-import { H1 } from '../../ui/headline';
-
-const messages = defineMessages({
- headline: {
- id: 'service.crashHandler.headline',
- defaultMessage: 'Oh no!',
- },
- text: {
- id: 'service.crashHandler.text',
- defaultMessage: '{name} has caused an error.',
- },
- action: {
- id: 'service.crashHandler.action',
- defaultMessage: 'Reload {name}',
- },
- autoReload: {
- id: 'service.crashHandler.autoReload',
- defaultMessage:
- 'Trying to automatically restore {name} in {seconds} seconds',
- },
-});
-
-class WebviewCrashHandler extends Component {
- static propTypes = {
- name: PropTypes.string.isRequired,
- reload: PropTypes.func.isRequired,
- };
-
- state = {
- countdown: ms('10s'),
- };
-
- countdownInterval = null;
-
- countdownIntervalTimeout = ms('1s');
-
- componentDidMount() {
- const { reload } = this.props;
-
- this.countdownInterval = setInterval(() => {
- this.setState(prevState => ({
- countdown: prevState.countdown - this.countdownIntervalTimeout,
- }));
-
- if (this.state.countdown <= 0) {
- reload();
- clearInterval(this.countdownInterval);
- }
- }, this.countdownIntervalTimeout);
- }
-
- render() {
- const { name, reload } = this.props;
- const { intl } = this.props;
-
- return (
-
-
{intl.formatMessage(messages.headline)}
-
{intl.formatMessage(messages.text, { name })}
-
reload()}
- />
-
- {intl.formatMessage(messages.autoReload, {
- name,
- seconds: this.state.countdown / ms('1s'),
- })}
-
-
- );
- }
-}
-
-export default injectIntl(observer(WebviewCrashHandler));
diff --git a/src/components/services/content/WebviewCrashHandler.tsx b/src/components/services/content/WebviewCrashHandler.tsx
new file mode 100644
index 000000000..e9b17e8aa
--- /dev/null
+++ b/src/components/services/content/WebviewCrashHandler.tsx
@@ -0,0 +1,90 @@
+import { Component, ReactElement } from 'react';
+import { observer } from 'mobx-react';
+import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
+import ms from 'ms';
+import Button from '../../ui/button';
+import { H1 } from '../../ui/headline';
+
+const messages = defineMessages({
+ headline: {
+ id: 'service.crashHandler.headline',
+ defaultMessage: 'Oh no!',
+ },
+ text: {
+ id: 'service.crashHandler.text',
+ defaultMessage: '{name} has caused an error.',
+ },
+ action: {
+ id: 'service.crashHandler.action',
+ defaultMessage: 'Reload {name}',
+ },
+ autoReload: {
+ id: 'service.crashHandler.autoReload',
+ defaultMessage:
+ 'Trying to automatically restore {name} in {seconds} seconds',
+ },
+});
+
+interface IProps extends WrappedComponentProps {
+ name: string;
+ reload: () => void;
+}
+
+interface IState {
+ countdown: number;
+}
+
+@observer
+class WebviewCrashHandler extends Component {
+ countdownInterval: NodeJS.Timer | undefined;
+
+ countdownIntervalTimeout = ms('1s');
+
+ constructor(props: IProps) {
+ super(props);
+
+ this.state = {
+ countdown: ms('10s'),
+ };
+ }
+
+ componentDidMount(): void {
+ const { reload } = this.props;
+
+ this.countdownInterval = setInterval(() => {
+ this.setState(prevState => ({
+ countdown: prevState.countdown - this.countdownIntervalTimeout,
+ }));
+
+ if (this.state.countdown <= 0) {
+ reload();
+ clearInterval(this.countdownInterval!);
+ }
+ }, this.countdownIntervalTimeout);
+ }
+
+ render(): ReactElement {
+ const { name, reload, intl } = this.props;
+
+ return (
+
+
{intl.formatMessage(messages.headline)}
+
{intl.formatMessage(messages.text, { name })}
+
reload()}
+ />
+
+ {intl.formatMessage(messages.autoReload, {
+ name,
+ seconds: this.state.countdown / ms('1s'),
+ })}
+
+
+ );
+ }
+}
+
+export default injectIntl(WebviewCrashHandler);
diff --git a/src/components/services/content/WebviewErrorHandler.tsx b/src/components/services/content/WebviewErrorHandler.tsx
new file mode 100644
index 000000000..b99c15006
--- /dev/null
+++ b/src/components/services/content/WebviewErrorHandler.tsx
@@ -0,0 +1,96 @@
+import { Component, ReactElement } from 'react';
+import { observer } from 'mobx-react';
+import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
+import withStyles, { WithStylesProps } from 'react-jss';
+import Button from '../../ui/button';
+import { H1 } from '../../ui/headline';
+
+const messages = defineMessages({
+ headline: {
+ id: 'service.errorHandler.headline',
+ defaultMessage: 'Oh no!',
+ },
+ text: {
+ id: 'service.errorHandler.text',
+ defaultMessage: '{name} has failed to load.',
+ },
+ action: {
+ id: 'service.errorHandler.action',
+ defaultMessage: 'Reload {name}',
+ },
+ editAction: {
+ id: 'service.errorHandler.editAction',
+ defaultMessage: 'Edit {name}',
+ },
+ errorMessage: {
+ id: 'service.errorHandler.message',
+ defaultMessage: 'Error',
+ },
+});
+
+const styles = theme => ({
+ component: {
+ left: 0,
+ position: 'absolute',
+ top: 0,
+ width: '100%',
+ zIndex: 0,
+ alignItems: 'center',
+ background: theme.colorWebviewErrorHandlerBackground,
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ textAlign: 'center',
+ },
+ buttonContainer: {
+ display: 'flex',
+ flexDirection: 'row',
+ height: 'auto',
+ margin: [40, 0, 20],
+
+ '& button': {
+ margin: [0, 10, 0, 10],
+ },
+ },
+});
+
+interface IProps extends WithStylesProps, WrappedComponentProps {
+ name: string;
+ reload: () => void;
+ edit: () => void;
+ errorMessage: string;
+}
+
+@observer
+class WebviewErrorHandler extends Component {
+ render(): ReactElement {
+ const { name, reload, edit, errorMessage, classes, intl } = this.props;
+
+ return (
+
+
{intl.formatMessage(messages.headline)}
+
{intl.formatMessage(messages.text, { name })}
+
+ {intl.formatMessage(messages.errorMessage)}:{' '}
+ {errorMessage}
+
+
+ edit()}
+ />
+ reload()}
+ />
+
+
+ );
+ }
+}
+
+export default injectIntl(
+ withStyles(styles, { injectTheme: true })(WebviewErrorHandler),
+);
--
cgit v1.2.3-70-g09d2