@oneuptime/common 11.5.1 → 11.5.2

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.
Files changed (57) hide show
  1. package/Server/Infrastructure/Postgres/SchemaMigrations/1783937343400-MigrationName.ts +386 -0
  2. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +3 -1
  3. package/Server/Services/AnalyticsDatabaseService.ts +59 -7
  4. package/Server/Services/MetricService.ts +124 -28
  5. package/Server/Services/SpanService.ts +11 -0
  6. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +39 -0
  7. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +8 -5
  8. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +84 -0
  9. package/Tests/Server/Services/MetricServiceAggregate.test.ts +167 -0
  10. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +40 -0
  11. package/Types/BaseDatabase/AggregateBy.ts +11 -1
  12. package/Types/BaseDatabase/AggregationInterval.ts +10 -0
  13. package/Types/BaseDatabase/AggregationIntervalUtil.ts +23 -0
  14. package/Types/Metrics/MetricFormulaConfigData.ts +5 -0
  15. package/Types/Metrics/MetricQueryConfigData.ts +19 -0
  16. package/UI/Components/Charts/Area/AreaChart.tsx +15 -2
  17. package/UI/Components/Charts/Bar/BarChart.tsx +16 -2
  18. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +31 -32
  19. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +41 -17
  20. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +38 -34
  21. package/UI/Components/Charts/ChartLibrary/SparkChart/SparkChart.tsx +4 -3
  22. package/UI/Components/Charts/ChartLibrary/Utils/ChartColors.ts +48 -10
  23. package/UI/Components/Charts/Line/LineChart.tsx +15 -2
  24. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783937343400-MigrationName.js +384 -0
  25. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783937343400-MigrationName.js.map +1 -0
  26. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +3 -1
  27. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  28. package/build/dist/Server/Services/AnalyticsDatabaseService.js +43 -5
  29. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  30. package/build/dist/Server/Services/MetricService.js +110 -23
  31. package/build/dist/Server/Services/MetricService.js.map +1 -1
  32. package/build/dist/Server/Services/SpanService.js +10 -0
  33. package/build/dist/Server/Services/SpanService.js.map +1 -1
  34. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +32 -0
  35. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  36. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +2 -1
  37. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  38. package/build/dist/Types/BaseDatabase/AggregationInterval.js +10 -0
  39. package/build/dist/Types/BaseDatabase/AggregationInterval.js.map +1 -1
  40. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +13 -0
  41. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
  42. package/build/dist/UI/Components/Charts/Area/AreaChart.js +3 -1
  43. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  44. package/build/dist/UI/Components/Charts/Bar/BarChart.js +3 -1
  45. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  46. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +13 -9
  47. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  48. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +19 -7
  49. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  50. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +21 -9
  51. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  52. package/build/dist/UI/Components/Charts/ChartLibrary/SparkChart/SparkChart.js.map +1 -1
  53. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/ChartColors.js +26 -0
  54. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/ChartColors.js.map +1 -1
  55. package/build/dist/UI/Components/Charts/Line/LineChart.js +3 -1
  56. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  57. package/package.json +1 -1
@@ -27,9 +27,11 @@ import { AxisDomain } from "recharts/types/util/types";
27
27
  import { useOnWindowResize } from "../Utils/UseWindowOnResize";
28
28
  import {
29
29
  AvailableChartColors,
30
- AvailableChartColorsKeys,
30
+ ChartColorValue,
31
31
  constructCategoryColors,
32
32
  getColorClassName,
33
+ getColorHex,
34
+ isHexColorValue,
33
35
  } from "../Utils/ChartColors";
34
36
  import { cx } from "../Utils/Cx";
35
37
  import { getYAxisDomain } from "../Utils/GetYAxisDomain";
@@ -40,8 +42,8 @@ import ChartCurve from "../../Types/ChartCurve";
40
42
 
