diff --git a/craco.config.cjs b/craco.config.cjs
new file mode 100644
index 00000000..5d983e49
--- /dev/null
+++ b/craco.config.cjs
@@ -0,0 +1,13 @@
+const path = require("path");
+
+// use some aliases to help reduce the ../../../ in our imports and make it more
+// obvious where stuff is coming from. Note that for intellisense to work these should
+// be mirrored in jsconfig.json
+
+module.exports = {
+ webpack: {
+ alias: {
+ "@": path.resolve(__dirname, "src"),
+ },
+ },
+};
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 00000000..22eddce5
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "target": "es6",
+ "baseUrl": "src",
+ "paths": {
+ "@/*": ["./*"]
+ }
+ }
+}
diff --git a/src/components/info/Disclaimer/Disclaimer.css b/src/components/info/Disclaimer/Disclaimer.css
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/components/info/Disclaimer/Disclaimer.js b/src/components/info/Disclaimer/Disclaimer.js
index 17ca4cc1..807e797c 100644
--- a/src/components/info/Disclaimer/Disclaimer.js
+++ b/src/components/info/Disclaimer/Disclaimer.js
@@ -1,11 +1,9 @@
import React, { useState } from "react";
import { Button, Modal } from "react-bootstrap";
-import "./Disclaimer.css";
-import { useStore } from "../../../state/state-store";
-import { useConfig } from "../../../state/query-hooks/use-config";
+import { useConfigContext } from "@/state/context-hooks/use-config-context";
function Disclaimer() {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const [acknowledged, setAcknowledged] = useState(!config.disclaimer.enabled);
const acknowledge = () => setAcknowledged(true);
diff --git a/src/components/info/NetworksMetadata/NetworksMetadata.js b/src/components/info/NetworksMetadata/NetworksMetadata.js
index 4838e2cb..1e22a962 100644
--- a/src/components/info/NetworksMetadata/NetworksMetadata.js
+++ b/src/components/info/NetworksMetadata/NetworksMetadata.js
@@ -11,16 +11,17 @@ import {
useReactTable,
flexRender,
} from "@tanstack/react-table";
-import logger from "../../../logger";
-import "./NetworksMetadata.css";
-import { useConfig } from "../../../state/query-hooks/use-config";
-import { useNetworks } from "../../../state/query-hooks/use-networks";
+import logger from "@/logger";
+import { useNetworks } from "@/state/query-hooks/use-networks";
+import useConfigContext from "@/state/context-hooks/use-config-context";
import { NetworkSpot } from "./NetworkSpot";
+import "./NetworksMetadata.css";
+
logger.configure({ active: true });
function NetworksMetadata() {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const { data: networks, isLoading, isError } = useNetworks();
const [sorting, setSorting] = React.useState([]);
diff --git a/src/components/info/ObservationCounts/ObservationCounts.js b/src/components/info/ObservationCounts/ObservationCounts.js
index c45b73c7..2a88ec5d 100644
--- a/src/components/info/ObservationCounts/ObservationCounts.js
+++ b/src/components/info/ObservationCounts/ObservationCounts.js
@@ -1,13 +1,14 @@
import PropTypes from "prop-types";
-import React, { useEffect, useState, useMemo } from "react";
+import React, { useMemo } from "react";
import { Table } from "react-bootstrap";
import { reduce } from "lodash/fp";
-import InfoPopup from "../../util/InfoPopup";
-import logger from "../../../logger";
-import { getTimer } from "../../../utils/timing";
+import InfoPopup from "@/components/util/InfoPopup";
+import logger from "@/logger";
+import { getTimer } from "@/utils/timing";
+import { useObservationCounts } from "@/state/query-hooks/use-observation-counts";
+import useConfigContext from "@/state/context-hooks/use-config-context";
+
import "./ObservationCounts.css";
-import { useConfig } from "../../../state/query-hooks/use-config";
-import { useObservationCounts } from "../../../state/query-hooks/use-observation-counts";
logger.configure({ active: true });
const timer = getTimer("Observation count timing");
@@ -31,7 +32,7 @@ function ObservationCounts({
clipToDate,
stations,
}) {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const {
data: countData,
isLoading,
diff --git a/src/components/info/StationData/StationData.js b/src/components/info/StationData/StationData.js
index 2cfc04f1..79d2aa96 100644
--- a/src/components/info/StationData/StationData.js
+++ b/src/components/info/StationData/StationData.js
@@ -3,16 +3,14 @@ import React, { useState } from "react";
import { Button, ButtonToolbar, Col, Row } from "react-bootstrap";
import capitalize from "lodash/fp/capitalize";
import map from "lodash/fp/map";
-import FileFormatSelector from "../../selectors/FileFormatSelector";
-import ClipToDateControl from "../../controls/ClipToDateControl";
-import ObservationCounts from "../../info/ObservationCounts";
-import InfoPopup from "../../util/InfoPopup";
-
-import logger from "../../../logger";
+import FileFormatSelector from "@/components/selectors/FileFormatSelector";
+import ClipToDateControl from "@/components/controls/ClipToDateControl";
+import ObservationCounts from "@/components/info/ObservationCounts";
+import InfoPopup from "@/components/util/InfoPopup";
+import logger from "@/logger";
+import useConfigContext from "@/state/context-hooks/use-config-context";
import "./StationData.css";
-import { useConfig } from "../../../state/query-hooks/use-config";
-
logger.configure({ active: true });
function StationData({
@@ -22,7 +20,7 @@ function StationData({
dataDownloadFilename,
rowClasses,
}) {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const [fileFormat, setFileFormat] = useState();
const [clipToDate, setClipToDate] = useState(false);
const toggleClipToDate = () => setClipToDate(!clipToDate);
diff --git a/src/components/main/App/App.js b/src/components/main/App/App.js
index 9e4400d8..b32ecf4e 100644
--- a/src/components/main/App/App.js
+++ b/src/components/main/App/App.js
@@ -1,13 +1,16 @@
import React from "react";
import { Container } from "react-bootstrap";
-import Disclaimer from "../../info/Disclaimer";
-import Header from "../Header/Header";
+import Disclaimer from "@/components/info/Disclaimer";
+import Header from "@/components/main/Header";
import { Outlet } from "react-router-dom";
+import { useConfigDefaults } from "@/state/client-server-hooks/use-config-defaults";
import "./App.css";
-import { useConfigDefaults } from "../../../state/client-server-hooks/use-config-defaults";
+
+import { ConfigContext } from "@/state/context-hooks/use-config-context";
+
export const App = () => {
- const { isLoading, isError } = useConfigDefaults();
+ const { data: config, isLoading, isError } = useConfigDefaults();
if (isError) {
return
An Error occoured while loading the app configuration.
;
@@ -18,11 +21,13 @@ export const App = () => {
}
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/src/components/main/Body/Body.js b/src/components/main/Body/Body.js
index 03d5d160..5601839d 100644
--- a/src/components/main/Body/Body.js
+++ b/src/components/main/Body/Body.js
@@ -2,33 +2,27 @@ import React, { useEffect, useMemo, useState } from "react";
import { Col, Row, Tab, Tabs } from "react-bootstrap";
import Select from "react-select";
-import logger from "../../../logger";
-import {
- dataDownloadFilename,
- dataDownloadUrl,
-} from "../../../api/pdp-data-service";
-import {
- stationAreaFilter,
- stationFilter,
-} from "../../../utils/station-filtering";
-import StationMap from "../../maps/StationMap";
-import StationMetadata from "../../info/StationMetadata";
-import StationData from "../../info/StationData";
-import NetworksMetadata from "../../info/NetworksMetadata";
-import SelectionCounts from "../../info/SelectionCounts";
-import SelectionCriteria from "../../info/SelectionCriteria";
-import UnselectedThings from "../../info/UnselectedThings";
-import AdjustableColumns from "../../util/AdjustableColumns";
+import logger from "@/logger";
+import { dataDownloadFilename, dataDownloadUrl } from "@/api/pdp-data-service";
+import { stationAreaFilter, stationFilter } from "@/utils/station-filtering";
+import StationMap from "@/components/maps/StationMap";
+import StationMetadata from "@/components/info/StationMetadata";
+import StationData from "@/components/info/StationData";
+import NetworksMetadata from "@/components/info/NetworksMetadata";
+import SelectionCounts from "@/components/info/SelectionCounts";
+import SelectionCriteria from "@/components/info/SelectionCriteria";
+import UnselectedThings from "@/components/info/UnselectedThings";
+import AdjustableColumns from "@/components/util/AdjustableColumns";
import StationFilters, {
useStationFiltering,
-} from "../../controls/StationFilters";
-import baseMaps from "../../maps/baseMaps";
-import { useStore } from "../../../state/state-store";
+} from "@/components/controls/StationFilters";
+import baseMaps from "@/components/maps/baseMaps";
+import { useStore } from "@/state/client/state-store";
import { useShallow } from "zustand/react/shallow";
-import { useConfig } from "../../../state/query-hooks/use-config";
-import { useStations } from "../../../state/query-hooks/use-stations";
-import { useVariables } from "../../../state/query-hooks/use-variables";
-import { useNetworks } from "../../../state/query-hooks/use-networks";
+import { useStations } from "@/state/query-hooks/use-stations";
+import { useVariables } from "@/state/query-hooks/use-variables";
+import { useNetworks } from "@/state/query-hooks/use-networks";
+import useConfigContext from "@/state/context-hooks/use-config-context";
import { NoRenderContent } from "./NoRenderContent";
import css from "../common.module.css";
@@ -36,7 +30,7 @@ import css from "../common.module.css";
logger.configure({ active: true });
function Body() {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const {
data: stations,
isLoading: isStationsLoading,
@@ -47,11 +41,6 @@ function Body() {
isLoading: isVariablesLoading,
isError: isVariablesError,
} = useVariables();
- const {
- data: networks,
- isLoading: networksLoading,
- isError: networksError,
- } = useNetworks();
const actions = useStore(
useShallow((state) => ({
diff --git a/src/components/main/Header/Header.js b/src/components/main/Header/Header.js
index 23199461..d8a78b71 100644
--- a/src/components/main/Header/Header.js
+++ b/src/components/main/Header/Header.js
@@ -1,10 +1,11 @@
import React from "react";
import { Row, Col } from "react-bootstrap";
+import { useConfigContext } from "@/state/context-hooks/use-config-context";
+
import "./Header.css";
-import { useConfig } from "../../../state/query-hooks/use-config";
function Header() {
- const { data: config } = useConfig();
+ const config = useConfigContext();
return (
diff --git a/src/components/maps/StationMap/StationMap.js b/src/components/maps/StationMap/StationMap.js
index f2bf5178..7de2ce77 100644
--- a/src/components/maps/StationMap/StationMap.js
+++ b/src/components/maps/StationMap/StationMap.js
@@ -46,15 +46,14 @@ import MapInfoDisplay from "../MapInfoDisplay";
import { defaultMarkerOptions, ManyStationMarkers } from "../StationMarkers";
import { layersToGeoJSONMultipolygon } from "../../../utils/geoJSON-leaflet";
-import logger from "../../../logger";
+import logger from "@/logger";
import "./StationMap.css";
-import { getTimer } from "../../../utils/timing";
+import { getTimer } from "@/utils/timing";
import { MapSpinner } from "pcic-react-leaflet-components";
import { useImmer } from "use-immer";
-import { useStore } from "../../../state/state-store";
import { StationRefresh } from "../StationRefresh/StationRefresh";
-import { useConfig } from "../../../state/query-hooks/use-config";
+import useConfigContext from "@/state/context-hooks/use-config-context";
logger.configure({ active: true });
const smtimer = getTimer("StationMarker timing");
@@ -76,7 +75,7 @@ function StationMap({
// should be true if and only if slow updates to the map are pending
// due to an external update.
}) {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const userShapeLayerRef = useRef();
const handleChangedGeometryLayers = () => {
diff --git a/src/components/maps/StationPopup/StationPopup.js b/src/components/maps/StationPopup/StationPopup.js
index 37902461..f5bb6429 100644
--- a/src/components/maps/StationPopup/StationPopup.js
+++ b/src/components/maps/StationPopup/StationPopup.js
@@ -8,11 +8,9 @@ import flow from "lodash/fp/flow";
import map from "lodash/fp/map";
import join from "lodash/fp/join";
import chroma from "chroma-js";
-import FrequencySelector from "../../selectors/FrequencySelector";
+import FrequencySelector from "@/components/selectors/FrequencySelector";
-import logger from "../../../logger";
-
-import "./StationPopup.css";
+import logger from "@/logger";
import {
stationNetwork,
uniqStationFreqs,
@@ -20,17 +18,19 @@ import {
uniqStationNames,
uniqStationObsPeriods,
uniqStationVariableNames,
-} from "../../../utils/station-info";
-import { useConfig } from "../../../state/query-hooks/use-config";
-import { useNetworks } from "../../../state/query-hooks/use-networks";
-import { useVariables } from "../../../state/query-hooks/use-variables";
+} from "@/utils/station-info";
+import { useNetworks } from "@/state/query-hooks/use-networks";
+import { useVariables } from "@/state/query-hooks/use-variables";
+
+import "./StationPopup.css";
+import useConfigContext from "@/state/context-hooks/use-config-context";
logger.configure({ active: true });
const formatDate = (d) => (d ? d.toISOString().substr(0, 10) : "unknown");
function StationPopup({ station }) {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const { data: networks } = useNetworks();
const { data: variables } = useVariables();
diff --git a/src/components/preview/StationPreview/EndDateControl.js b/src/components/preview/StationPreview/EndDateControl.js
index 23af76c6..d7f584dd 100644
--- a/src/components/preview/StationPreview/EndDateControl.js
+++ b/src/components/preview/StationPreview/EndDateControl.js
@@ -1,6 +1,6 @@
import { useState } from "react";
import DatePicker from "react-datepicker";
-import { useStore } from "../../../state/state-store";
+import { useStore } from "@/state/client/state-store";
import css from "./EndDateControl.module.css";
export const EndDateControl = () => {
diff --git a/src/components/preview/StationPreview/GraphsBlock.js b/src/components/preview/StationPreview/GraphsBlock.js
index 849a3583..3767a620 100644
--- a/src/components/preview/StationPreview/GraphsBlock.js
+++ b/src/components/preview/StationPreview/GraphsBlock.js
@@ -2,9 +2,9 @@ import React from "react";
import { Card, Col, Row } from "react-bootstrap";
import map from "lodash/fp/map";
import PreviewGraph from "./PreviewGraph";
-import { useStore } from "../../../state/state-store";
-import { useStation } from "../../../state/query-hooks/use-station";
-import { useStationVariables } from "../../../state/query-hooks/use-station-variables";
+import { useStore } from "@/state/client/state-store";
+import { useStation } from "@/state/query-hooks/use-station";
+import { useStationVariables } from "@/state/query-hooks/use-station-variables";
const GraphsBlock = () => {
const stationId = useStore((state) => state.stationId);
diff --git a/src/components/preview/StationPreview/HeaderBlock.js b/src/components/preview/StationPreview/HeaderBlock.js
index 81ccf706..111c2e9f 100644
--- a/src/components/preview/StationPreview/HeaderBlock.js
+++ b/src/components/preview/StationPreview/HeaderBlock.js
@@ -2,8 +2,8 @@ import React from "react";
import { Link } from "react-router-dom";
import map from "lodash/fp/map";
import { Accordion, Table, Row, Col, Spinner } from "react-bootstrap";
-import { useStation } from "../../../state/query-hooks/use-station";
-import { useStore } from "../../../state/state-store";
+import { useStation } from "@/state/query-hooks/use-station";
+import { useStore } from "@/state/client/state-store";
export const HeaderBlock = () => {
const stationId = useStore((state) => state.stationId);
diff --git a/src/components/preview/StationPreview/NavBlock.js b/src/components/preview/StationPreview/NavBlock.js
index 9561284b..3121893c 100644
--- a/src/components/preview/StationPreview/NavBlock.js
+++ b/src/components/preview/StationPreview/NavBlock.js
@@ -13,8 +13,8 @@ import { LinkContainer } from "react-router-bootstrap";
import { useShallow } from "zustand/react/shallow";
import RangeBlock from "./RangeBlock";
import EndDateControl from "./EndDateControl";
-import { useStationVariables } from "../../../state/query-hooks/use-station-variables";
-import { useStore } from "../../../state/state-store";
+import { useStationVariables } from "@/state/query-hooks/use-station-variables";
+import { useStore } from "@/state/client/state-store";
const NavBlock = () => {
const data = useStore(
diff --git a/src/components/preview/StationPreview/PreviewGraph.js b/src/components/preview/StationPreview/PreviewGraph.js
index a65bc98e..c02cba9f 100644
--- a/src/components/preview/StationPreview/PreviewGraph.js
+++ b/src/components/preview/StationPreview/PreviewGraph.js
@@ -2,15 +2,16 @@ import React from "react";
import { Spinner } from "react-bootstrap";
import map from "lodash/fp/map";
import { useShallow } from "zustand/react/shallow";
-import { useStore } from "../../../state/state-store";
-import { useStationVariableObservations } from "../../../state/query-hooks/use-station-variable-observations";
+import { useStore } from "@/state/client/state-store";
+import { useStationVariableObservations } from "@/state/query-hooks/use-station-variable-observations";
+import { useConfigContext } from "@/state/context-hooks/use-config-context";
// Importing a smaller version of plotly allows us to significantly reduce the
// bundle size (approx 5MB to 1MB) over the full version of plotly.
// https://github.com/plotly/react-plotly.js?tab=readme-ov-file#customizing-the-plotlyjs-bundle
import Plotly from "plotly.js-basic-dist";
import createPlotlyComponent from "react-plotly.js/factory";
-import { useConfig } from "../../../state/query-hooks/use-config";
+
const Plot = createPlotlyComponent(Plotly);
const PreviewGraph = ({ variableId }) => {
@@ -23,7 +24,7 @@ const PreviewGraph = ({ variableId }) => {
showLegend: state.showLegend,
})),
);
- const { data: config } = useConfig();
+ const config = useConfigContext();
const {
data: previewObservations,
isLoading,
diff --git a/src/components/preview/StationPreview/RangeBlock.js b/src/components/preview/StationPreview/RangeBlock.js
index 50598608..6404b841 100644
--- a/src/components/preview/StationPreview/RangeBlock.js
+++ b/src/components/preview/StationPreview/RangeBlock.js
@@ -1,21 +1,19 @@
-import React, { useState, useEffect } from "react";
-import DateRange from "../../daterange";
-import startOfMonth from "date-fns/startOfMonth";
-import endOfMonth from "date-fns/endOfMonth";
+import React from "react";
+import DateRange from "@/components/daterange";
import addDays from "date-fns/addDays";
import differenceInDays from "date-fns/differenceInDays";
import differenceInYears from "date-fns/differenceInYears";
import startOfDecade from "date-fns/startOfDecade";
import endOfDecade from "date-fns/endOfDecade";
-import { useStore } from "../../../state/state-store";
-import { useConfig } from "../../../state/query-hooks/use-config";
-import { useStationVariables } from "../../../state/query-hooks/use-station-variables";
+import { useStore } from "@/state/client/state-store";
+import { useStationVariables } from "@/state/query-hooks/use-station-variables";
+import useConfigContext from "@/state/context-hooks/use-config-context";
const millisecondsPerMonth = 2629746000;
const millisedondsPerDay = 86400000;
const RangeBlock = ({}) => {
- const { data: config } = useConfig();
+ const config = useConfigContext();
const storeData = useStore((state) => ({
stationId: state.stationId,
minStartDate: state.minStartDate,