@oneuptime/common 10.0.81 → 10.0.84

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 (41) hide show
  1. package/Models/AnalyticsModels/Metric.ts +296 -2
  2. package/Server/Services/MetricService.ts +228 -3
  3. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +43 -3
  4. package/Types/AnalyticsDatabase/TableColumnType.ts +1 -0
  5. package/Types/BaseDatabase/AggregationType.ts +35 -0
  6. package/UI/Components/Banner/Banner.tsx +7 -2
  7. package/UI/Components/Breadcrumbs/Breadcrumbs.tsx +6 -2
  8. package/UI/Components/EventItem/EventItem.tsx +9 -5
  9. package/UI/Components/Label/Labels.tsx +10 -2
  10. package/UI/Components/Modal/ConfirmModal.tsx +5 -1
  11. package/UI/Components/Modal/Modal.tsx +21 -5
  12. package/UI/Components/ModelTable/BaseModelTable.tsx +7 -1
  13. package/UI/Components/Page/Page.tsx +6 -2
  14. package/UI/esbuild-config.js +8 -0
  15. package/build/dist/Models/AnalyticsModels/Metric.js +250 -2
  16. package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
  17. package/build/dist/Server/Services/MetricService.js +183 -2
  18. package/build/dist/Server/Services/MetricService.js.map +1 -1
  19. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +36 -2
  20. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  21. package/build/dist/Types/AnalyticsDatabase/TableColumnType.js +1 -0
  22. package/build/dist/Types/AnalyticsDatabase/TableColumnType.js.map +1 -1
  23. package/build/dist/Types/BaseDatabase/AggregationType.js +30 -0
  24. package/build/dist/Types/BaseDatabase/AggregationType.js.map +1 -1
  25. package/build/dist/UI/Components/Banner/Banner.js +6 -2
  26. package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
  27. package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js +5 -2
  28. package/build/dist/UI/Components/Breadcrumbs/Breadcrumbs.js.map +1 -1
  29. package/build/dist/UI/Components/EventItem/EventItem.js +9 -7
  30. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  31. package/build/dist/UI/Components/Label/Labels.js +8 -2
  32. package/build/dist/UI/Components/Label/Labels.js.map +1 -1
  33. package/build/dist/UI/Components/Modal/ConfirmModal.js +4 -1
  34. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  35. package/build/dist/UI/Components/Modal/Modal.js +13 -3
  36. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  37. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +7 -1
  38. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  39. package/build/dist/UI/Components/Page/Page.js +5 -2
  40. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  41. package/package.json +1 -1
@@ -4,6 +4,41 @@ enum AggregationType {
4
4
  Sum = "Sum",
5
5
  Avg = "Avg",
6
6
  Count = "Count",
7
+ /*
8
+ * Percentile aggregations. For Metric (the only model that carries
9
+ * histogram bucket data), MetricService overrides the aggregate path to
10
+ * fan out histogram buckets into weighted samples and use
11
+ * quantileExactWeighted, so a P95 of an `http.server.request.duration`
12
+ * histogram returns the bucket-derived 95th percentile rather than the
13
+ * 95th percentile of the per-row `sum`. For other models (Span, Log,
14
+ * etc.) the StatementGenerator falls back to ClickHouse's `quantile(p)`
15
+ * over the raw column, which is the right thing for scalar columns.
16
+ */
17
+ P50 = "P50",
18
+ P90 = "P90",
19
+ P95 = "P95",
20
+ P99 = "P99",
7
21
  }
8
22
 
9
23
  export default AggregationType;
24
+
25
+ export const PercentileAggregationLevels: Record<string, number> = {
26
+ [AggregationType.P50]: 0.5,
27
+ [AggregationType.P90]: 0.9,
28
+ [AggregationType.P95]: 0.95,
29
+ [AggregationType.P99]: 0.99,
30
+ };
31
+
32
+ export function isPercentileAggregation(type: AggregationType): boolean {
33
+ return Object.prototype.hasOwnProperty.call(
34
+ PercentileAggregationLevels,
35
+ type,
36
+ );
37
+ }
38
+
39
+ export function getPercentileLevel(type: AggregationType): number | null {
40
+ if (!isPercentileAggregation(type)) {
41
+ return null;
42
+ }
43
+ return PercentileAggregationLevels[type] ?? null;
44
+ }
@@ -1,6 +1,7 @@
1
1
  import Link from "../Link/Link";
