@databricks/appkit-ui 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/js/format/index.d.ts +38 -0
- package/dist/js/format/index.d.ts.map +1 -0
- package/dist/js/format/index.js +160 -0
- package/dist/js/format/index.js.map +1 -0
- package/dist/js/index.d.ts +5 -1
- package/dist/js/index.js +3 -1
- package/dist/js/metric-filter/index.d.ts +40 -0
- package/dist/js/metric-filter/index.d.ts.map +1 -0
- package/dist/js/metric-filter/index.js +56 -0
- package/dist/js/metric-filter/index.js.map +1 -0
- package/dist/react/charts/base.d.ts +19 -2
- package/dist/react/charts/base.d.ts.map +1 -1
- package/dist/react/charts/base.js +28 -8
- package/dist/react/charts/base.js.map +1 -1
- package/dist/react/charts/index.d.ts +4 -3
- package/dist/react/charts/normalize.d.ts.map +1 -1
- package/dist/react/charts/normalize.js +6 -6
- package/dist/react/charts/normalize.js.map +1 -1
- package/dist/react/charts/options.d.ts +31 -2
- package/dist/react/charts/options.d.ts.map +1 -1
- package/dist/react/charts/options.js +150 -13
- package/dist/react/charts/options.js.map +1 -1
- package/dist/react/charts/types.d.ts +54 -1
- package/dist/react/charts/types.d.ts.map +1 -1
- package/dist/react/charts/types.js.map +1 -1
- package/dist/react/charts/utils.d.ts +8 -9
- package/dist/react/charts/utils.d.ts.map +1 -1
- package/dist/react/charts/utils.js +135 -28
- package/dist/react/charts/utils.js.map +1 -1
- package/dist/react/hooks/analytics-sse.js +117 -0
- package/dist/react/hooks/analytics-sse.js.map +1 -0
- package/dist/react/hooks/index.d.ts +4 -1
- package/dist/react/hooks/types.d.ts +90 -4
- package/dist/react/hooks/types.d.ts.map +1 -1
- package/dist/react/hooks/use-analytics-query.d.ts.map +1 -1
- package/dist/react/hooks/use-analytics-query.js +14 -74
- package/dist/react/hooks/use-analytics-query.js.map +1 -1
- package/dist/react/hooks/use-metric-view.d.ts +39 -0
- package/dist/react/hooks/use-metric-view.d.ts.map +1 -0
- package/dist/react/hooks/use-metric-view.js +178 -0
- package/dist/react/hooks/use-metric-view.js.map +1 -0
- package/dist/react/index.d.ts +9 -5
- package/dist/react/index.js +5 -3
- package/dist/react/lib/format.js +3 -1
- package/dist/react/lib/format.js.map +1 -1
- package/dist/shared/src/index.d.ts +2 -0
- package/dist/shared/src/metric-filter.d.ts +36 -0
- package/dist/shared/src/metric-filter.d.ts.map +1 -0
- package/dist/shared/src/metric-metadata.d.ts +15 -0
- package/dist/shared/src/metric-metadata.d.ts.map +1 -0
- package/docs/development/type-generation.md +7 -6
- package/docs/plugins/ai-search.md +10 -0
- package/docs/plugins/analytics.md +287 -12
- package/package.json +1 -1
- package/sbom.cdx.json +1 -1
|
@@ -16,6 +16,8 @@ type Orientation = "vertical" | "horizontal";
|
|
|
16
16
|
type ChartType = "bar" | "line" | "area" | "pie" | "donut" | "scatter" | "radar" | "heatmap";
|
|
17
17
|
/** Data that can be passed to unified charts */
|
|
18
18
|
type ChartData = Table | Record<string, unknown>[];
|
|
19
|
+
/** Formats a measure value for chart axes, tooltips, and value labels. */
|
|
20
|
+
type ChartValueFormatter = (value: string | number, field: string) => string;
|
|
19
21
|
/** Color palette types for different visualization needs */
|
|
20
22
|
type ChartColorPalette = "categorical" | "sequential" | "diverging";
|
|
21
23
|
/** Resolved colors for the chart UI — axis text, titles, grid lines, and tooltip. */
|
|
@@ -58,6 +60,57 @@ interface ChartBaseProps {
|
|
|
58
60
|
testId?: string;
|
|
59
61
|
/** Additional ECharts options to merge */
|
|
60
62
|
options?: Record<string, unknown>;
|
|
63
|
+
/**
|
|
64
|
+
* Formats measure values in the chart's built-in value axes, tooltips, and
|
|
65
|
+
* value labels. `field` is the corresponding `yKey`, so one formatter can
|
|
66
|
+
* select a different format for each series.
|
|
67
|
+
*
|
|
68
|
+
* For charts with multiple series on one value axis, axis ticks use the
|
|
69
|
+
* first `yKey`; each tooltip uses its own series field.
|
|
70
|
+
*/
|
|
71
|
+
valueFormatter?: ChartValueFormatter;
|
|
72
|
+
/**
|
|
73
|
+
* Pointer-only: charts render to <canvas>, so this does not fire for keyboard
|
|
74
|
+
* users. Provide a keyboard-accessible equivalent (e.g. a table row action) for
|
|
75
|
+
* the same action.
|
|
76
|
+
*/
|
|
77
|
+
onDataClick?: (datum: ChartClickDatum) => void;
|
|
78
|
+
/**
|
|
79
|
+
* Controlled selection by category name. Matching data element(s) render at full
|
|
80
|
+
* prominence while the rest are dimmed. Drive it from your own state to reflect a
|
|
81
|
+
* cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis;
|
|
82
|
+
* other chart types ignore it.
|
|
83
|
+
*/
|
|
84
|
+
selected?: string | string[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* A normalized description of a clicked chart element.
|
|
88
|
+
*
|
|
89
|
+
* In the common cross-filter case, {@link ChartClickDatum.name} carries the
|
|
90
|
+
* dimension value of the clicked element.
|
|
91
|
+
*/
|
|
92
|
+
interface ChartClickDatum {
|
|
93
|
+
/** Category label of the clicked element — the dimension value in the common cross-filter case. */
|
|
94
|
+
name: string;
|
|
95
|
+
/**
|
|
96
|
+
* The datum's scalar value:
|
|
97
|
+
* - bar / pie — the datum itself.
|
|
98
|
+
* - time-series / scatter — the y-component of the `[x, y]` point (see
|
|
99
|
+
* {@link ChartClickDatum.x} / {@link ChartClickDatum.y}).
|
|
100
|
+
* - heatmap — the cell value (the third entry of ECharts'
|
|
101
|
+
* `[xIndex, yIndex, value]` triple), *not* an axis index.
|
|
102
|
+
* - radar — `null`; the item holds one value per indicator, so there is no
|
|
103
|
+
* single scalar to report. Read the vector from {@link ChartClickDatum.raw}.
|
|
104
|
+
*
|
|
105
|
+
* `null` whenever there is no scalar value to surface.
|
|
106
|
+
*/
|
|
107
|
+
value: number | string | null;
|
|
108
|
+
x?: number | string;
|
|
109
|
+
y?: number | string;
|
|
110
|
+
seriesName?: string;
|
|
111
|
+
dataIndex: number;
|
|
112
|
+
seriesIndex: number;
|
|
113
|
+
raw: unknown;
|
|
61
114
|
}
|
|
62
115
|
/** Props for query-based data fetching */
|
|
63
116
|
interface QueryProps extends ChartBaseProps {
|
|
@@ -174,5 +227,5 @@ declare function isQueryProps(props: UnifiedChartProps): props is QueryProps;
|
|
|
174
227
|
/** Type guard to check if props are data-based */
|
|
175
228
|
declare function isDataProps(props: UnifiedChartProps): props is DataProps;
|
|
176
229
|
//#endregion
|
|
177
|
-
export { AreaChartProps, AreaChartSpecificProps, BarChartProps, BarChartSpecificProps, ChartBaseProps, ChartColorPalette, ChartData, ChartType, ChartUITokens, DataFormat, DataProps, DonutChartProps, HeatmapChartProps, HeatmapChartSpecificProps, LineChartProps, LineChartSpecificProps, NormalizedChartData, NormalizedChartDataBase, Orientation, PieChartProps, PieChartSpecificProps, QueryProps, RadarChartProps, RadarChartSpecificProps, ScatterChartProps, ScatterChartSpecificProps, UnifiedChartProps, isArrowTable, isDataProps, isQueryProps };
|
|
230
|
+
export { AreaChartProps, AreaChartSpecificProps, BarChartProps, BarChartSpecificProps, ChartBaseProps, ChartClickDatum, ChartColorPalette, ChartData, ChartType, ChartUITokens, ChartValueFormatter, DataFormat, DataProps, DonutChartProps, HeatmapChartProps, HeatmapChartSpecificProps, LineChartProps, LineChartSpecificProps, NormalizedChartData, NormalizedChartDataBase, Orientation, PieChartProps, PieChartSpecificProps, QueryProps, RadarChartProps, RadarChartSpecificProps, ScatterChartProps, ScatterChartSpecificProps, UnifiedChartProps, isArrowTable, isDataProps, isQueryProps };
|
|
178
231
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/react/charts/types.ts"],"mappings":";;;;;AAcA;;;;;AAUA;KAVY,UAAA;;KAUA,WAAA;;KAGA,SAAA;AAWZ;AAAA,KAAY,SAAA,GAAY,KAAA,GAAQ,MAAA;;
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/react/charts/types.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/react/charts/types.ts"],"sourcesContent":["import type { Table } from \"apache-arrow\";\n\n// ============================================================================\n// Data Format Types\n// ============================================================================\n\n/**\n * Supported data formats for analytics queries.\n *\n * \"json\" and \"arrow\" are legacy aliases kept for backwards compatibility\n * with appkit-ui < 0.33.0 — safe to remove once no consumer is on a\n * pre-0.33.0 version. resolveFormat() normalizes them to their canonical\n * equivalents before any downstream code reads the value.\n */\nexport type DataFormat =\n | \"json_array\"\n | \"arrow_stream\"\n | \"auto\"\n /** @deprecated Use \"json_array\". Safe to remove once no consumer is on appkit-ui < 0.33.0. */\n | \"json\"\n /** @deprecated Use \"arrow_stream\". Safe to remove once no consumer is on appkit-ui < 0.33.0. */\n | \"arrow\";\n\n/** Chart orientation */\nexport type Orientation = \"vertical\" | \"horizontal\";\n\n/** Supported chart types */\nexport type ChartType =\n | \"bar\"\n | \"line\"\n | \"area\"\n | \"pie\"\n | \"donut\"\n | \"scatter\"\n | \"radar\"\n | \"heatmap\";\n\n/** Data that can be passed to unified charts */\nexport type ChartData = Table | Record<string, unknown>[];\n\n// ============================================================================\n// Base Props (shared by all charts)\n// ============================================================================\n\n/** Color palette types for different visualization needs */\nexport type ChartColorPalette = \"categorical\" | \"sequential\" | \"diverging\";\n\n/** Resolved colors for the chart UI — axis text, titles, grid lines, and tooltip. */\nexport interface ChartUITokens {\n /** Axis tick labels (≈ `--muted-foreground`) */\n axisLabel: string;\n /** Axis names, legend, title, and visualMap text (≈ `--foreground`) */\n axisTitle: string;\n /** Axis, tick, and split (grid) lines (≈ `--border`) */\n grid: string;\n /** Tooltip popover background (≈ `--popover`) */\n tooltipBg: string;\n}\n\n/** Common visual and behavior props for all charts */\nexport interface ChartBaseProps {\n /** Chart title */\n title?: string;\n /** Show legend */\n showLegend?: boolean;\n /**\n * Color palette to use. Auto-selected based on chart type if not specified.\n * - \"categorical\": Distinct colors for different categories (bar, pie, line)\n * - \"sequential\": Gradient for magnitude/intensity (heatmap)\n * - \"diverging\": Two-tone for positive/negative values\n */\n colorPalette?: ChartColorPalette;\n /** Custom colors for series (overrides colorPalette) */\n colors?: string[];\n /** Chart height in pixels @default 300 */\n height?: number;\n /** Additional CSS classes */\n className?: string;\n\n /** X-axis field key. Auto-detected from schema if not provided. */\n xKey?: string;\n /** Y-axis field key(s). Auto-detected from schema if not provided. */\n yKey?: string | string[];\n\n /** Accessibility label for screen readers */\n ariaLabel?: string;\n /** Test ID for automated testing */\n testId?: string;\n\n /** Additional ECharts options to merge */\n options?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Query-based Props (chart fetches data)\n// ============================================================================\n\n/** Props for query-based data fetching */\nexport interface QueryProps extends ChartBaseProps {\n /** Analytics query key registered with analytics plugin */\n queryKey: string;\n /** Query parameters passed to the analytics endpoint */\n parameters?: Record<string, unknown>;\n /**\n * Data format to use\n * - \"json_array\": Use JSON format (smaller payloads, simpler)\n * - \"arrow_stream\": Use Arrow format (faster for large datasets)\n * - \"auto\": Automatically select based on expected data size\n * @default \"auto\"\n */\n format?: DataFormat;\n /** Transform raw data before rendering */\n transformer?: <T>(data: T) => T;\n // Discriminator: cannot use direct data with query\n data?: never;\n}\n\n// ============================================================================\n// Data-based Props (chart receives data externally)\n// ============================================================================\n\n/** Props for direct data injection */\nexport interface DataProps extends ChartBaseProps {\n /** Arrow Table or JSON array */\n data: ChartData;\n\n // Discriminator: cannot use query props with direct data\n queryKey?: never;\n parameters?: never;\n format?: never;\n transformer?: never;\n}\n\n// ============================================================================\n// Union Types for Each Chart\n// ============================================================================\n\n/** Base union type - either query-based or data-based */\nexport type UnifiedChartProps = QueryProps | DataProps;\n\n// ============================================================================\n// Chart-Specific Props\n// ============================================================================\n\n/** Props specific to bar charts */\nexport interface BarChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Stack bars */\n stacked?: boolean;\n}\n\n/** Props specific to line charts */\nexport interface LineChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Show data point symbols @default false */\n showSymbol?: boolean;\n /** Smooth line curves @default true */\n smooth?: boolean;\n}\n\n/** Props specific to area charts */\nexport interface AreaChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Show data point symbols @default false */\n showSymbol?: boolean;\n /** Smooth line curves @default true */\n smooth?: boolean;\n /** Stack areas @default false */\n stacked?: boolean;\n}\n\n/** Props specific to scatter charts */\nexport interface ScatterChartSpecificProps {\n /** Symbol size @default 8 */\n symbolSize?: number;\n}\n\n/** Props specific to pie/donut charts */\nexport interface PieChartSpecificProps {\n /** Inner radius for donut charts (0-100%) @default 0 */\n innerRadius?: number;\n /** Show labels on slices @default true */\n showLabels?: boolean;\n /** Label position @default \"outside\" */\n labelPosition?: \"outside\" | \"inside\" | \"center\";\n}\n\n/** Props specific to radar charts */\nexport interface RadarChartSpecificProps {\n /** Show area fill @default true */\n showArea?: boolean;\n}\n\n/** Props specific to heatmap charts */\nexport interface HeatmapChartSpecificProps {\n /**\n * Field key for the Y-axis categories.\n * For heatmaps, data should have: xKey (column), yAxisKey (row), and yKey (value).\n */\n yAxisKey?: string;\n /** Min value for color scale (auto-detected if not provided) */\n min?: number;\n /** Max value for color scale (auto-detected if not provided) */\n max?: number;\n /** Show value labels on cells @default false */\n showLabels?: boolean;\n}\n\n// ============================================================================\n// Complete Chart Props (union + specific)\n// ============================================================================\n\nexport type BarChartProps = (QueryProps | DataProps) & BarChartSpecificProps;\nexport type LineChartProps = (QueryProps | DataProps) & LineChartSpecificProps;\nexport type AreaChartProps = (QueryProps | DataProps) & AreaChartSpecificProps;\nexport type ScatterChartProps = (QueryProps | DataProps) &\n ScatterChartSpecificProps;\nexport type PieChartProps = (QueryProps | DataProps) & PieChartSpecificProps;\nexport type DonutChartProps = (QueryProps | DataProps) & PieChartSpecificProps;\nexport type RadarChartProps = (QueryProps | DataProps) &\n RadarChartSpecificProps;\nexport type HeatmapChartProps = (QueryProps | DataProps) &\n HeatmapChartSpecificProps;\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Base normalized data shared by all chart types */\nexport interface NormalizedChartDataBase {\n xData: (string | number)[];\n xField: string;\n yFields: string[];\n chartType: \"timeseries\" | \"categorical\";\n}\n\n/** Normalized chart data for rendering (standard charts) */\nexport interface NormalizedChartData extends NormalizedChartDataBase {\n yDataMap: Record<string, (string | number)[]>;\n}\n\n/** Type guard to check if data is an Arrow Table */\nexport function isArrowTable(data: ChartData): data is Table {\n return (\n data !== null &&\n typeof data === \"object\" &&\n \"schema\" in data &&\n \"numRows\" in data &&\n typeof (data as Table).getChild === \"function\"\n );\n}\n\n/** Type guard to check if props are query-based */\nexport function isQueryProps(props: UnifiedChartProps): props is QueryProps {\n return (\n \"queryKey\" in props &&\n typeof props.queryKey === \"string\" &&\n props.queryKey.length > 0\n );\n}\n\n/** Type guard to check if props are data-based */\nexport function isDataProps(props: UnifiedChartProps): props is DataProps {\n return \"data\" in props && props.data != null;\n}\n"],"mappings":";;AAqPA,SAAgB,aAAa,MAAgC;AAC3D,QACE,SAAS,QACT,OAAO,SAAS,YAChB,YAAY,QACZ,aAAa,QACb,OAAQ,KAAe,aAAa;;;AAKxC,SAAgB,aAAa,OAA+C;AAC1E,QACE,cAAc,SACd,OAAO,MAAM,aAAa,YAC1B,MAAM,SAAS,SAAS;;;AAK5B,SAAgB,YAAY,OAA8C;AACxE,QAAO,UAAU,SAAS,MAAM,QAAQ"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/react/charts/types.ts"],"sourcesContent":["import type { Table } from \"apache-arrow\";\n\n// ============================================================================\n// Data Format Types\n// ============================================================================\n\n/**\n * Supported data formats for analytics queries.\n *\n * \"json\" and \"arrow\" are legacy aliases kept for backwards compatibility\n * with appkit-ui < 0.33.0 — safe to remove once no consumer is on a\n * pre-0.33.0 version. resolveFormat() normalizes them to their canonical\n * equivalents before any downstream code reads the value.\n */\nexport type DataFormat =\n | \"json_array\"\n | \"arrow_stream\"\n | \"auto\"\n /** @deprecated Use \"json_array\". Safe to remove once no consumer is on appkit-ui < 0.33.0. */\n | \"json\"\n /** @deprecated Use \"arrow_stream\". Safe to remove once no consumer is on appkit-ui < 0.33.0. */\n | \"arrow\";\n\n/** Chart orientation */\nexport type Orientation = \"vertical\" | \"horizontal\";\n\n/** Supported chart types */\nexport type ChartType =\n | \"bar\"\n | \"line\"\n | \"area\"\n | \"pie\"\n | \"donut\"\n | \"scatter\"\n | \"radar\"\n | \"heatmap\";\n\n/** Data that can be passed to unified charts */\nexport type ChartData = Table | Record<string, unknown>[];\n\n/** Formats a measure value for chart axes, tooltips, and value labels. */\nexport type ChartValueFormatter = (\n value: string | number,\n field: string,\n) => string;\n\n// ============================================================================\n// Base Props (shared by all charts)\n// ============================================================================\n\n/** Color palette types for different visualization needs */\nexport type ChartColorPalette = \"categorical\" | \"sequential\" | \"diverging\";\n\n/** Resolved colors for the chart UI — axis text, titles, grid lines, and tooltip. */\nexport interface ChartUITokens {\n /** Axis tick labels (≈ `--muted-foreground`) */\n axisLabel: string;\n /** Axis names, legend, title, and visualMap text (≈ `--foreground`) */\n axisTitle: string;\n /** Axis, tick, and split (grid) lines (≈ `--border`) */\n grid: string;\n /** Tooltip popover background (≈ `--popover`) */\n tooltipBg: string;\n}\n\n/** Common visual and behavior props for all charts */\nexport interface ChartBaseProps {\n /** Chart title */\n title?: string;\n /** Show legend */\n showLegend?: boolean;\n /**\n * Color palette to use. Auto-selected based on chart type if not specified.\n * - \"categorical\": Distinct colors for different categories (bar, pie, line)\n * - \"sequential\": Gradient for magnitude/intensity (heatmap)\n * - \"diverging\": Two-tone for positive/negative values\n */\n colorPalette?: ChartColorPalette;\n /** Custom colors for series (overrides colorPalette) */\n colors?: string[];\n /** Chart height in pixels @default 300 */\n height?: number;\n /** Additional CSS classes */\n className?: string;\n\n /** X-axis field key. Auto-detected from schema if not provided. */\n xKey?: string;\n /** Y-axis field key(s). Auto-detected from schema if not provided. */\n yKey?: string | string[];\n\n /** Accessibility label for screen readers */\n ariaLabel?: string;\n /** Test ID for automated testing */\n testId?: string;\n\n /** Additional ECharts options to merge */\n options?: Record<string, unknown>;\n\n /**\n * Formats measure values in the chart's built-in value axes, tooltips, and\n * value labels. `field` is the corresponding `yKey`, so one formatter can\n * select a different format for each series.\n *\n * For charts with multiple series on one value axis, axis ticks use the\n * first `yKey`; each tooltip uses its own series field.\n */\n valueFormatter?: ChartValueFormatter;\n\n /**\n * Pointer-only: charts render to <canvas>, so this does not fire for keyboard\n * users. Provide a keyboard-accessible equivalent (e.g. a table row action) for\n * the same action.\n */\n onDataClick?: (datum: ChartClickDatum) => void;\n\n /**\n * Controlled selection by category name. Matching data element(s) render at full\n * prominence while the rest are dimmed. Drive it from your own state to reflect a\n * cross-filter or selection. Categorical charts (bar, pie/donut) show emphasis;\n * other chart types ignore it.\n */\n selected?: string | string[];\n}\n\n// ============================================================================\n// Interaction / Click Events\n// ============================================================================\n\n/**\n * A normalized description of a clicked chart element.\n *\n * In the common cross-filter case, {@link ChartClickDatum.name} carries the\n * dimension value of the clicked element.\n */\nexport interface ChartClickDatum {\n /** Category label of the clicked element — the dimension value in the common cross-filter case. */\n name: string;\n /**\n * The datum's scalar value:\n * - bar / pie — the datum itself.\n * - time-series / scatter — the y-component of the `[x, y]` point (see\n * {@link ChartClickDatum.x} / {@link ChartClickDatum.y}).\n * - heatmap — the cell value (the third entry of ECharts'\n * `[xIndex, yIndex, value]` triple), *not* an axis index.\n * - radar — `null`; the item holds one value per indicator, so there is no\n * single scalar to report. Read the vector from {@link ChartClickDatum.raw}.\n *\n * `null` whenever there is no scalar value to surface.\n */\n value: number | string | null;\n x?: number | string;\n y?: number | string;\n seriesName?: string;\n dataIndex: number;\n seriesIndex: number;\n // Untouched ECharts event params.\n raw: unknown;\n}\n\n// ============================================================================\n// Query-based Props (chart fetches data)\n// ============================================================================\n\n/** Props for query-based data fetching */\nexport interface QueryProps extends ChartBaseProps {\n /** Analytics query key registered with analytics plugin */\n queryKey: string;\n /** Query parameters passed to the analytics endpoint */\n parameters?: Record<string, unknown>;\n /**\n * Data format to use\n * - \"json_array\": Use JSON format (smaller payloads, simpler)\n * - \"arrow_stream\": Use Arrow format (faster for large datasets)\n * - \"auto\": Automatically select based on expected data size\n * @default \"auto\"\n */\n format?: DataFormat;\n /** Transform raw data before rendering */\n transformer?: <T>(data: T) => T;\n // Discriminator: cannot use direct data with query\n data?: never;\n}\n\n// ============================================================================\n// Data-based Props (chart receives data externally)\n// ============================================================================\n\n/** Props for direct data injection */\nexport interface DataProps extends ChartBaseProps {\n /** Arrow Table or JSON array */\n data: ChartData;\n\n // Discriminator: cannot use query props with direct data\n queryKey?: never;\n parameters?: never;\n format?: never;\n transformer?: never;\n}\n\n// ============================================================================\n// Union Types for Each Chart\n// ============================================================================\n\n/** Base union type - either query-based or data-based */\nexport type UnifiedChartProps = QueryProps | DataProps;\n\n// ============================================================================\n// Chart-Specific Props\n// ============================================================================\n\n/** Props specific to bar charts */\nexport interface BarChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Stack bars */\n stacked?: boolean;\n}\n\n/** Props specific to line charts */\nexport interface LineChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Show data point symbols @default false */\n showSymbol?: boolean;\n /** Smooth line curves @default true */\n smooth?: boolean;\n}\n\n/** Props specific to area charts */\nexport interface AreaChartSpecificProps {\n /** Chart orientation @default \"vertical\" */\n orientation?: Orientation;\n /** Show data point symbols @default false */\n showSymbol?: boolean;\n /** Smooth line curves @default true */\n smooth?: boolean;\n /** Stack areas @default false */\n stacked?: boolean;\n}\n\n/** Props specific to scatter charts */\nexport interface ScatterChartSpecificProps {\n /** Symbol size @default 8 */\n symbolSize?: number;\n}\n\n/** Props specific to pie/donut charts */\nexport interface PieChartSpecificProps {\n /** Inner radius for donut charts (0-100%) @default 0 */\n innerRadius?: number;\n /** Show labels on slices @default true */\n showLabels?: boolean;\n /** Label position @default \"outside\" */\n labelPosition?: \"outside\" | \"inside\" | \"center\";\n}\n\n/** Props specific to radar charts */\nexport interface RadarChartSpecificProps {\n /** Show area fill @default true */\n showArea?: boolean;\n}\n\n/** Props specific to heatmap charts */\nexport interface HeatmapChartSpecificProps {\n /**\n * Field key for the Y-axis categories.\n * For heatmaps, data should have: xKey (column), yAxisKey (row), and yKey (value).\n */\n yAxisKey?: string;\n /** Min value for color scale (auto-detected if not provided) */\n min?: number;\n /** Max value for color scale (auto-detected if not provided) */\n max?: number;\n /** Show value labels on cells @default false */\n showLabels?: boolean;\n}\n\n// ============================================================================\n// Complete Chart Props (union + specific)\n// ============================================================================\n\nexport type BarChartProps = (QueryProps | DataProps) & BarChartSpecificProps;\nexport type LineChartProps = (QueryProps | DataProps) & LineChartSpecificProps;\nexport type AreaChartProps = (QueryProps | DataProps) & AreaChartSpecificProps;\nexport type ScatterChartProps = (QueryProps | DataProps) &\n ScatterChartSpecificProps;\nexport type PieChartProps = (QueryProps | DataProps) & PieChartSpecificProps;\nexport type DonutChartProps = (QueryProps | DataProps) & PieChartSpecificProps;\nexport type RadarChartProps = (QueryProps | DataProps) &\n RadarChartSpecificProps;\nexport type HeatmapChartProps = (QueryProps | DataProps) &\n HeatmapChartSpecificProps;\n\n// ============================================================================\n// Internal Types\n// ============================================================================\n\n/** Base normalized data shared by all chart types */\nexport interface NormalizedChartDataBase {\n xData: (string | number)[];\n xField: string;\n yFields: string[];\n chartType: \"timeseries\" | \"categorical\";\n}\n\n/** Normalized chart data for rendering (standard charts) */\nexport interface NormalizedChartData extends NormalizedChartDataBase {\n yDataMap: Record<string, (string | number)[]>;\n}\n\n/** Type guard to check if data is an Arrow Table */\nexport function isArrowTable(data: ChartData): data is Table {\n return (\n data !== null &&\n typeof data === \"object\" &&\n \"schema\" in data &&\n \"numRows\" in data &&\n typeof (data as Table).getChild === \"function\"\n );\n}\n\n/** Type guard to check if props are query-based */\nexport function isQueryProps(props: UnifiedChartProps): props is QueryProps {\n return (\n \"queryKey\" in props &&\n typeof props.queryKey === \"string\" &&\n props.queryKey.length > 0\n );\n}\n\n/** Type guard to check if props are data-based */\nexport function isDataProps(props: UnifiedChartProps): props is DataProps {\n return \"data\" in props && props.data != null;\n}\n"],"mappings":";;AAuTA,SAAgB,aAAa,MAAgC;AAC3D,QACE,SAAS,QACT,OAAO,SAAS,YAChB,YAAY,QACZ,aAAa,QACb,OAAQ,KAAe,aAAa;;;AAKxC,SAAgB,aAAa,OAA+C;AAC1E,QACE,cAAc,SACd,OAAO,MAAM,aAAa,YAC1B,MAAM,SAAS,SAAS;;;AAK5B,SAAgB,YAAY,OAA8C;AACxE,QAAO,UAAU,SAAS,MAAM,QAAQ"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { formatLabel } from "../../js/format/index.js";
|
|
2
|
+
import "../../js/index.js";
|
|
3
|
+
import "./types.js";
|
|
4
|
+
|
|
1
5
|
//#region src/react/charts/utils.d.ts
|
|
2
6
|
/**
|
|
3
7
|
* Converts a value to a chart-compatible type.
|
|
@@ -9,13 +13,6 @@ declare function toChartValue(value: unknown): string | number;
|
|
|
9
13
|
* Converts an array of values to chart-compatible types.
|
|
10
14
|
*/
|
|
11
15
|
declare function toChartArray(data: unknown[]): (string | number)[];
|
|
12
|
-
/**
|
|
13
|
-
* Formats a field name into a human-readable label.
|
|
14
|
-
* Handles camelCase, snake_case, acronyms, and ALL_CAPS.
|
|
15
|
-
* E.g., "totalSpend" -> "Total Spend", "user_name" -> "User Name",
|
|
16
|
-
* "userID" -> "User Id", "TOTAL_SPEND" -> "Total Spend"
|
|
17
|
-
*/
|
|
18
|
-
declare function formatLabel(field: string): string;
|
|
19
16
|
/**
|
|
20
17
|
* Truncates a label to a maximum length with ellipsis.
|
|
21
18
|
*/
|
|
@@ -25,12 +22,14 @@ declare function truncateLabel(value: string, maxLength?: number): string;
|
|
|
25
22
|
*/
|
|
26
23
|
declare function createTimeSeriesData(xData: (string | number)[], yData: (string | number)[]): [string | number, string | number][];
|
|
27
24
|
/**
|
|
28
|
-
* Sorts time-series data in ascending chronological order
|
|
25
|
+
* Sorts time-series data in ascending chronological order while preserving
|
|
26
|
+
* the correlation between each x value and its y values. Non-date category
|
|
27
|
+
* strings are intentionally left in their source order.
|
|
29
28
|
*/
|
|
30
29
|
declare function sortTimeSeriesAscending(xData: (string | number)[], yDataMap: Record<string, (string | number)[]>, yFields: string[]): {
|
|
31
30
|
xData: (string | number)[];
|
|
32
31
|
yDataMap: Record<string, (string | number)[]>;
|
|
33
32
|
};
|
|
34
33
|
//#endregion
|
|
35
|
-
export { createTimeSeriesData,
|
|
34
|
+
export { createTimeSeriesData, sortTimeSeriesAscending, toChartArray, toChartValue, truncateLabel };
|
|
36
35
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../../src/react/charts/utils.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../../src/react/charts/utils.ts"],"mappings":";;;;;;;;;AAWA;iBAAgB,YAAA,CAAa,KAAA;;;;iBAmBb,YAAA,CAAa,IAAA;;;AAkT7B;iBArRgB,aAAA,CAAc,KAAA,UAAe,SAAA;;;;iBAO7B,oBAAA,CACd,KAAA,uBACA,KAAA;;;;;;iBA4Qc,uBAAA,CACd,KAAA,uBACA,QAAA,EAAU,MAAA,+BACV,OAAA;EAEA,KAAA;EACA,QAAA,EAAU,MAAA;AAAA"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { formatLabel } from "../../js/format/index.js";
|
|
2
|
+
|
|
1
3
|
//#region src/react/charts/utils.ts
|
|
2
4
|
/**
|
|
3
5
|
* Converts a value to a chart-compatible type.
|
|
@@ -19,15 +21,6 @@ function toChartArray(data) {
|
|
|
19
21
|
return data.map(toChartValue);
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
|
-
* Formats a field name into a human-readable label.
|
|
23
|
-
* Handles camelCase, snake_case, acronyms, and ALL_CAPS.
|
|
24
|
-
* E.g., "totalSpend" -> "Total Spend", "user_name" -> "User Name",
|
|
25
|
-
* "userID" -> "User Id", "TOTAL_SPEND" -> "Total Spend"
|
|
26
|
-
*/
|
|
27
|
-
function formatLabel(field) {
|
|
28
|
-
return field.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").replace(/\s+/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase()).trim();
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
24
|
* Escapes HTML special characters to prevent XSS.
|
|
32
25
|
* Required for ECharts function formatters: unlike string-template
|
|
33
26
|
* formatters, their return values are injected as raw HTML into the
|
|
@@ -77,36 +70,150 @@ function sortNumericAscending(xData, yDataMap, yFields) {
|
|
|
77
70
|
yDataMap: sortedYDataMap
|
|
78
71
|
};
|
|
79
72
|
}
|
|
73
|
+
function resolveLineStrokePoint(params, axes, instance) {
|
|
74
|
+
if (params.seriesType !== "line" || params.value !== void 0 || !instance || typeof params.seriesIndex !== "number") return null;
|
|
75
|
+
const clickX = (params.event !== null && typeof params.event === "object" ? params.event : null)?.offsetX;
|
|
76
|
+
if (typeof clickX !== "number") return null;
|
|
77
|
+
try {
|
|
78
|
+
const option = instance.getOption();
|
|
79
|
+
if (option === null || typeof option !== "object") return null;
|
|
80
|
+
const series = option.series;
|
|
81
|
+
if (!Array.isArray(series)) return null;
|
|
82
|
+
const seriesOption = series[params.seriesIndex];
|
|
83
|
+
if (seriesOption === null || typeof seriesOption !== "object" || Array.isArray(seriesOption)) return null;
|
|
84
|
+
const data = seriesOption.data;
|
|
85
|
+
if (!Array.isArray(data)) return null;
|
|
86
|
+
let nearest = null;
|
|
87
|
+
let nearestDistance = Number.POSITIVE_INFINITY;
|
|
88
|
+
for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {
|
|
89
|
+
const item = data[dataIndex];
|
|
90
|
+
const itemRecord = item !== null && typeof item === "object" && !Array.isArray(item) ? item : null;
|
|
91
|
+
const rawValue = itemRecord ? itemRecord.value : item;
|
|
92
|
+
let x;
|
|
93
|
+
let y;
|
|
94
|
+
if (Array.isArray(rawValue)) {
|
|
95
|
+
if ((typeof rawValue[0] === "string" || typeof rawValue[0] === "number") && (typeof rawValue[1] === "string" || typeof rawValue[1] === "number")) {
|
|
96
|
+
x = rawValue[0];
|
|
97
|
+
y = rawValue[1];
|
|
98
|
+
}
|
|
99
|
+
} else if ((typeof rawValue === "string" || typeof rawValue === "number") && axes.xLabels?.[dataIndex] !== void 0) {
|
|
100
|
+
x = axes.xLabels[dataIndex];
|
|
101
|
+
y = rawValue;
|
|
102
|
+
}
|
|
103
|
+
if (x === void 0 || y === void 0) continue;
|
|
104
|
+
const pixel = instance.convertToPixel({ seriesIndex: params.seriesIndex }, [x, y]);
|
|
105
|
+
if (!Array.isArray(pixel) || typeof pixel[0] !== "number") continue;
|
|
106
|
+
const distance = Math.abs(pixel[0] - clickX);
|
|
107
|
+
if (distance < nearestDistance) {
|
|
108
|
+
nearestDistance = distance;
|
|
109
|
+
nearest = {
|
|
110
|
+
name: typeof itemRecord?.name === "string" ? itemRecord.name : String(x),
|
|
111
|
+
value: [x, y],
|
|
112
|
+
dataIndex
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return nearest;
|
|
117
|
+
} catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Maps a raw ECharts click-event `params` object into a public
|
|
123
|
+
* {@link ChartClickDatum}.
|
|
124
|
+
*
|
|
125
|
+
* @param params - The raw ECharts click-event payload (untyped at our boundary).
|
|
126
|
+
* @param axes - Category labels used to resolve index-addressed heatmap data.
|
|
127
|
+
* @param instance - The chart instance used to resolve series-level line clicks.
|
|
128
|
+
* @returns A normalized, ECharts-free {@link ChartClickDatum}.
|
|
129
|
+
*/
|
|
130
|
+
function mapToDatum(params, axes = {}, instance) {
|
|
131
|
+
const p = params !== null && typeof params === "object" ? params : {};
|
|
132
|
+
const isScalar = (v) => typeof v === "number" || typeof v === "string";
|
|
133
|
+
const linePoint = resolveLineStrokePoint(p, axes, instance);
|
|
134
|
+
const rawValue = linePoint?.value ?? p.value;
|
|
135
|
+
const seriesType = typeof p.seriesType === "string" ? p.seriesType : void 0;
|
|
136
|
+
let x;
|
|
137
|
+
let y;
|
|
138
|
+
let value;
|
|
139
|
+
if (seriesType === "heatmap" && Array.isArray(rawValue)) {
|
|
140
|
+
const labelAt = (labels, index) => {
|
|
141
|
+
if (!isScalar(index)) return void 0;
|
|
142
|
+
if (typeof index === "number" && labels?.[index] !== void 0) return labels[index];
|
|
143
|
+
return index;
|
|
144
|
+
};
|
|
145
|
+
x = labelAt(axes.xLabels, rawValue[0]);
|
|
146
|
+
y = labelAt(axes.yLabels, rawValue[1]);
|
|
147
|
+
value = isScalar(rawValue[2]) ? rawValue[2] : null;
|
|
148
|
+
} else if (seriesType === "radar") value = null;
|
|
149
|
+
else if (Array.isArray(rawValue)) {
|
|
150
|
+
if (isScalar(rawValue[0])) x = rawValue[0];
|
|
151
|
+
if (isScalar(rawValue[1])) y = rawValue[1];
|
|
152
|
+
value = y ?? null;
|
|
153
|
+
} else value = isScalar(rawValue) ? rawValue : null;
|
|
154
|
+
const name = typeof p.name === "string" ? p.name : linePoint?.name ?? (x !== void 0 ? String(x) : "");
|
|
155
|
+
const seriesName = typeof p.seriesName === "string" ? p.seriesName : void 0;
|
|
156
|
+
const dataIndex = typeof p.dataIndex === "number" ? p.dataIndex : linePoint?.dataIndex ?? -1;
|
|
157
|
+
const seriesIndex = typeof p.seriesIndex === "number" ? p.seriesIndex : -1;
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
value,
|
|
161
|
+
x,
|
|
162
|
+
y,
|
|
163
|
+
seriesName,
|
|
164
|
+
dataIndex,
|
|
165
|
+
seriesIndex,
|
|
166
|
+
raw: params
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const DATE_STRING_PATTERN = /^\d{4}-\d{2}-\d{2}(?:$|[T\s])/;
|
|
170
|
+
/**
|
|
171
|
+
* Converts a value to a number that can be compared chronologically, or null
|
|
172
|
+
* when it is not a date. This is the single definition of "chartable date"
|
|
173
|
+
* shared by field detection, value conversion and sorting: a shape-only check
|
|
174
|
+
* would classify "2025-01-01 nonsense" as a date field and then fail to place
|
|
175
|
+
* it on a time axis.
|
|
176
|
+
*/
|
|
177
|
+
function toChronologicalValue(value) {
|
|
178
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
179
|
+
if (typeof value !== "string") return null;
|
|
180
|
+
if (!DATE_STRING_PATTERN.test(value)) return null;
|
|
181
|
+
const timestamp = Date.parse(value.replace(" ", "T"));
|
|
182
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
183
|
+
}
|
|
80
184
|
/**
|
|
81
|
-
* Sorts time-series data in ascending chronological order
|
|
185
|
+
* Sorts time-series data in ascending chronological order while preserving
|
|
186
|
+
* the correlation between each x value and its y values. Non-date category
|
|
187
|
+
* strings are intentionally left in their source order.
|
|
82
188
|
*/
|
|
83
189
|
function sortTimeSeriesAscending(xData, yDataMap, yFields) {
|
|
84
190
|
if (xData.length <= 1) return {
|
|
85
191
|
xData,
|
|
86
192
|
yDataMap
|
|
87
193
|
};
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const original = yDataMap[key];
|
|
97
|
-
sortedYDataMap[key] = indices.map((i) => original[i]);
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
xData: sortedXData,
|
|
101
|
-
yDataMap: sortedYDataMap
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
return {
|
|
194
|
+
const chronologicalValues = xData.map(toChronologicalValue);
|
|
195
|
+
if (chronologicalValues.some((value) => value === null)) return {
|
|
196
|
+
xData,
|
|
197
|
+
yDataMap
|
|
198
|
+
};
|
|
199
|
+
const indices = xData.map((_, i) => i);
|
|
200
|
+
indices.sort((a, b) => chronologicalValues[a] - chronologicalValues[b]);
|
|
201
|
+
if (indices.every((originalIndex, index) => originalIndex === index)) return {
|
|
105
202
|
xData,
|
|
106
203
|
yDataMap
|
|
107
204
|
};
|
|
205
|
+
const sortedXData = indices.map((i) => xData[i]);
|
|
206
|
+
const sortedYDataMap = { ...yDataMap };
|
|
207
|
+
for (const key of yFields) {
|
|
208
|
+
const original = yDataMap[key];
|
|
209
|
+
sortedYDataMap[key] = indices.map((i) => original[i]);
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
xData: sortedXData,
|
|
213
|
+
yDataMap: sortedYDataMap
|
|
214
|
+
};
|
|
108
215
|
}
|
|
109
216
|
|
|
110
217
|
//#endregion
|
|
111
|
-
export { createTimeSeriesData, escapeHtml,
|
|
218
|
+
export { createTimeSeriesData, escapeHtml, mapToDatum, sortNumericAscending, sortTimeSeriesAscending, toChartArray, toChartValue, toChronologicalValue, truncateLabel };
|
|
112
219
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/react/charts/utils.ts"],"sourcesContent":["// ============================================================================\n// Chart Utility Functions\n// ============================================================================\n\n/**\n * Converts a value to a chart-compatible type.\n * Handles BigInt conversion (Arrow can return BigInt64Array values).\n * Handles Date objects by converting to timestamps.\n */\nexport function toChartValue(value: unknown): string | number {\n if (value === null || value === undefined) {\n return 0;\n }\n if (typeof value === \"bigint\") {\n return Number(value);\n }\n if (value instanceof Date) {\n return value.getTime();\n }\n if (typeof value === \"string\" || typeof value === \"number\") {\n return value;\n }\n return String(value);\n}\n\n/**\n * Converts an array of values to chart-compatible types.\n */\nexport function toChartArray(data: unknown[]): (string | number)[] {\n if (data.length === 0) return [];\n return data.map(toChartValue);\n}\n\n/**\n * Formats a field name into a human-readable label.\n * Handles camelCase, snake_case, acronyms, and ALL_CAPS.\n * E.g., \"totalSpend\" -> \"Total Spend\", \"user_name\" -> \"User Name\",\n * \"userID\" -> \"User Id\", \"TOTAL_SPEND\" -> \"Total Spend\"\n */\nexport function formatLabel(field: string): string {\n return (\n field\n // Handle consecutive uppercase followed by lowercase (e.g., HTTPUrl → HTTP Url)\n .replace(/([A-Z]+)([A-Z][a-z])/g, \"$1 $2\")\n // Handle lowercase followed by uppercase (e.g., totalSpend → total Spend)\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n // Replace underscores with spaces\n .replace(/_/g, \" \")\n // Collapse multiple spaces into one\n .replace(/\\s+/g, \" \")\n // Normalize to title case\n .toLowerCase()\n .replace(/\\b\\w/g, (l) => l.toUpperCase())\n .trim()\n );\n}\n\n/**\n * Escapes HTML special characters to prevent XSS.\n * Required for ECharts function formatters: unlike string-template\n * formatters, their return values are injected as raw HTML into the\n * tooltip DOM.\n *\n * Only for HTML tooltip contexts; do NOT use on canvas-rendered\n * axis/series label formatters — canvas text is not HTML and would\n * display literal entities (e.g. \"&\").\n */\nexport function escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Truncates a label to a maximum length with ellipsis.\n */\nexport function truncateLabel(value: string, maxLength = 15): string {\n return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;\n}\n\n/**\n * Creates time-series data pairs for ECharts.\n */\nexport function createTimeSeriesData(\n xData: (string | number)[],\n yData: (string | number)[],\n): [string | number, string | number][] {\n const len = xData.length;\n const result: [string | number, string | number][] = new Array(len);\n for (let i = 0; i < len; i++) {\n result[i] = [xData[i], yData[i]];\n }\n return result;\n}\n\n/**\n * Sorts numeric x-data in ascending order, reordering y-data to match.\n * Also coerces numeric string x-values to numbers.\n */\nexport function sortNumericAscending(\n xData: (string | number)[],\n yDataMap: Record<string, (string | number)[]>,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n if (xData.length <= 1) {\n return { xData, yDataMap };\n }\n\n const indices = xData.map((_, i) => i);\n indices.sort((a, b) => Number(xData[a]) - Number(xData[b]));\n\n const sortedXData = indices.map((i) => Number(xData[i]));\n const sortedYDataMap: Record<string, (string | number)[]> = {};\n for (const key of yFields) {\n const original = yDataMap[key];\n sortedYDataMap[key] = indices.map((i) => original[i]);\n }\n\n return { xData: sortedXData, yDataMap: sortedYDataMap };\n}\n\n/**\n * Sorts time-series data in ascending chronological order.\n */\nexport function sortTimeSeriesAscending(\n xData: (string | number)[],\n yDataMap: Record<string, (string | number)[]>,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n if (xData.length <= 1) {\n return { xData, yDataMap };\n }\n\n const first = xData[0];\n const last = xData[xData.length - 1];\n\n if (typeof first === \"number\" && typeof last === \"number\" && first > last) {\n const indices = xData.map((_, i) => i);\n indices.sort((a, b) => (xData[a] as number) - (xData[b] as number));\n\n const sortedXData = indices.map((i) => xData[i]);\n const sortedYDataMap: Record<string, (string | number)[]> = {};\n for (const key of yFields) {\n const original = yDataMap[key];\n sortedYDataMap[key] = indices.map((i) => original[i]);\n }\n\n return { xData: sortedXData, yDataMap: sortedYDataMap };\n }\n\n return { xData, yDataMap };\n}\n"],"mappings":";;;;;;AASA,SAAgB,aAAa,OAAiC;AAC5D,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAET,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAEtB,KAAI,iBAAiB,KACnB,QAAO,MAAM,SAAS;AAExB,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAChD,QAAO;AAET,QAAO,OAAO,MAAM;;;;;AAMtB,SAAgB,aAAa,MAAsC;AACjE,KAAI,KAAK,WAAW,EAAG,QAAO,EAAE;AAChC,QAAO,KAAK,IAAI,aAAa;;;;;;;;AAS/B,SAAgB,YAAY,OAAuB;AACjD,QACE,MAEG,QAAQ,yBAAyB,QAAQ,CAEzC,QAAQ,mBAAmB,QAAQ,CAEnC,QAAQ,MAAM,IAAI,CAElB,QAAQ,QAAQ,IAAI,CAEpB,aAAa,CACb,QAAQ,UAAU,MAAM,EAAE,aAAa,CAAC,CACxC,MAAM;;;;;;;;;;;;AAcb,SAAgB,WAAW,OAAuB;AAChD,QAAO,MACJ,QAAQ,MAAM,QAAQ,CACtB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,SAAS,CACvB,QAAQ,MAAM,QAAQ;;;;;AAM3B,SAAgB,cAAc,OAAe,YAAY,IAAY;AACnE,QAAO,MAAM,SAAS,YAAY,GAAG,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO;;;;;AAMxE,SAAgB,qBACd,OACA,OACsC;CACtC,MAAM,MAAM,MAAM;CAClB,MAAM,SAA+C,IAAI,MAAM,IAAI;AACnE,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IACvB,QAAO,KAAK,CAAC,MAAM,IAAI,MAAM,GAAG;AAElC,QAAO;;;;;;AAOT,SAAgB,qBACd,OACA,UACA,SAIA;AACA,KAAI,MAAM,UAAU,EAClB,QAAO;EAAE;EAAO;EAAU;CAG5B,MAAM,UAAU,MAAM,KAAK,GAAG,MAAM,EAAE;AACtC,SAAQ,MAAM,GAAG,MAAM,OAAO,MAAM,GAAG,GAAG,OAAO,MAAM,GAAG,CAAC;CAE3D,MAAM,cAAc,QAAQ,KAAK,MAAM,OAAO,MAAM,GAAG,CAAC;CACxD,MAAM,iBAAsD,EAAE;AAC9D,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,WAAW,SAAS;AAC1B,iBAAe,OAAO,QAAQ,KAAK,MAAM,SAAS,GAAG;;AAGvD,QAAO;EAAE,OAAO;EAAa,UAAU;EAAgB;;;;;AAMzD,SAAgB,wBACd,OACA,UACA,SAIA;AACA,KAAI,MAAM,UAAU,EAClB,QAAO;EAAE;EAAO;EAAU;CAG5B,MAAM,QAAQ,MAAM;CACpB,MAAM,OAAO,MAAM,MAAM,SAAS;AAElC,KAAI,OAAO,UAAU,YAAY,OAAO,SAAS,YAAY,QAAQ,MAAM;EACzE,MAAM,UAAU,MAAM,KAAK,GAAG,MAAM,EAAE;AACtC,UAAQ,MAAM,GAAG,MAAO,MAAM,KAAiB,MAAM,GAAc;EAEnE,MAAM,cAAc,QAAQ,KAAK,MAAM,MAAM,GAAG;EAChD,MAAM,iBAAsD,EAAE;AAC9D,OAAK,MAAM,OAAO,SAAS;GACzB,MAAM,WAAW,SAAS;AAC1B,kBAAe,OAAO,QAAQ,KAAK,MAAM,SAAS,GAAG;;AAGvD,SAAO;GAAE,OAAO;GAAa,UAAU;GAAgB;;AAGzD,QAAO;EAAE;EAAO;EAAU"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../../src/react/charts/utils.ts"],"sourcesContent":["import type { ChartClickDatum } from \"./types\";\n\n// ============================================================================\n// Chart Utility Functions\n// ============================================================================\n\n/**\n * Converts a value to a chart-compatible type.\n * Handles BigInt conversion (Arrow can return BigInt64Array values).\n * Handles Date objects by converting to timestamps.\n */\nexport function toChartValue(value: unknown): string | number {\n if (value === null || value === undefined) {\n return 0;\n }\n if (typeof value === \"bigint\") {\n return Number(value);\n }\n if (value instanceof Date) {\n return value.getTime();\n }\n if (typeof value === \"string\" || typeof value === \"number\") {\n return value;\n }\n return String(value);\n}\n\n/**\n * Converts an array of values to chart-compatible types.\n */\nexport function toChartArray(data: unknown[]): (string | number)[] {\n if (data.length === 0) return [];\n return data.map(toChartValue);\n}\n\nexport { formatLabel } from \"@/js\";\n\n/**\n * Escapes HTML special characters to prevent XSS.\n * Required for ECharts function formatters: unlike string-template\n * formatters, their return values are injected as raw HTML into the\n * tooltip DOM.\n *\n * Only for HTML tooltip contexts; do NOT use on canvas-rendered\n * axis/series label formatters — canvas text is not HTML and would\n * display literal entities (e.g. \"&\").\n */\nexport function escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Truncates a label to a maximum length with ellipsis.\n */\nexport function truncateLabel(value: string, maxLength = 15): string {\n return value.length > maxLength ? `${value.slice(0, maxLength)}...` : value;\n}\n\n/**\n * Creates time-series data pairs for ECharts.\n */\nexport function createTimeSeriesData(\n xData: (string | number)[],\n yData: (string | number)[],\n): [string | number, string | number][] {\n const len = xData.length;\n const result: [string | number, string | number][] = new Array(len);\n for (let i = 0; i < len; i++) {\n result[i] = [xData[i], yData[i]];\n }\n return result;\n}\n\n/**\n * Sorts numeric x-data in ascending order, reordering y-data to match.\n * Also coerces numeric string x-values to numbers.\n */\nexport function sortNumericAscending(\n xData: (string | number)[],\n yDataMap: Record<string, (string | number)[]>,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n if (xData.length <= 1) {\n return { xData, yDataMap };\n }\n\n const indices = xData.map((_, i) => i);\n indices.sort((a, b) => Number(xData[a]) - Number(xData[b]));\n\n const sortedXData = indices.map((i) => Number(xData[i]));\n const sortedYDataMap: Record<string, (string | number)[]> = {};\n for (const key of yFields) {\n const original = yDataMap[key];\n sortedYDataMap[key] = indices.map((i) => original[i]);\n }\n\n return { xData: sortedXData, yDataMap: sortedYDataMap };\n}\n\n/**\n * Axis category labels for the chart being clicked, so index-addressed data\n * (heatmap) can be resolved back to the labels the user actually sees.\n */\ninterface DatumAxisContext {\n xLabels?: (string | number)[];\n yLabels?: (string | number)[];\n}\n\ninterface ChartEventInstance {\n getOption(): unknown;\n convertToPixel(\n finder: { seriesIndex: number },\n value: (string | number)[],\n ): unknown;\n}\n\ninterface ResolvedLinePoint {\n name: string;\n value: [string | number, string | number];\n dataIndex: number;\n}\n\nfunction resolveLineStrokePoint(\n params: Record<string, unknown>,\n axes: DatumAxisContext,\n instance?: ChartEventInstance,\n): ResolvedLinePoint | null {\n if (\n params.seriesType !== \"line\" ||\n params.value !== undefined ||\n !instance ||\n typeof params.seriesIndex !== \"number\"\n ) {\n return null;\n }\n\n const event =\n params.event !== null && typeof params.event === \"object\"\n ? (params.event as Record<string, unknown>)\n : null;\n const clickX = event?.offsetX;\n if (typeof clickX !== \"number\") return null;\n\n try {\n const option = instance.getOption();\n if (option === null || typeof option !== \"object\") return null;\n\n const series = (option as Record<string, unknown>).series;\n if (!Array.isArray(series)) return null;\n\n const seriesOption = series[params.seriesIndex];\n if (\n seriesOption === null ||\n typeof seriesOption !== \"object\" ||\n Array.isArray(seriesOption)\n ) {\n return null;\n }\n\n const data = (seriesOption as Record<string, unknown>).data;\n if (!Array.isArray(data)) return null;\n\n let nearest: ResolvedLinePoint | null = null;\n let nearestDistance = Number.POSITIVE_INFINITY;\n\n for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {\n const item = data[dataIndex];\n const itemRecord =\n item !== null && typeof item === \"object\" && !Array.isArray(item)\n ? (item as Record<string, unknown>)\n : null;\n const rawValue = itemRecord ? itemRecord.value : item;\n\n let x: string | number | undefined;\n let y: string | number | undefined;\n if (Array.isArray(rawValue)) {\n if (\n (typeof rawValue[0] === \"string\" ||\n typeof rawValue[0] === \"number\") &&\n (typeof rawValue[1] === \"string\" || typeof rawValue[1] === \"number\")\n ) {\n x = rawValue[0];\n y = rawValue[1];\n }\n } else if (\n (typeof rawValue === \"string\" || typeof rawValue === \"number\") &&\n axes.xLabels?.[dataIndex] !== undefined\n ) {\n x = axes.xLabels[dataIndex];\n y = rawValue;\n }\n if (x === undefined || y === undefined) continue;\n\n const pixel = instance.convertToPixel(\n { seriesIndex: params.seriesIndex },\n [x, y],\n );\n if (!Array.isArray(pixel) || typeof pixel[0] !== \"number\") continue;\n\n const distance = Math.abs(pixel[0] - clickX);\n if (distance < nearestDistance) {\n nearestDistance = distance;\n nearest = {\n name:\n typeof itemRecord?.name === \"string\" ? itemRecord.name : String(x),\n value: [x, y],\n dataIndex,\n };\n }\n }\n\n return nearest;\n } catch {\n return null;\n }\n}\n\n/**\n * Maps a raw ECharts click-event `params` object into a public\n * {@link ChartClickDatum}.\n *\n * @param params - The raw ECharts click-event payload (untyped at our boundary).\n * @param axes - Category labels used to resolve index-addressed heatmap data.\n * @param instance - The chart instance used to resolve series-level line clicks.\n * @returns A normalized, ECharts-free {@link ChartClickDatum}.\n */\nexport function mapToDatum(\n params: unknown,\n axes: DatumAxisContext = {},\n instance?: ChartEventInstance,\n): ChartClickDatum {\n const p = (\n params !== null && typeof params === \"object\" ? params : {}\n ) as Record<string, unknown>;\n\n const isScalar = (v: unknown): v is number | string =>\n typeof v === \"number\" || typeof v === \"string\";\n\n const linePoint = resolveLineStrokePoint(p, axes, instance);\n const rawValue = linePoint?.value ?? p.value;\n const seriesType =\n typeof p.seriesType === \"string\" ? p.seriesType : undefined;\n\n let x: number | string | undefined;\n let y: number | string | undefined;\n let value: number | string | null;\n\n if (seriesType === \"heatmap\" && Array.isArray(rawValue)) {\n // `[xIndex, yIndex, value]`: report the cell value\n const labelAt = (\n labels: (string | number)[] | undefined,\n index: unknown,\n ): number | string | undefined => {\n if (!isScalar(index)) return undefined;\n if (typeof index === \"number\" && labels?.[index] !== undefined) {\n return labels[index];\n }\n return index;\n };\n x = labelAt(axes.xLabels, rawValue[0]);\n y = labelAt(axes.yLabels, rawValue[1]);\n value = isScalar(rawValue[2]) ? rawValue[2] : null;\n } else if (seriesType === \"radar\") {\n // A radar item holds one value per indicator;\n value = null;\n } else if (Array.isArray(rawValue)) {\n // `[x, y]` (time-series / scatter): split values so callers don't have to re-parse `raw`.\n if (isScalar(rawValue[0])) x = rawValue[0];\n if (isScalar(rawValue[1])) y = rawValue[1];\n value = y ?? null;\n } else {\n value = isScalar(rawValue) ? rawValue : null;\n }\n\n const name =\n typeof p.name === \"string\"\n ? p.name\n : (linePoint?.name ?? (x !== undefined ? String(x) : \"\"));\n\n const seriesName =\n typeof p.seriesName === \"string\" ? p.seriesName : undefined;\n\n const dataIndex =\n typeof p.dataIndex === \"number\"\n ? p.dataIndex\n : (linePoint?.dataIndex ?? -1);\n const seriesIndex = typeof p.seriesIndex === \"number\" ? p.seriesIndex : -1;\n\n return {\n name,\n value,\n x,\n y,\n seriesName,\n dataIndex,\n seriesIndex,\n raw: params,\n };\n}\n\nconst DATE_STRING_PATTERN = /^\\d{4}-\\d{2}-\\d{2}(?:$|[T\\s])/;\n\n/**\n * Converts a value to a number that can be compared chronologically, or null\n * when it is not a date. This is the single definition of \"chartable date\"\n * shared by field detection, value conversion and sorting: a shape-only check\n * would classify \"2025-01-01 nonsense\" as a date field and then fail to place\n * it on a time axis.\n */\nexport function toChronologicalValue(value: unknown): number | null {\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : null;\n }\n\n if (typeof value !== \"string\") return null;\n if (!DATE_STRING_PATTERN.test(value)) return null;\n\n // Spark JSON_ARRAY timestamps commonly use a space between the date and\n // time. Normalize that separator to the ISO form before parsing.\n const timestamp = Date.parse(value.replace(\" \", \"T\"));\n return Number.isFinite(timestamp) ? timestamp : null;\n}\n\n/**\n * Sorts time-series data in ascending chronological order while preserving\n * the correlation between each x value and its y values. Non-date category\n * strings are intentionally left in their source order.\n */\nexport function sortTimeSeriesAscending(\n xData: (string | number)[],\n yDataMap: Record<string, (string | number)[]>,\n yFields: string[],\n): {\n xData: (string | number)[];\n yDataMap: Record<string, (string | number)[]>;\n} {\n if (xData.length <= 1) {\n return { xData, yDataMap };\n }\n\n const chronologicalValues = xData.map(toChronologicalValue);\n if (chronologicalValues.some((value) => value === null)) {\n return { xData, yDataMap };\n }\n\n const indices = xData.map((_, i) => i);\n indices.sort(\n (a, b) =>\n (chronologicalValues[a] as number) - (chronologicalValues[b] as number),\n );\n\n if (indices.every((originalIndex, index) => originalIndex === index)) {\n return { xData, yDataMap };\n }\n\n const sortedXData = indices.map((i) => xData[i]);\n const sortedYDataMap: Record<string, (string | number)[]> = {\n ...yDataMap,\n };\n for (const key of yFields) {\n const original = yDataMap[key];\n sortedYDataMap[key] = indices.map((i) => original[i]);\n }\n\n return { xData: sortedXData, yDataMap: sortedYDataMap };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
//#region src/react/hooks/analytics-sse.ts
|
|
2
|
+
const GENERIC_LOAD_ERROR = "Unable to load data, please try again";
|
|
3
|
+
function getDevMode() {
|
|
4
|
+
const dev = new URL(window.location.href).searchParams.get("dev");
|
|
5
|
+
return dev ? `?dev=${dev}` : "";
|
|
6
|
+
}
|
|
7
|
+
/** Map a fetch/SSE transport error to a user-facing message. */
|
|
8
|
+
function userFacingFetchError(error) {
|
|
9
|
+
if (error instanceof Error) {
|
|
10
|
+
if (error.name === "AbortError") return "Request timed out, please try again";
|
|
11
|
+
if (error.message.includes("Failed to fetch")) return "Network error. Please check your connection.";
|
|
12
|
+
}
|
|
13
|
+
return GENERIC_LOAD_ERROR;
|
|
14
|
+
}
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
function isWarehouseStatusPayload(value) {
|
|
19
|
+
return typeof value === "object" && value !== null && typeof value.state === "string";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse and classify the deliberately loose analytics SSE wire format.
|
|
23
|
+
* Result rows normalize to an empty array so hook state remains `T | null`.
|
|
24
|
+
*/
|
|
25
|
+
function parseAnalyticsSseMessage(data, defaultExecutionError) {
|
|
26
|
+
const parsed = JSON.parse(data);
|
|
27
|
+
if (!isRecord(parsed)) return {
|
|
28
|
+
kind: "invalid",
|
|
29
|
+
reason: "unrecognized",
|
|
30
|
+
payload: parsed
|
|
31
|
+
};
|
|
32
|
+
if (parsed.type === "warehouse_status") {
|
|
33
|
+
if (!isWarehouseStatusPayload(parsed.status)) return {
|
|
34
|
+
kind: "invalid",
|
|
35
|
+
reason: "malformed-warehouse-status",
|
|
36
|
+
payload: parsed
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
kind: "warehouse-status",
|
|
40
|
+
status: parsed.status
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (parsed.type === "result") return {
|
|
44
|
+
kind: "result",
|
|
45
|
+
data: Array.isArray(parsed.data) ? parsed.data : [],
|
|
46
|
+
payload: parsed
|
|
47
|
+
};
|
|
48
|
+
if (parsed.type === "error" || parsed.error || parsed.code) return {
|
|
49
|
+
kind: "error",
|
|
50
|
+
message: typeof parsed.error === "string" && parsed.error || typeof parsed.message === "string" && parsed.message || defaultExecutionError,
|
|
51
|
+
errorCode: typeof parsed.errorCode === "string" ? parsed.errorCode : null,
|
|
52
|
+
code: parsed.code
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
kind: "invalid",
|
|
56
|
+
reason: "unrecognized",
|
|
57
|
+
payload: parsed
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function failWithGenericError(ctx) {
|
|
61
|
+
ctx.setLoading(false);
|
|
62
|
+
ctx.setError(GENERIC_LOAD_ERROR);
|
|
63
|
+
ctx.unpublishWarehouseStatus();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Apply the state transitions shared by analytics-query and metric-view SSE
|
|
67
|
+
* messages while delegating their distinct result/status state to callbacks.
|
|
68
|
+
*/
|
|
69
|
+
async function handleAnalyticsSseMessage(data, ctx) {
|
|
70
|
+
if (ctx.signal.aborted) return;
|
|
71
|
+
try {
|
|
72
|
+
const message = parseAnalyticsSseMessage(data, ctx.defaultExecutionError);
|
|
73
|
+
if (message.kind === "warehouse-status") {
|
|
74
|
+
ctx.onWarehouseStatus(message.status);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (message.kind === "result") {
|
|
78
|
+
ctx.setLoading(false);
|
|
79
|
+
ctx.onResult(message);
|
|
80
|
+
ctx.unpublishWarehouseStatus();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (message.kind === "error") {
|
|
84
|
+
ctx.setLoading(false);
|
|
85
|
+
ctx.setError(message.message);
|
|
86
|
+
ctx.unpublishWarehouseStatus();
|
|
87
|
+
if (message.errorCode !== null) ctx.setErrorCode(message.errorCode);
|
|
88
|
+
if (message.code) console.error(`[${ctx.source}] Code: ${String(message.code)}, Message: ${message.message}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (message.reason === "malformed-warehouse-status") console.error(`[${ctx.source}] Malformed warehouse_status event`, message.payload);
|
|
92
|
+
else console.error(`[${ctx.source}] Unrecognized SSE payload`, message.payload);
|
|
93
|
+
failWithGenericError(ctx);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.warn(`[${ctx.source}] Malformed message received`, error);
|
|
96
|
+
ctx.setLoading(false);
|
|
97
|
+
ctx.setError(GENERIC_LOAD_ERROR);
|
|
98
|
+
if (ctx.unpublishOnMalformedMessage) ctx.unpublishWarehouseStatus();
|
|
99
|
+
ctx.abort();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Apply the shared terminal state for an SSE connection failure. */
|
|
103
|
+
function handleAnalyticsSseError(error, ctx) {
|
|
104
|
+
if (ctx.signal.aborted) return;
|
|
105
|
+
ctx.setLoading(false);
|
|
106
|
+
ctx.unpublishWarehouseStatus();
|
|
107
|
+
if (error instanceof Error) console.error(`[${ctx.source}] Error`, {
|
|
108
|
+
...ctx.resource,
|
|
109
|
+
error: error.message,
|
|
110
|
+
stack: error.stack
|
|
111
|
+
});
|
|
112
|
+
ctx.setError(userFacingFetchError(error));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
export { GENERIC_LOAD_ERROR, getDevMode, handleAnalyticsSseError, handleAnalyticsSseMessage, userFacingFetchError };
|
|
117
|
+
//# sourceMappingURL=analytics-sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics-sse.js","names":[],"sources":["../../../src/react/hooks/analytics-sse.ts"],"sourcesContent":["import type { WarehouseStatus } from \"./types\";\n\nexport const GENERIC_LOAD_ERROR = \"Unable to load data, please try again\";\n\nexport function getDevMode(): string {\n const dev = new URL(window.location.href).searchParams.get(\"dev\");\n return dev ? `?dev=${dev}` : \"\";\n}\n\n/** Map a fetch/SSE transport error to a user-facing message. */\nexport function userFacingFetchError(error: unknown): string {\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n return \"Request timed out, please try again\";\n }\n if (error.message.includes(\"Failed to fetch\")) {\n return \"Network error. Please check your connection.\";\n }\n }\n return GENERIC_LOAD_ERROR;\n}\n\ninterface WarehouseStatusMessage {\n kind: \"warehouse-status\";\n status: WarehouseStatus;\n}\n\nexport interface AnalyticsSseResultMessage {\n kind: \"result\";\n data: unknown[];\n payload: Record<string, unknown>;\n}\n\ninterface AnalyticsSseErrorMessage {\n kind: \"error\";\n message: string;\n errorCode: string | null;\n code: unknown;\n}\n\ninterface InvalidAnalyticsSseMessage {\n kind: \"invalid\";\n reason: \"malformed-warehouse-status\" | \"unrecognized\";\n payload: unknown;\n}\n\ntype AnalyticsSseMessage =\n | WarehouseStatusMessage\n | AnalyticsSseResultMessage\n | AnalyticsSseErrorMessage\n | InvalidAnalyticsSseMessage;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isWarehouseStatusPayload(value: unknown): value is WarehouseStatus {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as WarehouseStatus).state === \"string\"\n );\n}\n\n/**\n * Parse and classify the deliberately loose analytics SSE wire format.\n * Result rows normalize to an empty array so hook state remains `T | null`.\n */\nexport function parseAnalyticsSseMessage(\n data: string,\n defaultExecutionError: string,\n): AnalyticsSseMessage {\n const parsed: unknown = JSON.parse(data);\n\n if (!isRecord(parsed)) {\n return { kind: \"invalid\", reason: \"unrecognized\", payload: parsed };\n }\n\n if (parsed.type === \"warehouse_status\") {\n if (!isWarehouseStatusPayload(parsed.status)) {\n return {\n kind: \"invalid\",\n reason: \"malformed-warehouse-status\",\n payload: parsed,\n };\n }\n return { kind: \"warehouse-status\", status: parsed.status };\n }\n\n if (parsed.type === \"result\") {\n return {\n kind: \"result\",\n data: Array.isArray(parsed.data) ? parsed.data : [],\n payload: parsed,\n };\n }\n\n if (parsed.type === \"error\" || parsed.error || parsed.code) {\n const message =\n (typeof parsed.error === \"string\" && parsed.error) ||\n (typeof parsed.message === \"string\" && parsed.message) ||\n defaultExecutionError;\n return {\n kind: \"error\",\n message,\n errorCode: typeof parsed.errorCode === \"string\" ? parsed.errorCode : null,\n code: parsed.code,\n };\n }\n\n return { kind: \"invalid\", reason: \"unrecognized\", payload: parsed };\n}\n\nexport interface AnalyticsSseHandlerContext {\n source: \"useAnalyticsQuery\" | \"useMetricView\";\n resource: Record<string, unknown>;\n defaultExecutionError: string;\n unpublishOnMalformedMessage: boolean;\n signal: AbortSignal;\n abort: () => void;\n setLoading: (loading: boolean) => void;\n setError: (error: string | null) => void;\n setErrorCode: (code: string | null) => void;\n onWarehouseStatus: (status: WarehouseStatus) => void;\n onResult: (message: AnalyticsSseResultMessage) => void;\n unpublishWarehouseStatus: () => void;\n}\n\nfunction failWithGenericError(ctx: AnalyticsSseHandlerContext): void {\n ctx.setLoading(false);\n ctx.setError(GENERIC_LOAD_ERROR);\n ctx.unpublishWarehouseStatus();\n}\n\n/**\n * Apply the state transitions shared by analytics-query and metric-view SSE\n * messages while delegating their distinct result/status state to callbacks.\n */\nexport async function handleAnalyticsSseMessage(\n data: string,\n ctx: AnalyticsSseHandlerContext,\n): Promise<void> {\n if (ctx.signal.aborted) return;\n\n try {\n const message = parseAnalyticsSseMessage(data, ctx.defaultExecutionError);\n\n if (message.kind === \"warehouse-status\") {\n ctx.onWarehouseStatus(message.status);\n return;\n }\n\n if (message.kind === \"result\") {\n ctx.setLoading(false);\n ctx.onResult(message);\n ctx.unpublishWarehouseStatus();\n return;\n }\n\n if (message.kind === \"error\") {\n ctx.setLoading(false);\n ctx.setError(message.message);\n ctx.unpublishWarehouseStatus();\n if (message.errorCode !== null) {\n ctx.setErrorCode(message.errorCode);\n }\n if (message.code) {\n console.error(\n `[${ctx.source}] Code: ${String(message.code)}, Message: ${message.message}`,\n );\n }\n return;\n }\n\n if (message.reason === \"malformed-warehouse-status\") {\n console.error(\n `[${ctx.source}] Malformed warehouse_status event`,\n message.payload,\n );\n } else {\n console.error(\n `[${ctx.source}] Unrecognized SSE payload`,\n message.payload,\n );\n }\n failWithGenericError(ctx);\n } catch (error) {\n console.warn(`[${ctx.source}] Malformed message received`, error);\n ctx.setLoading(false);\n ctx.setError(GENERIC_LOAD_ERROR);\n if (ctx.unpublishOnMalformedMessage) {\n ctx.unpublishWarehouseStatus();\n }\n ctx.abort();\n }\n}\n\n/** Apply the shared terminal state for an SSE connection failure. */\nexport function handleAnalyticsSseError(\n error: unknown,\n ctx: AnalyticsSseHandlerContext,\n): void {\n if (ctx.signal.aborted) return;\n\n ctx.setLoading(false);\n ctx.unpublishWarehouseStatus();\n\n if (error instanceof Error) {\n console.error(`[${ctx.source}] Error`, {\n ...ctx.resource,\n error: error.message,\n stack: error.stack,\n });\n }\n ctx.setError(userFacingFetchError(error));\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MetricFilter, MetricFilterOperatorName, MetricOrderBy, MetricOrderDirection, MetricPredicate } from "../../shared/src/metric-filter.js";
|
|
2
|
+
import { MetricViewColumnDisplay } from "../../shared/src/metric-metadata.js";
|
|
3
|
+
import { AnalyticsFormat, GrainsForSelectedTimeDims, InferDimensionKeys, InferMeasureKeys, InferMetricRow, InferResultByFormat, InferRowType, InferServingChunk, InferServingRequest, InferServingResponse, InferTimeDimensionKeys, InferTimeGrains, MetricKey, MetricRegistry, PickMetricRow, PluginRegistry, QueryRegistry, ServingAlias, ServingEndpointRegistry, TypedArrowTable, UseAnalyticsQueryOptions, UseAnalyticsQueryResult, UseMetricViewOptions, UseMetricViewResult, WarehouseState, WarehouseStatus } from "./types.js";
|
|
2
4
|
import { UseChartDataOptions, UseChartDataResult, useChartData } from "./use-chart-data.js";
|
|
3
5
|
import { AggregatedResourceStatus, ResourceSeverity, ResourceStatus, ResourceStatusFilter, ResourceStatusProvider, ResourceStatusProviderProps, useResourceStatus, useResourceStatusPublisher } from "./use-resource-status.js";
|
|
4
6
|
import { ResourceKindRenderer, ResourceStatusIndicator, ResourceStatusIndicatorProps, ResourceStatusToasterOptions, useResourceStatusToaster } from "../resource-status-indicator.js";
|
|
5
7
|
import { AgentChatEvent, UseAgentChatOptions, UseAgentChatResult, useAgentChat } from "./use-agent-chat.js";
|
|
6
8
|
import { useAnalyticsQuery } from "./use-analytics-query.js";
|
|
9
|
+
import { useMetricView } from "./use-metric-view.js";
|
|
7
10
|
import { useIsMobile } from "./use-mobile.js";
|
|
8
11
|
import { usePluginClientConfig } from "./use-plugin-config.js";
|
|
9
12
|
import { UseServingInvokeOptions, UseServingInvokeResult, useServingInvoke } from "./use-serving-invoke.js";
|