From b22d262bfb8130d6d72f9f5aeba9f2b18d9cfbff Mon Sep 17 00:00:00 2001 From: Paul Murray Date: Wed, 25 Oct 2023 13:53:09 -0400 Subject: [PATCH] no more useDispatch, or "controller" --- flatfront-astro/src/lib/columns.ts | 26 ++++++-- .../src/lib/components/CatalogCell.tsx | 34 +++++----- flatfront-astro/src/lib/components/Cells.tsx | 13 ++-- .../src/lib/components/FilterControls.tsx | 11 +++- .../src/lib/components/GlobalControls.tsx | 21 +++--- flatfront-astro/src/lib/components/Plot.tsx | 43 ++++++++---- .../src/lib/contexts/AppStateContext.tsx | 55 ++++++++-------- .../src/lib/contexts/CatalogContext.tsx | 11 +--- .../src/lib/contexts/FiltersContext.tsx | 65 ++++++++++++------- .../src/lib/contexts/RandomContext.tsx | 16 +++-- flatfront-astro/src/lib/dark-mode.ts | 4 +- flatfront-astro/src/lib/plot-hooks.ts | 13 ++-- flatfront-astro/src/lib/types.ts | 2 +- 13 files changed, 191 insertions(+), 123 deletions(-) diff --git a/flatfront-astro/src/lib/columns.ts b/flatfront-astro/src/lib/columns.ts index ae0e4d3..4af5df0 100644 --- a/flatfront-astro/src/lib/columns.ts +++ b/flatfront-astro/src/lib/columns.ts @@ -1,4 +1,4 @@ -import { useAppState, useDispatch } from "./contexts/AppStateContext"; +import { useAppState, useMergeState } from "./contexts/AppStateContext"; import { useCatalogCellID, useCatalogID } from "./contexts/CatalogContext"; import { useCatalogMetadata } from "./contexts/CatalogMetadataContext"; import type { CatalogHierarchyNode, FieldID, FieldMetadata } from "./types"; @@ -39,19 +39,35 @@ function get_column_ids( export function useAddColumn() { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const dispatch = useDispatch(); + const merge_state = useMergeState(); return (node: CatalogHierarchyNode) => { const field_id = node.data.name; - dispatch([`show_columns`, catalog_cell_id, catalog_id, field_id], true); + merge_state({ + show_columns: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: true + } + } + } + }); }; } export function useRemoveColumn() { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const dispatch = useDispatch(); + const merge_state = useMergeState(); return (node: CatalogHierarchyNode) => { const field_id = node.data.name; - dispatch([`show_columns`, catalog_cell_id, catalog_id, field_id], false); + merge_state({ + show_columns: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: false + } + } + } + }); }; } diff --git a/flatfront-astro/src/lib/components/CatalogCell.tsx b/flatfront-astro/src/lib/components/CatalogCell.tsx index 44ca790..59243f0 100644 --- a/flatfront-astro/src/lib/components/CatalogCell.tsx +++ b/flatfront-astro/src/lib/components/CatalogCell.tsx @@ -1,8 +1,6 @@ import type { CatalogHierarchyNode, CellID, - CountRequestBody, - CountResponse, PlotID, TopResponse, TopResponseEntry @@ -11,14 +9,7 @@ import type { import React from "react"; import * as d3 from "d3"; import { useQuery } from "@tanstack/react-query"; -import * as controller from "../contexts/AppStateContext"; -import { - fetch_api_get, - fetch_api_post, - format, - get_field_titles, - log -} from "../shared"; +import { fetch_api_get, format, get_field_titles } from "../shared"; import { useAddPlot, usePlotIDs } from "../plot-hooks"; import { useFilters } from "../contexts/FiltersContext"; import { useCatalogMetadata } from "../contexts/CatalogMetadataContext"; @@ -47,6 +38,7 @@ import FieldCard from "./FieldCard"; import BrowseFieldsDialog from "./BrowseFieldsDialog"; import Katex from "./Katex"; import { useSetRandomConfig } from "../contexts/RandomContext"; +import { useMergeState } from "../contexts/AppStateContext"; export default function CatalogCell({ id: catalog_cell_id @@ -109,7 +101,7 @@ function CatalogSelect() { const catalog_list = d3.sort(catalog_list_unsorted, get_title); const ready = catalog_list.length > 0; const selected = catalog_list.find((d) => d.name === catalog_id); - const dispatch = controller.useDispatch(); + const merge_state = useMergeState(); return (
{ const plot_type = d?.key; - dispatch([`set_plot_type`, plot_id], plot_type); + merge_state({ + set_plot_type: { + [plot_id]: plot_type + } + }); }} size="small" /> @@ -201,11 +205,11 @@ function PlotControl({ return type === `INTEGER` || type === `FLOAT`; }); - const plot_config = controller.useAppState().set_plot_control?.[plot_id]; + const plot_config = useAppState().set_plot_control?.[plot_id]; const field_id = plot_config?.[plot_control_key]; - const dispatch = controller.useDispatch(); + const merge_state = useMergeState(); const value = numeric_nodes.find((d) => d.data.name === field_id); @@ -222,7 +226,13 @@ function PlotControl({ { - dispatch([`set_plot_control`, plot_id, log_mode_key], checked); + merge_state({ + set_plot_control: { + [plot_id]: { + [log_mode_key]: checked + } + } + }); }} />
@@ -240,7 +250,13 @@ function PlotControl({ getDisplayName={(d) => d.data.name} onValueChange={(d) => { const value = d?.data.name; - dispatch([`set_plot_control`, plot_id, plot_control_key], value); + merge_state({ + set_plot_control: { + [plot_id]: { + [plot_control_key]: value + } + } + }); }} triggerClassName="overflow-hidden text-ellipsis" valueClassName="overflow-hidden text-ellipsis" @@ -255,7 +271,7 @@ function Histogram() { const filters = useFilters(); const plot_id = usePlotID(); - const plot_state = controller.useAppState()?.set_plot_control?.[plot_id]; + const plot_state = useAppState()?.set_plot_control?.[plot_id]; const x_axis_field_id = plot_state?.x_axis; const x_axis_log_mode = plot_state?.x_axis_log_mode ?? false; @@ -332,7 +348,7 @@ function Heatmap() { const filters = useFilters(); const plot_id = usePlotID(); - const plot_state = controller.useAppState()?.set_plot_control?.[plot_id]; + const plot_state = useAppState()?.set_plot_control?.[plot_id]; const x_axis_field_id = plot_state?.x_axis; const y_axis_field_id = plot_state?.y_axis; @@ -420,7 +436,7 @@ function Scatterplot() { const filters = useFilters(); const plot_id = usePlotID(); - const plot_state = controller.useAppState()?.set_plot_control?.[plot_id]; + const plot_state = useAppState()?.set_plot_control?.[plot_id]; const x_axis_field_id = plot_state?.x_axis; const y_axis_field_id = plot_state?.y_axis; @@ -436,8 +452,9 @@ function Scatterplot() { fields: [x_axis_field_id, y_axis_field_id], ...filters, count, - sort: sort ? [sort] : undefined - // sample: 0.42, + sort: sort ? [sort] : undefined, + // TODO: Make this optional + sample: 0.42 // seed: 12345 // ...query_parameters }; diff --git a/flatfront-astro/src/lib/contexts/AppStateContext.tsx b/flatfront-astro/src/lib/contexts/AppStateContext.tsx index 99225eb..04354aa 100644 --- a/flatfront-astro/src/lib/contexts/AppStateContext.tsx +++ b/flatfront-astro/src/lib/contexts/AppStateContext.tsx @@ -3,6 +3,8 @@ import React from "react"; import { useDebounce } from "@uidotdev/usehooks"; import * as lzstring from "lz-string"; import lodash_set from "lodash.set"; +import lodash_merge from "lodash.merge"; +import { setAutoFreeze } from "immer"; import { useImmer, type Updater } from "use-immer"; import { log } from "../shared"; @@ -11,8 +13,31 @@ const DispatchContext = React.createContext | undefined>( undefined ); +// function autobuild(obj: T) { +// return new Proxy(obj, { +// get(target, property, receiver) { +// const is_symbol = typeof property === `symbol`; +// const is_to_json = property === `toJSON`; +// const misssing_property = !(property in target); +// const is_extensible = Object.isExtensible(target); +// const should_create_object = +// !is_symbol && !is_to_json && misssing_property && is_extensible; +// if (should_create_object) { +// target[property] = autobuild({}); +// } +// return Reflect.get(target, property, receiver); +// } +// }); +// } + export function Provider({ children }) { - const [app_state, set_app_state] = useImmer({}); + const [app_state, set_app_state] = useImmer(() => { + const app_state_from_url = get_data_from_url(`app_state`); + const initial_app_state: AppState = app_state_from_url ?? {}; + return initial_app_state; + // return autobuild(initial_app_state); + }); + log(`AppState:`, app_state); return ( @@ -38,39 +63,13 @@ export function useSetAppState() { return set_app_state; } -export function useDispatch() { - const set_app_state = useSetAppState(); - const dispatch = (keys: Array, value: any) => { - set_app_state((obj) => lodash_set(obj, keys, value)); - }; - return dispatch; -} - -function merge(obj: T, to_merge: T) { - for (const key in to_merge) { - if (typeof obj[key] === `object`) { - merge(obj[key], to_merge[key]); - } else { - obj[key] = to_merge[key]; - } - } -} - export function useMergeState() { const set_app_state = useSetAppState(); - return (next: AppState) => set_app_state((prev) => merge(prev, next)); + return (next: AppState) => set_app_state((prev) => lodash_merge(prev, next)); } export function useSaveAndRestoreState() { const app_state = useAppState(); - const set_app_state = useSetAppState(); - React.useEffect(() => { - const app_state = get_data_from_url(`app_state`); - if (app_state) { - log(`Setting app state from URL:`, app_state); - set_app_state(app_state); - } - }, []); const debounced = useDebounce(app_state, 1000); React.useEffect(() => { if (Object.keys(debounced).length === 0) return; diff --git a/flatfront-astro/src/lib/contexts/CatalogContext.tsx b/flatfront-astro/src/lib/contexts/CatalogContext.tsx index 07bd2a1..3f1858a 100644 --- a/flatfront-astro/src/lib/contexts/CatalogContext.tsx +++ b/flatfront-astro/src/lib/contexts/CatalogContext.tsx @@ -1,17 +1,12 @@ -import type { - CatalogMetadataWrapper, - CellID, - CountRequestBody, - CountResponse -} from "../types"; +import type { CellID, CountRequestBody, CountResponse } from "../types"; import React from "react"; import { useQuery } from "@tanstack/react-query"; -import * as controller from "./AppStateContext"; import { assert_catalog_cell_id, fetch_api_post } from "../shared"; import { FiltersProvider, useFilters } from "./FiltersContext"; import { CatalogMetadataProvider } from "./CatalogMetadataContext"; import { RandomProvider } from "./RandomContext"; +import { useAppState } from "./AppStateContext"; const CatalogCellIDContext = React.createContext( undefined @@ -76,7 +71,7 @@ export function useCatalogCellID() { export function useCatalogID(): string { const catalog_cell_id = useCatalogCellID(); - const catalog_id = controller.useAppState()?.set_catalog?.[catalog_cell_id]; + const catalog_id = useAppState()?.set_catalog?.[catalog_cell_id]; return catalog_id; } diff --git a/flatfront-astro/src/lib/contexts/FiltersContext.tsx b/flatfront-astro/src/lib/contexts/FiltersContext.tsx index 6403ac9..7623a17 100644 --- a/flatfront-astro/src/lib/contexts/FiltersContext.tsx +++ b/flatfront-astro/src/lib/contexts/FiltersContext.tsx @@ -8,7 +8,6 @@ import type { import React from "react"; import lodash_merge from "lodash.merge"; -import * as controller from "./AppStateContext"; import { assert_numeric_field_stats, get_field_type, @@ -17,6 +16,7 @@ import { import { useCatalogCellID, useCatalogID } from "./CatalogContext"; import { useCatalogMetadata } from "./CatalogMetadataContext"; import { useFieldNode } from "./FieldNodeContext"; +import { useAppState, useMergeState, useSetAppState } from "./AppStateContext"; const FiltersContext = React.createContext(null); @@ -25,7 +25,7 @@ export function FiltersProvider({ children }) { const catalog_id = useCatalogID(); const catalog_metadata = useCatalogMetadata(); const catalog_hierarchy = catalog_metadata?.hierarchy; - const app_state = controller.useAppState(); + const app_state = useAppState(); const show_filters_config: Record = app_state?.add_filter?.[catalog_cell_id]?.[catalog_id] ?? {}; const filter_names_set = catalog_hierarchy @@ -36,7 +36,7 @@ export function FiltersProvider({ children }) { catalog_hierarchy ); const filter_state: Filters = - controller.useAppState()?.set_filter_value?.[catalog_cell_id]?.[catalog_id]; + app_state?.set_filter_value?.[catalog_cell_id]?.[catalog_id]; const filters = lodash_merge(initial_filters, filter_state); return ( @@ -131,33 +131,43 @@ export function useSetFilterValue( const field_id = field_node.data.name; const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const action_key_base = [ - `set_filter_value`, - catalog_cell_id, - catalog_id, - field_id - ]; - const dispatch = controller.useDispatch(); - return (action_key: string[], value: FilterValueRaw) => { - dispatch([...action_key_base, ...action_key], value); + const merge_state = useMergeState(); + return (value: FilterValueRaw) => { + merge_state({ + set_filter_value: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: value + } + } + } + }); }; } export function useRemoveFilter() { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const set_app_state = controller.useSetAppState(); + const set_app_state = useSetAppState(); return (node: CatalogHierarchyNode) => { const field_id = node.data.name; set_app_state((obj) => { - obj.add_filter ??= {}; - obj.add_filter[catalog_cell_id] ??= {}; - obj.add_filter[catalog_cell_id][catalog_id] ??= {}; - obj.add_filter[catalog_cell_id][catalog_id][field_id] = false; - - obj.set_filter_value ??= {}; - obj.set_filter_value[catalog_cell_id] ??= {}; - obj.set_filter_value[catalog_cell_id][catalog_id] ??= {}; + lodash_merge(obj, { + add_filter: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: false + } + } + }, + set_filter_value: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: null + } + } + } + }); delete obj.set_filter_value[catalog_cell_id][catalog_id][field_id]; }); }; @@ -166,9 +176,18 @@ export function useRemoveFilter() { export function useAddFilter() { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const dispatch = controller.useDispatch(); + const merge_state = useMergeState(); + return (node: CatalogHierarchyNode) => { const field_id = node.data.name; - dispatch([`add_filter`, catalog_cell_id, catalog_id, field_id], true); + merge_state({ + add_filter: { + [catalog_cell_id]: { + [catalog_id]: { + [field_id]: true + } + } + } + }); }; } diff --git a/flatfront-astro/src/lib/contexts/RandomContext.tsx b/flatfront-astro/src/lib/contexts/RandomContext.tsx index f145485..638539f 100644 --- a/flatfront-astro/src/lib/contexts/RandomContext.tsx +++ b/flatfront-astro/src/lib/contexts/RandomContext.tsx @@ -1,6 +1,6 @@ import React from "react"; -import * as controller from "./AppStateContext"; import { useCatalogCellID, useCatalogID } from "./CatalogContext"; +import { useAppState, useMergeState } from "./AppStateContext"; const RandomContext = React.createContext< | { @@ -13,7 +13,7 @@ const RandomContext = React.createContext< export function RandomProvider({ children }) { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const app_state = controller.useAppState(); + const app_state = useAppState(); const random_config = app_state?.set_random_sample?.[catalog_cell_id]?.[catalog_id]; @@ -32,9 +32,17 @@ export function useRandomConfig() { export function useSetRandomConfig() { const catalog_cell_id = useCatalogCellID(); const catalog_id = useCatalogID(); - const dispatch = controller.useDispatch(); + const merge_state = useMergeState(); return (key: `sample` | `seed`, value: number) => { - dispatch([`set_random_sample`, catalog_cell_id, catalog_id, key], value); + merge_state({ + set_random_sample: { + [catalog_cell_id]: { + [catalog_id]: { + [key]: value + } + } + } + }); // dispatch({ // set_random_sample: { // [catalog_cell_id]: { diff --git a/flatfront-astro/src/lib/dark-mode.ts b/flatfront-astro/src/lib/dark-mode.ts index 337eee7..10efa22 100644 --- a/flatfront-astro/src/lib/dark-mode.ts +++ b/flatfront-astro/src/lib/dark-mode.ts @@ -1,11 +1,11 @@ import type { DarkModeValue } from "./types"; import React from "react"; -import * as controller from "./contexts/AppStateContext"; import { log } from "./shared"; +import { useAppState } from "./contexts/AppStateContext"; export function useDarkModeValue(): DarkModeValue { - const dark_mode_value = controller.useAppState()?.dark_mode; + const dark_mode_value = useAppState()?.dark_mode; return dark_mode_value ?? `system`; } diff --git a/flatfront-astro/src/lib/plot-hooks.ts b/flatfront-astro/src/lib/plot-hooks.ts index 99627b1..2886fca 100644 --- a/flatfront-astro/src/lib/plot-hooks.ts +++ b/flatfront-astro/src/lib/plot-hooks.ts @@ -1,10 +1,6 @@ import type { PlotID } from "./types"; import * as d3 from "d3"; -import { - useAppState, - useDispatch, - useMergeState -} from "./contexts/AppStateContext"; +import { useAppState, useMergeState } from "./contexts/AppStateContext"; import { useCatalogCellID } from "./contexts/CatalogContext"; import { assert_plot_id } from "./shared"; @@ -25,10 +21,9 @@ export function useAddPlot() { export function useRemovePlot(id: PlotID) { const catalog_cell_id = useCatalogCellID(); - const dispatch = useDispatch(); - return () => { - dispatch([`add_plot`, catalog_cell_id, id], false); - }; + const merge_state = useMergeState(); + return () => + merge_state({ add_plot: { [catalog_cell_id]: { [id]: false } } }); } export function usePlotIDs() { diff --git a/flatfront-astro/src/lib/types.ts b/flatfront-astro/src/lib/types.ts index 1cb92b2..02c12c5 100644 --- a/flatfront-astro/src/lib/types.ts +++ b/flatfront-astro/src/lib/types.ts @@ -4,7 +4,7 @@ export type { schema }; export type AppState = { dark_mode?: DarkModeValue; - add_cell?: Cell.Any[]; + add_cell?: Record; add_filter?: Record< CellID.Catalog, Record>