mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-07-17 17:21:48 +00:00
Shift config to URL as source of truth
This commit is contained in:
@@ -97,7 +97,7 @@ We will gradually eliminate React state variables in `src/app.tsx` and derive th
|
||||
* [x] **Step 3.1d:** Shift `freezeAnimation` to URL as SSOT. Derive it directly from search parameters on render and remove its React state variable.
|
||||
* [x] **Step 3.2:** Extract `selection` and `detailIndi` state. Parse them directly from URL params (`indi`, `gen`, and `detail`); update display selectors. Remove React states. Ensure that chart selection changes (`onSelection` callback) explicitly clear or update the `detail` query parameter to match the new selection to avoid getting stuck on the old details viewport. Also update the detail-only selection handler (`onDetailSelection`) to update the `detail` query parameter in the URL.
|
||||
* [x] **Step 3.3:** Extract `showSidePanel` state. Derive state directly from `?sidePanel=` parameter. Remove React state. Enhance URL args helpers to allow generating path/query target objects with replaced values, and ensure layout settings (`sidePanel`) and configuration changes use `replace: true` to prevent polluting the browser history stack.
|
||||
* [ ] **Step 3.4:** Extract `config` state. Parse display settings on render using `argsToConfig` helper. Remove state. In `ViewPage`, run `updateChartWithConfig(config, data)` synchronously during the render pass (e.g. in the `useMemo` that derives query parameters/config) to update the in-memory chart data before it is rendered by the `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred.
|
||||
* [x] **Step 3.4:** Extract `config` state. Parse display settings on render using `argsToConfig` helper. Remove state. In `ViewPage`, run `updateChartWithConfig(config, data)` synchronously during the render pass (e.g. in the `useMemo` that derives query parameters/config) to update the in-memory chart data before it is rendered by the `<Chart>` child component. Run E2E and visual tests to verify no rendering regressions occurred.
|
||||
|
||||
#### Phase 4: Structural Page Nesting
|
||||
* [ ] **Step 4.1:** Create `src/hooks/use_google_auth.ts` to manage Google Drive authentication token updates. Remove `hasGoogleToken` state from `src/app.tsx`.
|
||||
|
||||
21
src/app.tsx
21
src/app.tsx
@@ -47,13 +47,7 @@ import {useWebMcpBridge} from './hooks/use_webmcp_bridge';
|
||||
import {Intro} from './intro';
|
||||
import {GoogleAuthModal} from './menu/google_auth_modal';
|
||||
import {TopBar} from './menu/top_bar';
|
||||
import {
|
||||
Config,
|
||||
configToArgs,
|
||||
DEFALUT_CONFIG,
|
||||
Ids,
|
||||
Sex,
|
||||
} from './sidepanel/config/config';
|
||||
import {Config, configToArgs, Ids, Sex} from './sidepanel/config/config';
|
||||
import {SidePanel} from './sidepanel/side-panel';
|
||||
import {analyticsEvent} from './util/analytics';
|
||||
import {TopolaError} from './util/error';
|
||||
@@ -92,9 +86,6 @@ export function App() {
|
||||
/** Specification of the source of the data. */
|
||||
const [sourceSpec, setSourceSpec] = useState<DataSourceSpec>();
|
||||
|
||||
/** Configuration settings for chart display options (e.g. colors, hiding IDs). */
|
||||
const [config, setConfig] = useState(DEFALUT_CONFIG);
|
||||
|
||||
/** Controls the visibility of the Google Drive OAuth permission modal. */
|
||||
const [showAuthModal, setShowAuthModal] = useState(false);
|
||||
/** Stores the file ID that failed to load from Google Drive due to authorization errors. */
|
||||
@@ -122,6 +113,12 @@ export function App() {
|
||||
const freezeAnimation = args.freezeAnimation;
|
||||
/** Whether the side panel is shown. */
|
||||
const showSidePanel = args.showSidePanel;
|
||||
/** Configuration settings for chart display options (e.g. colors, hiding IDs). */
|
||||
const config = args.config;
|
||||
|
||||
useMemo(() => {
|
||||
updateChartWithConfig(config, data);
|
||||
}, [config, data]);
|
||||
/** The currently selected individual. Fallback to default individual from loaded data if not specified. */
|
||||
const updatedSelection = useMemo(() => {
|
||||
return data ? getSelection(data.chartData, args.selection) : undefined;
|
||||
@@ -345,7 +342,6 @@ export function App() {
|
||||
setState(AppState.LOADING);
|
||||
// Set state from URL parameters.
|
||||
setSourceSpec(args.sourceSpec);
|
||||
setConfig(args.config);
|
||||
const currentFetchId = ++fetchIdRef.current;
|
||||
setLoadingStatus('Loading…');
|
||||
try {
|
||||
@@ -369,7 +365,6 @@ export function App() {
|
||||
data.chartData,
|
||||
args.selection,
|
||||
);
|
||||
updateChartWithConfig(args.config, data);
|
||||
setState(AppState.SHOWING_CHART);
|
||||
} catch (error: unknown) {
|
||||
if (!isMountedRef.current || fetchIdRef.current !== currentFetchId) {
|
||||
@@ -587,8 +582,6 @@ export function App() {
|
||||
expanded={showSidePanel}
|
||||
onToggle={onToggleSidePanel}
|
||||
onConfigChange={(config) => {
|
||||
setConfig(config);
|
||||
updateChartWithConfig(config, data);
|
||||
updateUrl(configToArgs(config), {replace: true});
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user