Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/clear-tables-document.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@usace-watermanagement/groundwork-water": patch
---

Document pre-fetched CWMSTable data and publish accurate optional prop types.
106 changes: 101 additions & 5 deletions docs/src/pages/docs/tables/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,40 @@ import { cdaTSHookParams } from "../../../props-declarations/data-hooks";
import { Badge, Text, UsaceBox } from "@usace/groundwork";
import CdaParamsTable from "../../components/cda-params-table.jsx";

const preloadedTimeseriesParams = [
{
tsid: "DEMO.Stage.Inst.1Hour.0.Observed",
header: "Stage (ft)",
precision: 2,
},
{
tsid: "DEMO.Flow.Inst.1Hour.0.Observed",
header: "Flow (cfs)",
precision: 0,
},
];

const preloadedTimeSeries = [
{
name: "DEMO.Stage.Inst.1Hour.0.Observed",
units: "ft",
values: [
[Date.parse("2026-08-18T08:00:00-05:00"), 12.34, 0],
[Date.parse("2026-08-18T09:00:00-05:00"), 12.41, 0],
[Date.parse("2026-08-18T10:00:00-05:00"), 12.47, 0],
],
},
{
name: "DEMO.Flow.Inst.1Hour.0.Observed",
units: "cfs",
values: [
[Date.parse("2026-08-18T08:00:00-05:00"), 842, 0],
[Date.parse("2026-08-18T09:00:00-05:00"), 875, 0],
[Date.parse("2026-08-18T10:00:00-05:00"), 901, 0],
],
},
];