41
43
  interface LegendItemProps {
42
44
  name: string;
43
- color: AvailableChartColorsKeys;
44
- onClick?: (name: string, color: AvailableChartColorsKeys) => void;
45
+ color: ChartColorValue;
46
+ onClick?: (name: string, color: ChartColorValue) => void;
45
47
  activeLegend?: string;
46
48
  }
47
49
 
@@ -77,6 +79,11 @@ const LegendItem: ({
77
79
  getColorClassName(color, "bg"),
78
80
  activeLegend && activeLegend !== name ? "opacity-40" : "opacity-100",
79
81
  )}
82
+ style={
83
+ isHexColorValue(color)
84
+ ? { backgroundColor: getColorHex(color) }
85
+ : undefined
86
+ }
80
87
  aria-hidden={true}
81
88
  />
82
89
  <p
@@ -166,7 +173,7 @@ const ScrollButton: ({
166
173
 
167
174
  interface LegendProps extends React.OlHTMLAttributes<HTMLOListElement> {
168
175
  categories: string[];
169
- colors?: AvailableChartColorsKeys[];
176
+ colors?: ChartColorValue[];
170
177
  onClickLegendItem?: (category: string, color: string) => void;
171
178
  activeLegend?: string;
172
179
  enableLegendSlider?: boolean;
@@ -310,7 +317,7 @@ const Legend: React.ForwardRefExoticComponent<
310
317
  <LegendItem
311
318
  key={`item-${index}`}
312
319
  name={category}
313
- color={colors[index] as AvailableChartColorsKeys}
320
+ color={colors[index] as ChartColorValue}
314
321
  onClick={onClickLegendItem as any}
315
322
  activeLegend={activeLegend!}
316
323
  />
@@ -356,7 +363,7 @@ Legend.displayName = "Legend";
356
363
 
357
364
  const ChartLegend: (
358
365
  { payload }: any,
359
- categoryColors: Map<string, AvailableChartColorsKeys>,
366
+ categoryColors: Map<string, ChartColorValue>,
360
367
  setLegendHeight: React.Dispatch<React.SetStateAction<number>>,
361
368
  activeLegend: string | undefined,
362
369
  onClick?: (category: string, color: string) => void,
@@ -365,7 +372,7 @@ const ChartLegend: (
365
372
  yAxisWidth?: number,
366
373
  ) => React.JSX.Element = (
367
374
  { payload }: any,
368
- categoryColors: Map<string, AvailableChartColorsKeys>,
375
+ categoryColors: Map<string, ChartColorValue>,
369
376
  setLegendHeight: React.Dispatch<React.SetStateAction<number>>,
370
377
  activeLegend: string | undefined,
371
378
  onClick?: (category: string, color: string) => void,
@@ -432,7 +439,7 @@ export type PayloadItem = {
432
439
  // eslint-disable-next-line react/no-unused-prop-types
433
440
  index: string;
434
441
  // eslint-disable-next-line react/no-unused-prop-types
435
- color: AvailableChartColorsKeys;
442
+ color: ChartColorValue;
436
443
  // eslint-disable-next-line react/no-unused-prop-types
437
444
  type?: string;
438
445
  // eslint-disable-next-line react/no-unused-prop-types
@@ -499,6 +506,11 @@ const ChartTooltip: ({
499
506
  "h-[3px] w-3.5 shrink-0 rounded-full",
500
507
  getColorClassName(color, "bg"),
501
508
  )}
509
+ style={
510
+ isHexColorValue(color)
511
+ ? { backgroundColor: getColorHex(color) }
512
+ : undefined
513
+ }
502
514
  />
503
515
  <p
504
516
  className={cx(
@@ -551,7 +563,7 @@ interface LineChartProps extends React.HTMLAttributes<HTMLDivElement> {
551
563
  data: Record<string, any>[];
552
564
  index: string;
553
565
  categories: string[];
554
- colors?: AvailableChartColorsKeys[];
566
+ colors?: ChartColorValue[];
555
567
  valueFormatter?: (value: number) => string;
556
568
  startEndOnly?: boolean;
557
569
  showXAxis?: boolean;
@@ -628,7 +640,7 @@ const LineChart: React.ForwardRefExoticComponent<
628
640
  const [activeLegend, setActiveLegend] = React.useState<string | undefined>(
629
641
  undefined,
630
642
  );
631
- const categoryColors: Map<string, string | number> =
643
+ const categoryColors: Map<string, ChartColorValue> =
632
644
  constructCategoryColors(categories, colors);
633
645
 
634
646
  const yAxisDomain: (number | "auto")[] = getYAxisDomain(
@@ -828,7 +840,7 @@ const LineChart: React.ForwardRefExoticComponent<
828
840
  index: item.payload[index],
829
841
  color: categoryColors.get(
830
842
  item.dataKey,
831
- ) as AvailableChartColorsKeys,
843
+ ) as ChartColorValue,
832
844
  type: item.type,
833
845
  payload: item.payload,
834
846
  };
@@ -887,14 +899,14 @@ const LineChart: React.ForwardRefExoticComponent<
887
899
  />
888
900
  ) : null}
889
901
  {categories.map((category: string) => {
902
+ const lineColor: ChartColorValue = categoryColors.get(
903
+ category,
904
+ ) as ChartColorValue;
905
+ const isCustomColor: boolean = isHexColorValue(lineColor);
906
+ const lineHex: string = getColorHex(lineColor);
890
907
  return (
891
908
  <Line
892
- className={cx(
893
- getColorClassName(
894
- categoryColors.get(category) as AvailableChartColorsKeys,
895
- "stroke",
896
- ),
897
- )}
909
+ className={cx(getColorClassName(lineColor, "stroke"))}
898
910
  strokeOpacity={
899
911
  activeDot || (activeLegend && activeLegend !== category)
900
912
  ? 0.3
@@ -908,24 +920,18 @@ const LineChart: React.ForwardRefExoticComponent<
908
920
  strokeLinecap,
909
921
  strokeLinejoin,
910
922
  strokeWidth,
911
- dataKey,
912
923
  } = props;
913
924
  return (
914
925
  <Dot
915
926
  className={cx(
916
927
  "stroke-white",
917
928
  onValueChange ? "cursor-pointer" : "",
918
- getColorClassName(
919
- categoryColors.get(
920
- dataKey,
921
- ) as AvailableChartColorsKeys,
922
- "fill",
923
- ),
929
+ getColorClassName(lineColor, "fill"),
924
930
  )}
925
931
  cx={cxCoord}
926
932
  cy={cyCoord}
927
933
  r={5}
928
- fill=""
934
+ fill={isCustomColor ? lineHex : ""}
929
935
  stroke={stroke}
930
936
  strokeLinecap={strokeLinecap}
931
937
  strokeLinejoin={strokeLinejoin}
@@ -944,7 +950,6 @@ const LineChart: React.ForwardRefExoticComponent<
944
950
  strokeWidth,
945
951
  cx: cxCoord,
946
952
  cy: cyCoord,
947
- dataKey,
948
953
  index,
949
954
  } = props;
950
955
 
@@ -964,19 +969,14 @@ const LineChart: React.ForwardRefExoticComponent<
964
969
  cy={cyCoord}
965
970
  r={5}
966
971
  stroke={stroke}
967
- fill=""
972
+ fill={isCustomColor ? lineHex : ""}
968
973
  strokeLinecap={strokeLinecap}
969
974
  strokeLinejoin={strokeLinejoin}
970
975
  strokeWidth={strokeWidth}
971
976
  className={cx(
972
977
  "stroke-white",
973
978
  onValueChange ? "cursor-pointer" : "",
974
- getColorClassName(
975
- categoryColors.get(
976
- dataKey,
977
- ) as AvailableChartColorsKeys,
978
- "fill",
979
- ),
979
+ getColorClassName(lineColor, "fill"),
980
980
  )}
981
981
  />
982
982
  );
@@ -987,7 +987,11 @@ const LineChart: React.ForwardRefExoticComponent<
987
987
  name={category}
988
988
  type={props.curve || ChartCurve.LINEAR}
989
989
  dataKey={category}
990
- stroke=""
990
+ /*
991
+ * Custom hex → set the stroke inline; named palette → keep ""
992
+ * so the `stroke-*` Tailwind class on the Line applies.
993
+ */
994
+ stroke={isCustomColor ? lineHex : ""}
991
995
  strokeWidth={2}
992
996
  strokeLinejoin="round"
993
997
  strokeLinecap="round"
@@ -21,6 +21,7 @@ import type { AxisDomain } from "recharts/types/util/types";
21
21
  import {
22
22
  AvailableChartColors,
23
23
  type AvailableChartColorsKeys,
24
+ type ChartColorValue,
24
25
  constructCategoryColors,
25
26
  getColorClassName,
26
27
  } from "../Utils/ChartColors";
@@ -64,7 +65,7 @@ const SparkAreaChart: React.ForwardRefExoticComponent<
64
65
  ...other
65
66
  } = props;
66
67
 
67
- const categoryColors: Map<string, AvailableChartColorsKeys> =
68
+ const categoryColors: Map<string, ChartColorValue> =
68
69
  constructCategoryColors(categories, colors);
69
70
  const yAxisDomain: AxisDomain = getYAxisDomain(
70
71
  autoMinValue,
@@ -209,7 +210,7 @@ const SparkLineChart: React.ForwardRefExoticComponent<
209
210
  ...other
210
211
  } = props;
211
212
 
212
- const categoryColors: Map<string, AvailableChartColorsKeys> =
213
+ const categoryColors: Map<string, ChartColorValue> =
213
214
  constructCategoryColors(categories, colors);
214
215
  const yAxisDomain: AxisDomain = getYAxisDomain(
215
216
  autoMinValue,
@@ -304,7 +305,7 @@ const SparkBarChart: React.ForwardRefExoticComponent<
304
305
  ...other
305
306
  } = props;
306
307
 
307
- const categoryColors: Map<string, AvailableChartColorsKeys> =
308
+ const categoryColors: Map<string, ChartColorValue> =
308
309
  constructCategoryColors(categories, colors);
309
310
 
310
311
  const yAxisDomain: AxisDomain = getYAxisDomain(
@@ -92,16 +92,38 @@ export const AvailableChartColors: AvailableChartColorsKeys[] = Object.keys(
92
92
  chartColors,
93
93
  ) as Array<AvailableChartColorsKeys>;
94
94
 
95
+ /*
96
+ * A chart color value can be either a named palette key (e.g. "indigo") or
97
+ * a raw hex string (e.g. "#6366f1"). Named keys resolve to Tailwind classes;
98
+ * hex values are applied via inline styles by the chart renderers. This lets
99
+ * users pick arbitrary custom/brand colors per series while the default
100
+ * palette continues to use theme-safe named colors.
101
+ */
102
+ export type ChartColorValue = AvailableChartColorsKeys | string;
103
+
104
+ /*
105
+ * True when the value is a raw hex color rather than a named palette key.
106
+ * The chart renderers use this to decide between an inline style (hex) and
107
+ * a Tailwind color class (named key). Accepts ChartColorValue (which widens
108
+ * to `string | number` because `chartColors` has a string index signature) —
109
+ * only actual `#…` strings return true.
110
+ */
111
+ export const isHexColorValue: (
112
+ color: ChartColorValue | undefined | null,
113
+ ) => boolean = (color: ChartColorValue | undefined | null): boolean => {
114
+ return typeof color === "string" && color.trim().startsWith("#");
115
+ };
116
+
95
117
  export const constructCategoryColors: (
96
118
  categories: string[],
97
- colors: AvailableChartColorsKeys[],
98
- ) => Map<string, AvailableChartColorsKeys> = (
119
+ colors: Array<ChartColorValue>,
120
+ ) => Map<string, ChartColorValue> = (
99
121
  categories: string[],
100
- colors: AvailableChartColorsKeys[],
101
- ): Map<string, AvailableChartColorsKeys> => {
102
- const categoryColors: Map<string, AvailableChartColorsKeys> = new Map<
122
+ colors: Array<ChartColorValue>,
123
+ ): Map<string, ChartColorValue> => {
124
+ const categoryColors: Map<string, ChartColorValue> = new Map<
103
125
  string,
104
- AvailableChartColorsKeys
126
+ ChartColorValue
105
127
  >();
106
128
  categories.forEach((category: string, index: number) => {
107
129
  categoryColors.set(category, colors[index % colors.length]!);
@@ -110,9 +132,9 @@ export const constructCategoryColors: (
110
132
  };
111
133
 
112
134
  export const getColorClassName: (
113
- color: AvailableChartColorsKeys,
135
+ color: ChartColorValue,
114
136
  type: ColorUtility,
115
- ) => string = (color: AvailableChartColorsKeys, type: ColorUtility): string => {
137
+ ) => string = (color: ChartColorValue, type: ColorUtility): string => {
116
138
  const fallbackColor: {
117
139
  bg: string;
118
140
  stroke: string;
@@ -124,11 +146,27 @@ export const getColorClassName: (
124
146
  fill: "fill-gray-500",
125
147
  text: "text-gray-500",
126
148
  };
149
+ /*
150
+ * Hex values have no Tailwind class — callers apply them via inline style,
151
+ * so return an empty string here rather than the gray fallback (which would
152
+ * otherwise paint a custom-colored series gray).
153
+ */
154
+ if (isHexColorValue(color)) {
155
+ return "";
156
+ }
127
157
  return chartColors[color]?.[type] ?? fallbackColor[type];
128
158
  };
129
159
 
130
- export const getColorHex: (color: AvailableChartColorsKeys) => string = (
131
- color: AvailableChartColorsKeys,
160
+ /*
161
+ * Resolve any chart color value to a concrete hex string. Named palette keys
162
+ * map to their `chartColors` hex; raw hex values pass through unchanged. Used
163
+ * for SVG fill/stroke and inline style props where a class name won't work.
164
+ */
165
+ export const getColorHex: (color: ChartColorValue) => string = (
166
+ color: ChartColorValue,
132
167
  ): string => {
168
+ if (isHexColorValue(color)) {
169
+ return color as string;
170
+ }
133
171
  return chartColors[color]?.hex ?? "#6b7280";
134
172
  };
@@ -1,5 +1,8 @@
1
1
  import { LineChart } from "../ChartLibrary/LineChart/LineChart";
2
- import { AvailableChartColorsKeys } from "../ChartLibrary/Utils/ChartColors";
2
+ import {
3
+ AvailableChartColorsKeys,
4
+ ChartColorValue,
5
+ } from "../ChartLibrary/Utils/ChartColors";
3
6
  import React, {
4
7
  FunctionComponent,
5
8
  ReactElement,
@@ -41,6 +44,12 @@ export interface ComponentProps {
41
44
  exemplarPoints?: Array<ExemplarPoint> | undefined;
42
45
  onExemplarClick?: ((exemplar: ExemplarPoint) => void) | undefined;
43
46
  showLegend?: boolean | undefined;
47
+ /*
48
+ * Optional per-series color override (named palette keys or hex strings).
49
+ * When provided, replaces the default LineChartPalette. Indexed by series
50
+ * position (index % length).
51
+ */
52
+ colors?: Array<ChartColorValue> | undefined;
44
53
  }
45
54
 
46
55
  export interface LineInternalProps extends ComponentProps {
@@ -118,7 +127,11 @@ const LineChartElement: FunctionComponent<LineInternalProps> = (
118
127
  tickGap={30}
119
128
  index={"Time"}
120
129
  categories={categories}
121
- colors={LineChartPalette}
130
+ colors={
131
+ props.colors && props.colors.length > 0
132
+ ? props.colors
133
+ : LineChartPalette
134
+ }
122
135
  valueFormatter={props.yAxis.options.formatter || undefined}
123
136
  showTooltip={true}
124
137
  showLegend={props.showLegend !== false}