2
2
  import Route from "../../../Types/API/Route";
3
3
  import URL from "../../../Types/API/URL";
4
+ import useTranslateValue from "../../Utils/Translation";
4
5
  import React, { FunctionComponent, ReactElement } from "react";
5
6
  import { GetReactElementFunction } from "../../Types/FunctionTypes";
6
7
 
@@ -15,10 +16,14 @@ export interface ComponentProps {
15
16
  const Banner: FunctionComponent<ComponentProps> = (
16
17
  props: ComponentProps,
17
18
  ): ReactElement => {
19
+ const { translateString } = useTranslateValue();
20
+ const translatedTitle: string = translateString(props.title) || props.title;
21
+ const translatedDescription: string =
22
+ translateString(props.description) || props.description;
18
23
  const getContent: GetReactElementFunction = (): ReactElement => {
19
24
  return (
20
25
  <>
21
- <strong className="font-semibold">{props.title}</strong>
26
+ <strong className="font-semibold">{translatedTitle}</strong>
22
27
  <svg
23
28
  viewBox="0 0 2 2"
24
29
  className="mx-2 inline h-0.5 w-0.5 fill-current"
@@ -26,7 +31,7 @@ const Banner: FunctionComponent<ComponentProps> = (
26
31
  >
27
32
  <circle cx="1" cy="1" r="1" />
28
33
  </svg>
29
- {props.description}&nbsp;
34
+ {translatedDescription}&nbsp;
30
35
  <span aria-hidden="true">&rarr;</span>
31
36
  </>
32
37
  );
@@ -4,6 +4,7 @@ import Route from "../../../Types/API/Route";
4
4
  import URL from "../../../Types/API/URL";
5
5
  import IconProp from "../../../Types/Icon/IconProp";
6
6
  import Link from "../../../Types/Link";
7
+ import useTranslateValue from "../../Utils/Translation";
7
8
  import React, { FunctionComponent, ReactElement } from "react";
8
9
 
9
10
  interface ComponentProps {
@@ -13,12 +14,15 @@ interface ComponentProps {
13
14
  const Breadcrumbs: FunctionComponent<ComponentProps> = ({
14
15
  links,
15
16
  }: ComponentProps): ReactElement => {
17
+ const { translateString } = useTranslateValue();
16
18
  return (
17
19
  <nav className="flex hidden md:block" aria-label="Breadcrumb">
18
20
  <ol role="list" className="flex items-center space-x-1">
19
21
  {links &&
20
22
  links.length > 0 &&
21
23
  links.map((link: Link, i: number) => {
24
+ const translatedTitle: string =
25
+ translateString(link.title) || link.title;
22
26
  return (
23
27
  <li className="breadcrumb-item" key={i}>
24
28
  {i === 0 && (
@@ -28,7 +32,7 @@ const Breadcrumbs: FunctionComponent<ComponentProps> = ({
28
32
  className="text-gray-400 hover:text-gray-500 -mt-1"
29
33
  >
30
34
  <span className="text-sm font-medium text-gray-500 hover:text-gray-700 -mt-1">
31
- {link.title}
35
+ {translatedTitle}
32
36
  </span>
33
37
  </UILink>
34
38
  </div>
@@ -48,7 +52,7 @@ const Breadcrumbs: FunctionComponent<ComponentProps> = ({
48
52
  }
49
53
  className="ml-1 text-sm font-medium text-gray-500 hover:text-gray-700 -mt-1"
50
54
  >
51
- {link.title}
55
+ {translatedTitle}
52
56
  </UILink>
53
57
  </div>
54
58
  )}
@@ -11,6 +11,7 @@ import Color from "../../../Types/Color";
11
11
  import OneUptimeDate from "../../../Types/Date";
12
12
  import IconProp from "../../../Types/Icon/IconProp";
13
13
  import React, { FunctionComponent, ReactElement } from "react";
14
+ import { useTranslation } from "react-i18next";
14
15
 
15
16
  export enum TimelineItemType {
16
17
  StateChange = "StateChange",
@@ -61,6 +62,7 @@ export interface ComponentProps {
61
62
  const EventItem: FunctionComponent<ComponentProps> = (
62
63
  props: ComponentProps,
63
64
  ): ReactElement => {
65
+ const { t } = useTranslation();
64
66
  return (
65
67
  <div className="mt-5 mb-5 bg-white shadow rounded-xl border-gray-100 p-5">
66
68
  <div>
@@ -156,7 +158,7 @@ const EventItem: FunctionComponent<ComponentProps> = (
156
158
  <div key={0}>
157
159
  <div className="flex flex-wrap gap-y-4 space-x-1 active-event-box-body-reesources">
158
160
  <div className="text-sm text-gray-400 mr-3 mt-1">
159
- Affected resources
161
+ {t("eventItem.affectedResources")}
160
162
  </div>
161
163
  {props.eventResourcesAffected?.map((item: string, i: number) => {
162
164
  return (
@@ -222,7 +224,7 @@ const EventItem: FunctionComponent<ComponentProps> = (
222
224
  <span className="font-medium text-gray-900 mr-1">
223
225
  {props.eventType}
224
226
  </span>
225
- state changed to
227
+ {t("eventItem.stateChangedTo")}
226
228
  </span>
227
229
  <span className="mr-1">
228
230
  <Pill
@@ -294,11 +296,13 @@ const EventItem: FunctionComponent<ComponentProps> = (
294
296
  >
295
297
  {item.title
296
298
  ? item.title
297
- : `Update to this ${props.eventType}`}
299
+ : t("eventItem.updateTo", {
300
+ eventType: props.eventType,
301
+ })}
298
302
  </span>
299
303
  </div>
300
304
  <p className="mt-0.5 text-sm text-gray-500">
301
- posted on{" "}
305
+ {t("eventItem.postedOn")}{" "}
302
306
  {OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
303
307
  item.date,
304
308
  )}
@@ -345,7 +349,7 @@ const EventItem: FunctionComponent<ComponentProps> = (
345
349
  className="cursor-pointer text-gray-400 hover:text-gray-500 text-sm"
346
350
  to={props.eventViewRoute}
347
351
  >
348
- <>View {props.eventType}</>
352
+ <>{t("eventItem.view", { eventType: props.eventType })}</>
349
353
  </Link>
350
354
  </span>
351
355
  ) : (
@@ -1,6 +1,7 @@
1
1
  import LabelElement from "./Label";
2
2
  import TableColumnListComponent from "../TableColumnList/TableColumnListComponent";
3
3
  import LabelModel from "../../../Models/DatabaseModels/Label";
4
+ import useTranslateValue from "../../Utils/Translation";
4
5
  import React, { FunctionComponent, ReactElement } from "react";
5
6
 
6
7
  export interface ComponentProps {
@@ -10,10 +11,17 @@ export interface ComponentProps {
10
11
  const LabelsElement: FunctionComponent<ComponentProps> = (
11
12
  props: ComponentProps,
12
13
  ): ReactElement => {
14
+ const { translateString } = useTranslateValue();
15
+ const moreText: string =
16
+ props.labels.length > 4
17
+ ? translateString("more labels") || "more labels"
18
+ : translateString("more label") || "more label";
19
+ const noItemsMessage: string =
20
+ translateString("No labels attached.") || "No labels attached.";
13
21
  return (
14
22
  <TableColumnListComponent
15
23
  items={props.labels}
16
- moreText={props.labels.length > 4 ? "more labels" : "more label"}
24
+ moreText={moreText}
17
25
  className={props.labels.length > 0 ? "-mb-1 -mt-1" : ""}
18
26
  getEachElement={(label: LabelModel) => {
19
27
  return (
@@ -27,7 +35,7 @@ const LabelsElement: FunctionComponent<ComponentProps> = (
27
35
  </div>
28
36
  );
29
37
  }}
30
- noItemsMessage="No labels attached."
38
+ noItemsMessage={noItemsMessage}
31
39
  />
32
40
  );
33
41
  };
@@ -1,5 +1,6 @@
1
1
  import { ButtonStyleType } from "../Button/Button";
2
2
  import Modal from "./Modal";
3
+ import useTranslateValue from "../../Utils/Translation";
3
4
  import React, { FunctionComponent, ReactElement } from "react";
4
5
 
5
6
  export interface ComponentProps {
@@ -19,6 +20,9 @@ export interface ComponentProps {
19
20
  const ConfirmModal: FunctionComponent<ComponentProps> = (
20
21
  props: ComponentProps,
21
22
  ): ReactElement => {
23
+ const { translateValue } = useTranslateValue();
24
+ const translatedDescription: string | ReactElement | undefined =
25
+ translateValue(props.description);
22
26
  return (
23
27
  <Modal
24
28
  title={props.title}
@@ -46,7 +50,7 @@ const ConfirmModal: FunctionComponent<ComponentProps> = (
46
50
  data-testid="confirm-modal-description"
47
51
  className="text-gray-500 mt-5 text-sm whitespace-pre-wrap break-words max-h-96 overflow-y-auto pr-1"
48
52
  >
49
- {props.description}
53
+ {translatedDescription}
50
54
  </div>
51
55
  </Modal>
52
56
  );
@@ -6,6 +6,7 @@ import ModalBody from "./ModalBody";
6
6
  import ModalFooter from "./ModalFooter";
7
7
  import { VeryLightGray } from "../../../Types/BrandColors";
8
8
  import IconProp from "../../../Types/Icon/IconProp";
9
+ import useTranslateValue from "../../Utils/Translation";
9
10
  import React, {
10
11
  FunctionComponent,
11
12
  ReactElement,
@@ -43,6 +44,17 @@ export interface ComponentProps {
43
44
  const Modal: FunctionComponent<ComponentProps> = (
44
45
  props: ComponentProps,
45
46
  ): ReactElement => {
47
+ const { translateString } = useTranslateValue();
48
+ const translatedTitle: string = translateString(props.title) || props.title;
49
+ const translatedDescription: string | undefined = translateString(
50
+ props.description,
51
+ );
52
+ const translatedSubmitButtonText: string | undefined = translateString(
53
+ props.submitButtonText,
54
+ );
55
+ const translatedCloseButtonText: string | undefined = translateString(
56
+ props.closeButtonText,
57
+ );
46
58
  const modalRef: React.RefObject<HTMLDivElement> =
47
59
  useRef<HTMLDivElement>(null);
48
60
 
@@ -162,15 +174,15 @@ const Modal: FunctionComponent<ComponentProps> = (
162
174
  }`}
163
175
  id="modal-title"
164
176
  >
165
- {props.title}
177
+ {translatedTitle}
166
178
  </h3>
167
- {props.description && (
179
+ {translatedDescription && (
168
180
  <p
169
181
  id="modal-description"
170
182
  data-testid="modal-description"
171
183
  className="text-sm leading-6 text-gray-500 mt-2"
172
184
  >
173
- {props.description}
185
+ {translatedDescription}
174
186
  </p>
175
187
  )}
176
188
  </div>
@@ -214,10 +226,14 @@ const Modal: FunctionComponent<ComponentProps> = (
214
226
  : ButtonStyleType.NORMAL
215
227
  }
216
228
  submitButtonText={
217
- props.submitButtonText ? props.submitButtonText : "Save"
229
+ translatedSubmitButtonText
230
+ ? translatedSubmitButtonText
231
+ : translateString("Save") || "Save"
218
232
  }
219
233
  closeButtonText={
220
- props.closeButtonText ? props.closeButtonText : "Cancel"
234
+ translatedCloseButtonText
235
+ ? translatedCloseButtonText
236
+ : translateString("Cancel") || "Cancel"
221
237
  }
222
238
  onSubmit={props.onSubmit}
223
239
  onClose={props.onClose ? props.onClose : undefined}
@@ -4,6 +4,7 @@ import { API_DOCS_URL, BILLING_ENABLED, getAllEnvVars } from "../../Config";
4
4
  import { GetReactElementFunction } from "../../Types/FunctionTypes";
5
5
  import SelectEntityField from "../../Types/SelectEntityField";
6
6
  import API from "../../Utils/API/API";
7
+ import useTranslateValue from "../../Utils/Translation";
7
8
 
8
9
  import Query from "../../../Types/BaseDatabase/Query";
9
10
  import GroupBy from "../../../Types/BaseDatabase/GroupBy";
@@ -266,6 +267,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
266
267
  ) => ReactElement = <TBaseModel extends BaseModel | AnalyticsBaseModel>(
267
268
  props: ComponentProps<TBaseModel>,
268
269
  ): ReactElement => {
270
+ const { translateValue } = useTranslateValue();
269
271
  const [tableView, setTableView] = useState<TableView | null>(null);
270
272
 
271
273
  const matchBulkSelectedItemByField: keyof TBaseModel =
@@ -1917,6 +1919,10 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1917
1919
  const getCardTitle: GetCardTitleFunction = (
1918
1920
  title: ReactElement | string,
1919
1921
  ): ReactElement => {
1922
+ const renderedTitle: ReactElement | string =
1923
+ typeof title === "string"
1924
+ ? (translateValue(title) as ReactElement | string | undefined) ?? title
1925
+ : title;
1920
1926
  const plan: PlanType | null = ProjectUtil.getCurrentPlan();
1921
1927
 
1922
1928
  let showPlan: boolean = Boolean(
@@ -1950,7 +1956,7 @@ const BaseModelTable: <TBaseModel extends BaseModel | AnalyticsBaseModel>(
1950
1956
 
1951
1957
  return (
1952
1958
  <span>
1953
- {title}
1959
+ {renderedTitle}
1954
1960
  {showPlan && (
1955
1961
  <span
1956
1962
  style={{
@@ -5,6 +5,7 @@ import PageLoader from "../Loader/PageLoader";
5
5
  import LabelElement from "../Label/Label";
6
6
  import Link from "../../../Types/Link";
7
7
  import LabelModel from "../../../Models/DatabaseModels/Label";
8
+ import useTranslateValue from "../../Utils/Translation";
8
9
  import React, { FunctionComponent, ReactElement, useEffect } from "react";
9
10
 
10
11
  export interface ComponentProps {
@@ -22,6 +23,9 @@ export interface ComponentProps {
22
23
  const Page: FunctionComponent<ComponentProps> = (
23
24
  props: ComponentProps,
24
25
  ): ReactElement => {
26
+ const { translateString } = useTranslateValue();
27
+ const translatedTitle: string | undefined = translateString(props.title);
28
+
25
29
  useEffect(() => {
26
30
  if (props.breadcrumbLinks && props.breadcrumbLinks.length > 0) {
27
31
  Analytics.capture(
@@ -60,7 +64,7 @@ const Page: FunctionComponent<ComponentProps> = (
60
64
  <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:flex-wrap sm:gap-4">
61
65
  <div className="flex flex-col gap-1 min-w-0">
62
66
  <h1 className="text-xl font-semibold leading-7 text-gray-900 sm:text-xl sm:tracking-tight sm:truncate">
63
- {props.title}
67
+ {translatedTitle}
64
68
  </h1>
65
69
  </div>
66
70
  {props.headerRight && (
@@ -71,7 +75,7 @@ const Page: FunctionComponent<ComponentProps> = (
71
75
  {props.labels && props.labels.length > 0 && (
72
76
  <div className="hidden sm:flex sm:flex-wrap sm:items-center sm:justify-end sm:gap-3">
73
77
  <span className="text-xs font-semibold uppercase tracking-wide text-gray-500 whitespace-nowrap">
74
- Labels
78
+ {translateString("Labels") || "Labels"}
75
79
  </span>
76
80
  <div className="flex flex-wrap items-center gap-2 justify-end">
77
81
  {props.labels
@@ -230,6 +230,8 @@ function createConfig(options) {
230
230
  const isDev = process.env.NODE_ENV !== 'production';
231
231
  const isAnalyze = process.env.analyze === 'true';
232
232
  const reactRoot = resolvePackageRoot('react');
233
+ const reactI18nextRoot = resolvePackageRoot('react-i18next');
234
+ const i18nextRoot = resolvePackageRoot('i18next');
233
235
 
234
236
  return {
235
237
  entryPoints: [entryPoint],
@@ -252,6 +254,12 @@ function createConfig(options) {
252
254
  'react': reactRoot,
253
255
  'react/jsx-runtime': path.join(reactRoot, 'jsx-runtime.js'),
254
256
  'react/jsx-dev-runtime': path.join(reactRoot, 'jsx-dev-runtime.js'),
257
+ // Force a single instance of i18next/react-i18next so that translations
258
+ // initialized in the service entry are visible to Common UI components.
259
+ // Without this, Common's own node_modules copy gets a separate, never-
260
+ // initialized i18n singleton and useTranslation() returns the raw key.
261
+ 'react-i18next': reactI18nextRoot,
262
+ 'i18next': i18nextRoot,
255
263
  ...additionalAlias,
256
264
  },
257
265
  plugins: [createMermaidPlugin(), createRefractorCompatibilityPlugin(), createCSSPlugin(), createFileLoaderPlugin()],
@@ -16,6 +16,7 @@ export var MetricPointType;
16
16
  MetricPointType["Gauge"] = "Gauge";
17
17
  MetricPointType["Histogram"] = "Histogram";
18
18
  MetricPointType["ExponentialHistogram"] = "ExponentialHistogram";
19
+ MetricPointType["Summary"] = "Summary";
19
20
  })(MetricPointType || (MetricPointType = {}));
20
21
  export var ServiceType;
21
22
  (function (ServiceType) {
@@ -473,8 +474,147 @@ export default class Metric extends AnalyticsBaseModel {
473
474
  });
474
475
  const explicitBoundsColumn = new AnalyticsTableColumn({
475
476
  key: "explicitBounds",
476
- title: "Explicit Bonds",
477
- description: "Explicit Bonds",
477
+ title: "Explicit Bounds",
478
+ description: "Upper bounds (exclusive of the +inf overflow bucket) for each explicit-bucket histogram bucket. Stored as Float64 so sub-integer boundaries (e.g. 0.005, 0.01) survive ingest — the previous Array(Int64) representation silently truncated those to 0.",
479
+ required: true,
480
+ defaultValue: [],
481
+ type: TableColumnType.ArrayDecimal,
482
+ accessControl: {
483
+ read: [
484
+ Permission.ProjectOwner,
485
+ Permission.ProjectAdmin,
486
+ Permission.ProjectMember,
487
+ Permission.ReadTelemetryServiceLog,
488
+ ],
489
+ create: [
490
+ Permission.ProjectOwner,
491
+ Permission.ProjectAdmin,
492
+ Permission.ProjectMember,
493
+ Permission.CreateTelemetryServiceLog,
494
+ ],
495
+ update: [],
496
+ },
497
+ });
498
+ /*
499
+ * --- ExponentialHistogram-only columns ----------------------------------
500
+ * These are populated only when metricPointType = ExponentialHistogram.
501
+ * For other metric types they are left at their defaults (0 / []).
502
+ */
503
+ const scaleColumn = new AnalyticsTableColumn({
504
+ key: "scale",
505
+ title: "Scale",
506
+ description: "ExponentialHistogram resolution. base = 2^(2^-scale); bucket index `i` covers (base^i, base^(i+1)].",
507
+ required: false,
508
+ type: TableColumnType.Number,
509
+ accessControl: {
510
+ read: [
511
+ Permission.ProjectOwner,
512
+ Permission.ProjectAdmin,
513
+ Permission.ProjectMember,
514
+ Permission.ReadTelemetryServiceLog,
515
+ ],
516
+ create: [
517
+ Permission.ProjectOwner,
518
+ Permission.ProjectAdmin,
519
+ Permission.ProjectMember,
520
+ Permission.CreateTelemetryServiceLog,
521
+ ],
522
+ update: [],
523
+ },
524
+ });
525
+ const zeroCountColumn = new AnalyticsTableColumn({
526
+ key: "zeroCount",
527
+ title: "Zero Count",
528
+ description: "ExponentialHistogram count of values within the zero region (|v| <= zeroThreshold).",
529
+ required: false,
530
+ type: TableColumnType.BigNumber,
531
+ accessControl: {
532
+ read: [
533
+ Permission.ProjectOwner,
534
+ Permission.ProjectAdmin,
535
+ Permission.ProjectMember,
536
+ Permission.ReadTelemetryServiceLog,
537
+ ],
538
+ create: [
539
+ Permission.ProjectOwner,
540
+ Permission.ProjectAdmin,
541
+ Permission.ProjectMember,
542
+ Permission.CreateTelemetryServiceLog,
543
+ ],
544
+ update: [],
545
+ },
546
+ });
547
+ const positiveOffsetColumn = new AnalyticsTableColumn({
548
+ key: "positiveOffset",
549
+ title: "Positive Bucket Offset",
550
+ description: "Bucket index of the first entry in positiveBucketCounts (ExponentialHistogram).",
551
+ required: false,
552
+ type: TableColumnType.Number,
553
+ accessControl: {
554
+ read: [
555
+ Permission.ProjectOwner,
556
+ Permission.ProjectAdmin,
557
+ Permission.ProjectMember,
558
+ Permission.ReadTelemetryServiceLog,
559
+ ],
560
+ create: [
561
+ Permission.ProjectOwner,
562
+ Permission.ProjectAdmin,
563
+ Permission.ProjectMember,
564
+ Permission.CreateTelemetryServiceLog,
565
+ ],
566
+ update: [],
567
+ },
568
+ });
569
+ const positiveBucketCountsColumn = new AnalyticsTableColumn({
570
+ key: "positiveBucketCounts",
571
+ title: "Positive Bucket Counts",
572
+ description: "Counts for the positive range of an ExponentialHistogram, indexed from positiveOffset.",
573
+ required: true,
574
+ defaultValue: [],
575
+ type: TableColumnType.ArrayBigNumber,
576
+ accessControl: {
577
+ read: [
578
+ Permission.ProjectOwner,
579
+ Permission.ProjectAdmin,
580
+ Permission.ProjectMember,
581
+ Permission.ReadTelemetryServiceLog,
582
+ ],
583
+ create: [
584
+ Permission.ProjectOwner,
585
+ Permission.ProjectAdmin,
586
+ Permission.ProjectMember,
587
+ Permission.CreateTelemetryServiceLog,
588
+ ],
589
+ update: [],
590
+ },
591
+ });
592
+ const negativeOffsetColumn = new AnalyticsTableColumn({
593
+ key: "negativeOffset",
594
+ title: "Negative Bucket Offset",
595
+ description: "Bucket index of the first entry in negativeBucketCounts (ExponentialHistogram).",
596
+ required: false,
597
+ type: TableColumnType.Number,
598
+ accessControl: {
599
+ read: [
600
+ Permission.ProjectOwner,
601
+ Permission.ProjectAdmin,
602
+ Permission.ProjectMember,
603
+ Permission.ReadTelemetryServiceLog,
604
+ ],
605
+ create: [
606
+ Permission.ProjectOwner,
607
+ Permission.ProjectAdmin,
608
+ Permission.ProjectMember,
609
+ Permission.CreateTelemetryServiceLog,
610
+ ],
611
+ update: [],
612
+ },
613
+ });
614
+ const negativeBucketCountsColumn = new AnalyticsTableColumn({
615
+ key: "negativeBucketCounts",
616
+ title: "Negative Bucket Counts",
617
+ description: "Counts for the negative range of an ExponentialHistogram, indexed from negativeOffset.",
478
618
  required: true,
479
619
  defaultValue: [],
480
620
  type: TableColumnType.ArrayBigNumber,
@@ -494,6 +634,58 @@ export default class Metric extends AnalyticsBaseModel {
494
634
  update: [],
495
635
  },
496
636
  });
637
+ /*
638
+ * --- Summary-only columns -----------------------------------------------
639
+ * Populated only when metricPointType = Summary. Two parallel arrays
640
+ * keyed by index (mirrors the bucketCounts/explicitBounds convention):
641
+ * summaryQuantiles[i] in [0,1], summaryValues[i] is value at that quantile.
642
+ */
643
+ const summaryQuantilesColumn = new AnalyticsTableColumn({
644
+ key: "summaryQuantiles",
645
+ title: "Summary Quantiles",
646
+ description: "Quantile percentages in [0,1] for a Summary metric (parallel to summaryValues).",
647
+ required: true,
648
+ defaultValue: [],
649
+ type: TableColumnType.ArrayDecimal,
650
+ accessControl: {
651
+ read: [
652
+ Permission.ProjectOwner,
653
+ Permission.ProjectAdmin,
654
+ Permission.ProjectMember,
655
+ Permission.ReadTelemetryServiceLog,
656
+ ],
657
+ create: [
658
+ Permission.ProjectOwner,
659
+ Permission.ProjectAdmin,
660
+ Permission.ProjectMember,
661
+ Permission.CreateTelemetryServiceLog,
662
+ ],
663
+ update: [],
664
+ },
665
+ });
666
+ const summaryValuesColumn = new AnalyticsTableColumn({
667
+ key: "summaryValues",
668
+ title: "Summary Values",
669
+ description: "Values corresponding to each quantile in summaryQuantiles for a Summary metric.",
670
+ required: true,
671
+ defaultValue: [],
672
+ type: TableColumnType.ArrayDecimal,
673
+ accessControl: {
674
+ read: [
675
+ Permission.ProjectOwner,
676
+ Permission.ProjectAdmin,
677
+ Permission.ProjectMember,
678
+ Permission.ReadTelemetryServiceLog,
679
+ ],
680
+ create: [
681
+ Permission.ProjectOwner,
682
+ Permission.ProjectAdmin,
683
+ Permission.ProjectMember,
684
+ Permission.CreateTelemetryServiceLog,
685
+ ],
686
+ update: [],
687
+ },
688
+ });
497
689
  const traceIdColumn = new AnalyticsTableColumn({
498
690
  key: "traceId",
499
691
  title: "Trace ID",
@@ -611,6 +803,14 @@ export default class Metric extends AnalyticsBaseModel {
611
803
  maxColumn,
612
804
  bucketCountsColumn,
613
805
  explicitBoundsColumn,
806
+ scaleColumn,
807
+ zeroCountColumn,
808
+ positiveOffsetColumn,
809
+ positiveBucketCountsColumn,
810
+ negativeOffsetColumn,
811
+ negativeBucketCountsColumn,
812
+ summaryQuantilesColumn,
813
+ summaryValuesColumn,
614
814
  traceIdColumn,
615
815
  spanIdColumn,
616
816
  retentionDateColumn,
@@ -760,5 +960,53 @@ export default class Metric extends AnalyticsBaseModel {
760
960
  set retentionDate(v) {
761
961
  this.setColumnValue("retentionDate", v);
762
962
  }
963
+ get scale() {
964
+ return this.getColumnValue("scale");
965
+ }
966
+ set scale(v) {
967
+ this.setColumnValue("scale", v);
968
+ }
969
+ get zeroCount() {
970
+ return this.getColumnValue("zeroCount");
971
+ }
972
+ set zeroCount(v) {
973
+ this.setColumnValue("zeroCount", v);
974
+ }
975
+ get positiveOffset() {
976
+ return this.getColumnValue("positiveOffset");
977
+ }
978
+ set positiveOffset(v) {
979
+ this.setColumnValue("positiveOffset", v);
980
+ }
981
+ get positiveBucketCounts() {
982
+ return this.getColumnValue("positiveBucketCounts");
983
+ }
984
+ set positiveBucketCounts(v) {
985
+ this.setColumnValue("positiveBucketCounts", v);
986
+ }
987
+ get negativeOffset() {
988
+ return this.getColumnValue("negativeOffset");
989
+ }
990
+ set negativeOffset(v) {
991
+ this.setColumnValue("negativeOffset", v);
992
+ }
993
+ get negativeBucketCounts() {
994
+ return this.getColumnValue("negativeBucketCounts");
995
+ }
996
+ set negativeBucketCounts(v) {
997
+ this.setColumnValue("negativeBucketCounts", v);
998
+ }
999
+ get summaryQuantiles() {
1000
+ return this.getColumnValue("summaryQuantiles");
1001
+ }
1002
+ set summaryQuantiles(v) {
1003
+ this.setColumnValue("summaryQuantiles", v);
1004
+ }
1005
+ get summaryValues() {
1006
+ return this.getColumnValue("summaryValues");
1007
+ }
1008
+ set summaryValues(v) {
1009
+ this.setColumnValue("summaryValues", v);
1010
+ }
763
1011
  }
764
1012
  //# sourceMappingURL=Metric.js.map