function Tables() {
const LOOKBACK_HOURS = 24;
const tsid = "KEYS.Elev.Inst.1Hour.0.Ccp-Rev";
Expand Down Expand Up @@ -47,7 +81,7 @@ function Tables() {
precision: 2,
},
{
tsid: "SHB.Temp-Air.Inst.0.0.DCP-rev",
tsid: "SHB.Temp-Air.Inst.30Minutes.0.DCP-rev",
header: "SHB.Temp-Air (F)",
precision: 0,
},
Expand Down Expand Up @@ -77,12 +111,74 @@ function Tables() {
end={cdaParams.end}
office={cdaParams.office}
timeseriesParams={tableTimeseriesParams}
interval="5"
interval={5}
snapTopOfInterval={true}
missingString="---"
sortAscending={false}
tableOptions={{ maxHeight: "45vh", className: "gw-mt-4" }}
/>
<Divider text="Use Pre-Fetched Data" className="mt-8" />
<Text>
To render data you already have, pass CDA-compatible time-series responses to
<code className="font-bold"> inputTSValues</code>. Each
<code className="font-bold"> timeseriesParams[].tsid</code> must match a
supplied series <code className="font-bold">name</code>. The value tuples
begin with a Unix timestamp in milliseconds and a value; quality codes and
other CDA metadata may follow.
</Text>
<Text className="mt-2">
When <code className="font-bold">inputTSValues</code> is supplied, the table
does not make CDA requests, so <code className="font-bold">office</code>,
<code className="font-bold"> begin</code>, and
<code className="font-bold"> end</code> are not required.
</Text>
<CWMSTable
timeseriesParams={preloadedTimeseriesParams}
inputTSValues={preloadedTimeSeries}
dateFormat="MMM D, YYYY h:mm A"
tableOptions={{ maxHeight: "24rem", className: "gw-mt-4" }}
/>
<Code className="mt-4" language="jsx">
{`const timeseriesParams = [
{
tsid: "DEMO.Stage.Inst.1Hour.0.Observed",
header: "Stage (ft)",
precision: 2,
},
{
tsid: "DEMO.Flow.Inst.1Hour.0.Observed",
header: "Flow (cfs)",
precision: 0,
},
];

const inputTSValues = [
{
name: "DEMO.Stage.Inst.1Hour.0.Observed",
units: "ft",
values: [
[Date.parse("2026-08-18T08:00:00-05:00"), 12.34, 0],
[Date.parse("2026-08-18T09:00:00-05:00"), 12.41, 0],
[Date.parse("2026-08-18T10:00:00-05:00"), 12.47, 0],
],
},
{
name: "DEMO.Flow.Inst.1Hour.0.Observed",
units: "cfs",
values: [
[Date.parse("2026-08-18T08:00:00-05:00"), 842, 0],
[Date.parse("2026-08-18T09:00:00-05:00"), 875, 0],
[Date.parse("2026-08-18T10:00:00-05:00"), 901, 0],
],
},
];

<CWMSTable
timeseriesParams={timeseriesParams}
inputTSValues={inputTSValues}
dateFormat="MMM D, YYYY h:mm A"
/>`}
</Code>
<Divider text="Header Line Breaks" className="mt-8" />
<Text className="mb-2">
The header for the table can be set to an HTML tag or component with line
Expand All @@ -100,7 +196,7 @@ const tableTimeseriesParams = [
]`}
</Code>
<Badge color="blue" className="mb-2">
Note: Using "\n" will NOT create a line break in the header.
Note: Using &quot;\n&quot; will NOT create a line break in the header.
</Badge>
<Divider text="Code Example:" className="mt-8" />
<div className="mt-8">
Expand Down Expand Up @@ -136,7 +232,7 @@ default export function Example() {
precision: 2,
},
{
tsid: "SHB.Temp-Air.Inst.0.0.DCP-rev",
tsid: "SHB.Temp-Air.Inst.30Minutes.0.DCP-rev",
header: "SHB.Temp-Air (F)",
precision: 0,
},
Expand All @@ -150,7 +246,7 @@ default export function Example() {
end={cdaParams.end}
office={cdaParams.office}
timeseriesParams={tableTimeseriesParams}
interval="5"
interval={5}
snapTopOfInterval={true}
missingString="---"
sortAscending={false}
Expand Down
13 changes: 11 additions & 2 deletions docs/src/props-declarations/tables.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,18 @@ const cwmsTableParams = [
},
{
name: "inputTSValues",
type: "array",
type: "CWMSTableSeries[]",
required: false,
desc: "Previously fetched CWMS time-series responses. When supplied, the table renders these values without making CDA requests and does not require an office.",
desc: (
<>
Previously fetched CWMS time-series responses shaped as{" "}
<Code>{`{ name, units?, values: [[timestamp, value, qualityCode?, ...], ...] }`}</Code>
. Each series <Code>name</Code> must match a{" "}
<Code>timeseriesParams[].tsid</Code>. When supplied, the table makes no CDA
requests and does not require <Code>office</Code>, <Code>begin</Code>, or{" "}
<Code>end</Code>.
</>
),
},
{
name: "dateTimeTableColumnHeader",
Expand Down
1 change: 1 addition & 0 deletions docs/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default defineConfig(({ mode }) => {
plugins: [react(), tailwindcss()],
base: base,
resolve: {
dedupe: ["react", "react-dom", "@tanstack/react-query"],
alias: isDevelopment
? [
// During development, alias to the source files for easier debugging
Expand Down
54 changes: 54 additions & 0 deletions lib/components/data/tables/CWMSTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,60 @@ function TableMessage({ children, tone = "info" }) {
);
}

/**
* A CWMS time-series value tuple. The first two entries are the Unix timestamp in
* milliseconds and the value. CDA responses may include quality codes and other
* metadata in later entries.
*
* @typedef {[number, number | string | null, ...unknown[]]} CWMSTableValue
*/

/**
* @typedef {Object} CWMSTableSeries
* @property {string} name Fully qualified time-series ID.
* @property {string} [units] Units returned for the series.
* @property {CWMSTableValue[]} values Time-series value tuples.
*/

/**
* @typedef {Object} CWMSTableTimeseriesParam
* @property {string} tsid Fully qualified time-series ID matching a series name.
* @property {import("react").ReactNode} [header] Column heading.
* @property {number} [precision] Number of decimal places to display.
* @property {number} [rounding] Alias for precision.
*/

/**
* @typedef {Record<string, unknown> & {
* className?: string,
* maxHeight?: string,
* overflowHeight?: string
* }} CWMSTableOptions
*/

/**
* @typedef {Object} CWMSTableProps
* @property {CWMSTableTimeseriesParam[]} timeseriesParams Series and columns to show.
* @property {string} [office] Owning office used when fetching from CDA.
* @property {string} [unit="EN"] Unit or unit system used when fetching from CDA.
* @property {string} [datum] Elevation datum used when fetching from CDA.
* @property {string} [begin] Beginning of the requested time range.
* @property {string} [end] End of the requested time range.
* @property {string} [timezone] Time zone for begin and end.
* @property {CWMSTableSeries[]} [inputTSValues] Pre-fetched CWMS time-series responses.
* @property {boolean} [trim=true] Whether CDA should trim leading and trailing missing values.
* @property {number | string} [pageSize] Maximum number of values requested from CDA.
* @property {number | string} [interval=1] Display interval in minutes.
* @property {boolean} [snapTopOfInterval=true] Whether interval filtering is clock-aligned.
* @property {boolean} [sortAscending=true] Whether rows are sorted oldest first.
* @property {string} [missingString=""] Text shown for missing values.
* @property {string} [dateFormat="ddd MMM DD HH:mm"] Day.js display format.
* @property {string} [cdaUrl] CDA base URL override.
* @property {string} [dateTimeTableColumnHeader="Date & Time (Local)"] Date column heading.
* @property {CWMSTableOptions} [tableOptions] Virtualized table container options.
*/

/** @param {CWMSTableProps} props */
export default function CWMSTable({
timeseriesParams,
office,
Expand Down