mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
Refactor error components out of app.tsx
This commit is contained in:
@@ -80,7 +80,7 @@ To refactor `app.tsx` safely and maintain continuous code correctness, we will m
|
|||||||
### Step-by-Step Execution Plan
|
### Step-by-Step Execution Plan
|
||||||
|
|
||||||
#### Phase 1: Pure Component and Utility Extraction
|
#### Phase 1: Pure Component and Utility Extraction
|
||||||
* [ ] **Step 1.1:** Create `src/components/error_display.tsx` and move `ErrorMessage` and `ErrorPopup` from `src/app.tsx`. Update imports in `src/app.tsx`.
|
* [x] **Step 1.1:** Create `src/components/error_display.tsx` and move `ErrorMessage` and `ErrorPopup` from `src/app.tsx`. Update imports in `src/app.tsx`.
|
||||||
* [ ] **Step 1.2:** Create `src/datasource/instances.ts` and move data source class instantiations. Update references in `src/app.tsx`. Refactor `EmbeddedDataSource` to clean up its message event listener when the loading promise resolves or rejects (or track listener state) to prevent duplicate event listener leaks on multiple page mounts.
|
* [ ] **Step 1.2:** Create `src/datasource/instances.ts` and move data source class instantiations. Update references in `src/app.tsx`. Refactor `EmbeddedDataSource` to clean up its message event listener when the loading promise resolves or rejects (or track listener state) to prevent duplicate event listener leaks on multiple page mounts.
|
||||||
* [ ] **Step 1.3:** Create `src/util/url_args.ts` (the parsing utility) and `src/util/url_args.spec.ts` (its Jest unit test suite) together. Extract URL query parameter parsing functions and types from `src/app.tsx`, write comprehensive tests, update imports in `src/app.tsx`, and run `npm test` to verify.
|
* [ ] **Step 1.3:** Create `src/util/url_args.ts` (the parsing utility) and `src/util/url_args.spec.ts` (its Jest unit test suite) together. Extract URL query parameter parsing functions and types from `src/app.tsx`, write comprehensive tests, update imports in `src/app.tsx`, and run `npm test` to verify.
|
||||||
* [ ] **Step 1.4:** Modify `src/menu/top_bar.tsx` to make chart-specific props and event handlers optional (e.g. `data`, `allowAllRelativesChart`, `allowPrintAndDownload`, `eventHandlers`, etc.), preparing the component for rendering on the landing screen without dummy properties.
|
* [ ] **Step 1.4:** Modify `src/menu/top_bar.tsx` to make chart-specific props and event handlers optional (e.g. `data`, `allowAllRelativesChart`, `allowPrintAndDownload`, `eventHandlers`, etc.), preparing the component for rendering on the landing screen without dummy properties.
|
||||||
|
|||||||
48
src/app.tsx
48
src/app.tsx
@@ -1,15 +1,9 @@
|
|||||||
import * as H from 'history';
|
import * as H from 'history';
|
||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
||||||
import {FormattedMessage, useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import {Navigate, Route, Routes, useLocation, useNavigate} from 'react-router';
|
import {Navigate, Route, Routes, useLocation, useNavigate} from 'react-router';
|
||||||
import {
|
import {Loader, SidebarPushable, SidebarPusher} from 'semantic-ui-react';
|
||||||
Loader,
|
|
||||||
Message,
|
|
||||||
Portal,
|
|
||||||
SidebarPushable,
|
|
||||||
SidebarPusher,
|
|
||||||
} from 'semantic-ui-react';
|
|
||||||
import {IndiInfo} from 'topola';
|
import {IndiInfo} from 'topola';
|
||||||
import {
|
import {
|
||||||
Chart,
|
Chart,
|
||||||
@@ -19,6 +13,7 @@ import {
|
|||||||
downloadSvg,
|
downloadSvg,
|
||||||
printChart,
|
printChart,
|
||||||
} from './chart';
|
} from './chart';
|
||||||
|
import {ErrorMessage, ErrorPopup} from './components/error_display';
|
||||||
import {DataSourceEnum, SourceSelection} from './datasource/data_source';
|
import {DataSourceEnum, SourceSelection} from './datasource/data_source';
|
||||||
import {EmbeddedDataSource, EmbeddedSourceSpec} from './datasource/embedded';
|
import {EmbeddedDataSource, EmbeddedSourceSpec} from './datasource/embedded';
|
||||||
import {
|
import {
|
||||||
@@ -87,43 +82,6 @@ function getStaticUrl(): string | undefined {
|
|||||||
|
|
||||||
const staticUrl = getStaticUrl();
|
const staticUrl = getStaticUrl();
|
||||||
|
|
||||||
/** Shows an error message in the middle of the screen. */
|
|
||||||
function ErrorMessage(props: {message?: string}) {
|
|
||||||
return (
|
|
||||||
<Message negative className="error">
|
|
||||||
<Message.Header>
|
|
||||||
<FormattedMessage
|
|
||||||
id="error.failed_to_load_file"
|
|
||||||
defaultMessage={'Failed to load file'}
|
|
||||||
/>
|
|
||||||
</Message.Header>
|
|
||||||
<p>{props.message}</p>
|
|
||||||
</Message>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ErrorPopupProps {
|
|
||||||
message?: string;
|
|
||||||
open: boolean;
|
|
||||||
onDismiss: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a dismissable error message in the bottom left corner of the screen.
|
|
||||||
*/
|
|
||||||
function ErrorPopup(props: ErrorPopupProps) {
|
|
||||||
return (
|
|
||||||
<Portal open={props.open} onClose={props.onDismiss}>
|
|
||||||
<Message negative className="errorPopup" onDismiss={props.onDismiss}>
|
|
||||||
<Message.Header>
|
|
||||||
<FormattedMessage id="error.error" defaultMessage={'Error'} />
|
|
||||||
</Message.Header>
|
|
||||||
<p>{props.message}</p>
|
|
||||||
</Message>
|
|
||||||
</Portal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AppState {
|
enum AppState {
|
||||||
INITIAL,
|
INITIAL,
|
||||||
LOADING,
|
LOADING,
|
||||||
|
|||||||
39
src/components/error_display.tsx
Normal file
39
src/components/error_display.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
import {Message, Portal} from 'semantic-ui-react';
|
||||||
|
|
||||||
|
/** Shows an error message in the middle of the screen. */
|
||||||
|
export function ErrorMessage(props: {message?: string}) {
|
||||||
|
return (
|
||||||
|
<Message negative className="error">
|
||||||
|
<Message.Header>
|
||||||
|
<FormattedMessage
|
||||||
|
id="error.failed_to_load_file"
|
||||||
|
defaultMessage={'Failed to load file'}
|
||||||
|
/>
|
||||||
|
</Message.Header>
|
||||||
|
<p>{props.message}</p>
|
||||||
|
</Message>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorPopupProps {
|
||||||
|
message?: string;
|
||||||
|
open: boolean;
|
||||||
|
onDismiss: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a dismissable error message in the bottom left corner of the screen.
|
||||||
|
*/
|
||||||
|
export function ErrorPopup(props: ErrorPopupProps) {
|
||||||
|
return (
|
||||||
|
<Portal open={props.open} onClose={props.onDismiss}>
|
||||||
|
<Message negative className="errorPopup" onDismiss={props.onDismiss}>
|
||||||
|
<Message.Header>
|
||||||
|
<FormattedMessage id="error.error" defaultMessage={'Error'} />
|
||||||
|
</Message.Header>
|
||||||
|
<p>{props.message}</p>
|
||||||
|
</Message>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user