@oneuptime/common 10.4.10 → 10.4.12

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 (174) hide show
  1. package/Models/AnalyticsModels/ExceptionInstance.ts +47 -1
  2. package/Models/AnalyticsModels/Log.ts +47 -1
  3. package/Models/AnalyticsModels/Metric.ts +1 -7
  4. package/Models/AnalyticsModels/Profile.ts +47 -1
  5. package/Models/AnalyticsModels/ProfileSample.ts +47 -1
  6. package/Models/AnalyticsModels/Span.ts +47 -1
  7. package/Models/DatabaseModels/Alert.ts +332 -0
  8. package/Models/DatabaseModels/DockerHost.ts +83 -0
  9. package/Models/DatabaseModels/Host.ts +83 -0
  10. package/Models/DatabaseModels/Incident.ts +332 -0
  11. package/Models/DatabaseModels/Index.ts +0 -2
  12. package/Models/DatabaseModels/KubernetesCluster.ts +83 -0
  13. package/Models/DatabaseModels/RunbookAgent.ts +16 -2
  14. package/Server/EnvironmentConfig.ts +16 -0
  15. package/Server/Infrastructure/ClickhouseConfig.ts +14 -0
  16. package/Server/Infrastructure/ClickhouseDatabase.ts +20 -3
  17. package/Server/Infrastructure/InMemoryTTLCache.ts +61 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.ts +1 -1
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.ts +44 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.ts +50 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1779302536475-AttachKubernetesAndDockerToIncidentAndAlert.ts +253 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1779303924241-AttachServiceToIncidentAndAlert.ts +60 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  24. package/Server/Middleware/TelemetryIngest.ts +6 -38
  25. package/Server/Middleware/UserAuthorization.ts +1 -11
  26. package/Server/Services/AlertService.ts +2 -4
  27. package/Server/Services/AnalyticsDatabaseService.ts +33 -1
  28. package/Server/Services/IncidentService.ts +2 -4
  29. package/Server/Services/Index.ts +0 -2
  30. package/Server/Services/LogAggregationService.ts +54 -6
  31. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +6 -0
  32. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +1 -0
  33. package/Server/Services/OnCallDutyPolicyScheduleService.ts +17 -0
  34. package/Server/Services/OpenTelemetryIngestService.ts +132 -0
  35. package/Server/Services/TelemetryIngestionKeyService.ts +90 -1
  36. package/Server/Services/TraceAggregationService.ts +83 -8
  37. package/Server/Utils/Monitor/MonitorMetricUtil.ts +2 -4
  38. package/Server/Utils/Telemetry/Telemetry.ts +38 -0
  39. package/Tests/Server/Middleware/UserAuthorization.test.ts +5 -7
  40. package/Types/Dashboard/DashboardComponentType.ts +0 -1
  41. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +2 -0
  42. package/Types/Dashboard/DashboardComponents/DashboardTableComponent.ts +74 -1
  43. package/Types/Dashboard/DashboardTemplates.ts +164 -51
  44. package/Types/Monitor/MonitorType.ts +1 -1
  45. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +36 -9
  46. package/Types/Permission.ts +0 -46
  47. package/Types/Telemetry/ServiceType.ts +19 -0
  48. package/UI/Components/Forms/Validation.ts +2 -2
  49. package/UI/Components/LogsViewer/LogsViewer.tsx +135 -17
  50. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +84 -1
  51. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -1
  52. package/Utils/Dashboard/Components/DashboardTableComponent.ts +80 -17
  53. package/Utils/Dashboard/Components/Index.ts +0 -7
  54. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js +41 -1
  55. package/build/dist/Models/AnalyticsModels/ExceptionInstance.js.map +1 -1
  56. package/build/dist/Models/AnalyticsModels/Log.js +41 -1
  57. package/build/dist/Models/AnalyticsModels/Log.js.map +1 -1
  58. package/build/dist/Models/AnalyticsModels/Metric.js +0 -7
  59. package/build/dist/Models/AnalyticsModels/Metric.js.map +1 -1
  60. package/build/dist/Models/AnalyticsModels/Profile.js +41 -1
  61. package/build/dist/Models/AnalyticsModels/Profile.js.map +1 -1
  62. package/build/dist/Models/AnalyticsModels/ProfileSample.js +41 -1
  63. package/build/dist/Models/AnalyticsModels/ProfileSample.js.map +1 -1
  64. package/build/dist/Models/AnalyticsModels/Span.js +41 -1
  65. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  66. package/build/dist/Models/DatabaseModels/Alert.js +324 -0
  67. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  68. package/build/dist/Models/DatabaseModels/DockerHost.js +84 -0
  69. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  70. package/build/dist/Models/DatabaseModels/Host.js +84 -0
  71. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  72. package/build/dist/Models/DatabaseModels/Incident.js +324 -0
  73. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  74. package/build/dist/Models/DatabaseModels/Index.js +0 -2
  75. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  76. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +84 -0
  77. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  78. package/build/dist/Models/DatabaseModels/RunbookAgent.js +16 -2
  79. package/build/dist/Models/DatabaseModels/RunbookAgent.js.map +1 -1
  80. package/build/dist/Server/EnvironmentConfig.js +8 -0
  81. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  82. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +9 -1
  83. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  84. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +12 -3
  85. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  86. package/build/dist/Server/Infrastructure/InMemoryTTLCache.js +49 -0
  87. package/build/dist/Server/Infrastructure/InMemoryTTLCache.js.map +1 -0
  88. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779199346010-AddTelemetryRetentionConfig.js.map +1 -1
  89. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.js +42 -0
  90. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779277271302-DropServiceDependencyTable.js.map +1 -0
  91. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.js +22 -0
  92. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779282769946-AddTelemetryRetentionToHostDockerKubernetes.js.map +1 -0
  93. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779302536475-AttachKubernetesAndDockerToIncidentAndAlert.js +100 -0
  94. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779302536475-AttachKubernetesAndDockerToIncidentAndAlert.js.map +1 -0
  95. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779303924241-AttachServiceToIncidentAndAlert.js +28 -0
  96. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1779303924241-AttachServiceToIncidentAndAlert.js.map +1 -0
  97. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  98. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  99. package/build/dist/Server/Middleware/TelemetryIngest.js +2 -26
  100. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  101. package/build/dist/Server/Middleware/UserAuthorization.js +1 -7
  102. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  103. package/build/dist/Server/Services/AlertService.js +2 -1
  104. package/build/dist/Server/Services/AlertService.js.map +1 -1
  105. package/build/dist/Server/Services/AnalyticsDatabaseService.js +23 -2
  106. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  107. package/build/dist/Server/Services/IncidentService.js +2 -1
  108. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  109. package/build/dist/Server/Services/Index.js +0 -2
  110. package/build/dist/Server/Services/Index.js.map +1 -1
  111. package/build/dist/Server/Services/LogAggregationService.js +46 -4
  112. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  113. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +28 -24
  114. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  115. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +1 -1
  116. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  117. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +18 -2
  118. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  119. package/build/dist/Server/Services/OpenTelemetryIngestService.js +103 -0
  120. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  121. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +83 -0
  122. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  123. package/build/dist/Server/Services/TraceAggregationService.js +66 -6
  124. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  125. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +2 -1
  126. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  127. package/build/dist/Server/Utils/Telemetry/Telemetry.js +26 -0
  128. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  129. package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js +3 -7
  130. package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +1 -1
  131. package/build/dist/Types/Dashboard/DashboardComponentType.js +0 -1
  132. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  133. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +2 -0
  134. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  135. package/build/dist/Types/Dashboard/DashboardComponents/DashboardTableComponent.js +13 -1
  136. package/build/dist/Types/Dashboard/DashboardComponents/DashboardTableComponent.js.map +1 -1
  137. package/build/dist/Types/Dashboard/DashboardTemplates.js +142 -42
  138. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  139. package/build/dist/Types/Monitor/MonitorType.js +1 -1
  140. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  141. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +27 -7
  142. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
  143. package/build/dist/Types/Permission.js +0 -40
  144. package/build/dist/Types/Permission.js.map +1 -1
  145. package/build/dist/Types/Telemetry/ServiceType.js +20 -0
  146. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -0
  147. package/build/dist/UI/Components/Forms/Validation.js +2 -2
  148. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  149. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +106 -16
  150. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  151. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +67 -1
  152. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  153. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +1 -1
  154. package/build/dist/Utils/Dashboard/Components/DashboardTableComponent.js +68 -16
  155. package/build/dist/Utils/Dashboard/Components/DashboardTableComponent.js.map +1 -1
  156. package/build/dist/Utils/Dashboard/Components/Index.js +0 -4
  157. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  158. package/package.json +1 -2
  159. package/Models/DatabaseModels/ServiceDependency.ts +0 -529
  160. package/Server/Services/ServiceDependencyService.ts +0 -48
  161. package/Types/Dashboard/DashboardComponents/DashboardHostMetricChartComponent.ts +0 -27
  162. package/Typings/elkjs.d.ts +0 -30
  163. package/UI/Components/Graphs/ServiceDependencyGraph.tsx +0 -286
  164. package/Utils/Dashboard/Components/DashboardHostMetricChartComponent.ts +0 -132
  165. package/build/dist/Models/DatabaseModels/ServiceDependency.js +0 -545
  166. package/build/dist/Models/DatabaseModels/ServiceDependency.js.map +0 -1
  167. package/build/dist/Server/Services/ServiceDependencyService.js +0 -47
  168. package/build/dist/Server/Services/ServiceDependencyService.js.map +0 -1
  169. package/build/dist/Types/Dashboard/DashboardComponents/DashboardHostMetricChartComponent.js +0 -11
  170. package/build/dist/Types/Dashboard/DashboardComponents/DashboardHostMetricChartComponent.js.map +0 -1
  171. package/build/dist/UI/Components/Graphs/ServiceDependencyGraph.js +0 -206
  172. package/build/dist/UI/Components/Graphs/ServiceDependencyGraph.js.map +0 -1
  173. package/build/dist/Utils/Dashboard/Components/DashboardHostMetricChartComponent.js +0 -113
  174. package/build/dist/Utils/Dashboard/Components/DashboardHostMetricChartComponent.js.map +0 -1
@@ -2,6 +2,7 @@ import ProjectMiddleware from "../../../Server/Middleware/ProjectAuthorization";
2
2
  import UserMiddleware from "../../../Server/Middleware/UserAuthorization";
3
3
  import AccessTokenService from "../../../Server/Services/AccessTokenService";
4
4
  import ProjectService from "../../../Server/Services/ProjectService";
5
+ import TeamMemberService from "../../../Server/Services/TeamMemberService";
5
6
  import UserService from "../../../Server/Services/UserService";
6
7
  import {
7
8
  ExpressRequest,
@@ -44,6 +45,7 @@ jest.mock("../../../Server/Services/UserService");
44
45
  jest.mock("../../../Server/Services/AccessTokenService");
45
46
  jest.mock("../../../Server/Utils/Response");
46
47
  jest.mock("../../../Server/Services/ProjectService");
48
+ jest.mock("../../../Server/Services/TeamMemberService");
47
49
  jest.mock("../../../Types/HashedString");
48
50
  jest.mock("../../../Types/JSONFunctions");
49
51
 
@@ -290,6 +292,9 @@ describe("UserMiddleware", () => {
290
292
  ).mockReturnValue(mockedAccessToken);
291
293
  getJestSpyOn(JSONWebToken, "decode").mockReturnValue(jwtTokenData);
292
294
  getJestSpyOn(HashedString, "hashValue").mockResolvedValue(hashValue);
295
+ getJestSpyOn(TeamMemberService, "getTeamIdsForUser").mockResolvedValue(
296
+ [],
297
+ );
293
298
  });
294
299
 
295
300
  beforeEach(() => {
@@ -418,7 +423,6 @@ describe("UserMiddleware", () => {
418
423
  req,
419
424
  tenantId: projectId,
420
425
  userId,
421
- isGlobalLogin: true,
422
426
  },
423
427
  );
424
428
  expect(next).not.toBeCalled();
@@ -449,7 +453,6 @@ describe("UserMiddleware", () => {
449
453
  req,
450
454
  tenantId: projectId,
451
455
  userId,
452
- isGlobalLogin: true,
453
456
  },
454
457
  );
455
458
  });
@@ -574,7 +577,6 @@ describe("UserMiddleware", () => {
574
577
  req: mockedRequest,
575
578
  tenantId: projectId,
576
579
  userId,
577
- isGlobalLogin: true,
578
580
  },
579
581
  );
580
582
  });
@@ -604,7 +606,6 @@ describe("UserMiddleware", () => {
604
606
  req,
605
607
  tenantId: projectId,
606
608
  userId,
607
- isGlobalLogin: true,
608
609
  }),
609
610
  ).rejects.toThrowError(new BadDataException("Invalid tenantId"));
610
611
  expect(spyFindOneById).toHaveBeenCalledWith({
@@ -631,7 +632,6 @@ describe("UserMiddleware", () => {
631
632
  req,
632
633
  tenantId: projectId,
633
634
  userId,
634
- isGlobalLogin: true,
635
635
  }),
636
636
  ).rejects.toThrowError(new SsoAuthorizationException());
637
637
  expect(spyDoesSsoTokenForProjectExist).toHaveBeenCalledWith(
@@ -654,7 +654,6 @@ describe("UserMiddleware", () => {
654
654
  req,
655
655
  tenantId: projectId,
656
656
  userId,
657
- isGlobalLogin: true,
658
657
  });
659
658
 
660
659
  expect(result).toBeNull();
@@ -681,7 +680,6 @@ describe("UserMiddleware", () => {
681
680
  req,
682
681
  tenantId: projectId,
683
682
  userId,
684
- isGlobalLogin: true,
685
683
  });
686
684
 
687
685
  expect(result).toEqual(mockedUserTenantAccessPermission);
@@ -23,7 +23,6 @@ enum DashboardComponentType {
23
23
  DockerNetworkList = `DockerNetworkList`,
24
24
  DockerVolumeList = `DockerVolumeList`,
25
25
  HostList = `HostList`,
26
- HostMetricChart = `HostMetricChart`,
27
26
  }
28
27
 
29
28
  export default DashboardComponentType;
@@ -11,6 +11,8 @@ export enum ComponentInputType {
11
11
  MetricsQueryConfig = "MetricsQueryConfig",
12
12
  MetricsQueryConfigs = "MetricsQueryConfigs",
13
13
  MetricsFormulaConfigs = "MetricsFormulaConfigs",
14
+ TableColumns = "TableColumns",
15
+ TableGroupBy = "TableGroupBy",
14
16
  LongText = "Long Text",
15
17
  Dropdown = "Dropdown",
16
18
  MultiSelectDropdown = "MultiSelectDropdown",
@@ -1,14 +1,87 @@
1
+ import MetricFormulaConfigData from "../../Metrics/MetricFormulaConfigData";
1
2
  import MetricQueryConfigData from "../../Metrics/MetricQueryConfigData";
3
+ import MetricsAggregationType from "../../Metrics/MetricsAggregationType";
2
4
  import ObjectID from "../../ObjectID";
3
5
  import DashboardComponentType from "../DashboardComponentType";
4
6
  import BaseComponent from "./DashboardBaseComponent";
5
7
 
8
+ export enum TableReduce {
9
+ Last = "Last",
10
+ Avg = "Avg",
11
+ Sum = "Sum",
12
+ Min = "Min",
13
+ Max = "Max",
14
+ }
15
+
16
+ export enum TableColumnKind {
17
+ Metric = "Metric",
18
+ Formula = "Formula",
19
+ }
20
+
21
+ export interface TableColumn {
22
+ /*
23
+ * Stable identifier so React keys survive reorder and the form can
24
+ * match inputs to the column being edited.
25
+ */
26
+ id: string;
27
+ // Single-letter variable (a, b, c, ...) that formulas can reference.
28
+ variable: string;
29
+ // User-facing column header (used only when showAsColumn !== false).
30
+ header: string;
31
+ kind: TableColumnKind;
32
+ /*
33
+ * When false, the metric/formula is still fetched (so formulas can
34
+ * reference it by variable) but it does not render a visible column.
35
+ * Default: true.
36
+ */
37
+ showAsColumn?: boolean | undefined;
38
+ // kind === Metric:
39
+ metricName?: string | undefined;
40
+ aggregation?: MetricsAggregationType | undefined;
41
+ // kind === Formula: expression referencing other variables, e.g. "(a / b) * 100".
42
+ formula?: string | undefined;
43
+ // Per-cell formatting (both kinds).
44
+ decimals?: number | undefined;
45
+ /*
46
+ * Unit to render after each cell value (e.g. "%", "MB", "ms").
47
+ * Empty/undefined = Auto: for metric columns, falls back to the metric
48
+ * type's native unit; for formula columns, no unit is rendered.
49
+ */
50
+ unit?: string | undefined;
51
+ }
52
+
53
+ export interface TableGroupByAttribute {
54
+ // OTel attribute key, e.g. "host.name" or "resource.k8s.pod.name".
55
+ key: string;
56
+ // Optional user-friendly header. When unset, the key is shown as-is.
57
+ header?: string | undefined;
58
+ }
59
+
6
60
  export default interface DashboardTableComponent extends BaseComponent {
7
61
  componentType: DashboardComponentType.Table;
8
62
  componentId: ObjectID;
9
63
  arguments: {
10
- metricQueryConfig?: MetricQueryConfigData | undefined;
64
+ // New shape: columns + widget-level group-by.
65
+ columns?: Array<TableColumn> | undefined;
66
+ // New shape — attribute + optional custom header. Source of truth.
67
+ groupByAttributes?: Array<TableGroupByAttribute> | undefined;
68
+ /*
69
+ * Legacy shape from before per-attribute headers. Read at render
70
+ * time if `groupByAttributes` is absent. Never written by the editor.
71
+ */
72
+ groupByAttributeKeys?: Array<string> | undefined;
73
+ // Common display options.
11
74
  tableTitle?: string | undefined;
75
+ tableDescription?: string | undefined;
12
76
  maxRows?: number | undefined;
77
+ reduce?: TableReduce | undefined;
78
+ decimals?: number | undefined;
79
+ /*
80
+ * Legacy widget shape from before the columns/groupByAttributes
81
+ * redesign — read-only at render time, never written by the editor.
82
+ */
83
+ metricQueryConfig?: MetricQueryConfigData | undefined;
84
+ metricQueryConfigs?: Array<MetricQueryConfigData> | undefined;
85
+ metricFormulaConfigs?: Array<MetricFormulaConfigData> | undefined;
13
86
  };
14
87
  }
@@ -5,13 +5,13 @@ import DashboardComponentType from "./DashboardComponentType";
5
5
  import DashboardChartType from "./Chart/ChartType";
6
6
  import ObjectID from "../ObjectID";
7
7
  import DashboardBaseComponent from "./DashboardComponents/DashboardBaseComponent";
8
+ import DashboardVariable, { DashboardVariableType } from "./DashboardVariable";
8
9
  import IconProp from "../Icon/IconProp";
9
10
  import MetricsAggregationType from "../Metrics/MetricsAggregationType";
10
11
  import IncidentMetricType from "../Incident/IncidentMetricType";
11
12
  import MonitorMetricType from "../Monitor/MonitorMetricType";
12
13
  import MetricDashboardMetricType from "../Metrics/MetricDashboardMetricType";
13
14
  import { DashboardValueTrendDirection } from "./DashboardComponents/DashboardValueComponent";
14
- import { HostMetricKind } from "./DashboardComponents/DashboardHostMetricChartComponent";
15
15
 
16
16
  /*
17
17
  * Trace / Exception / Profiles entries are intentionally not in this
@@ -88,6 +88,19 @@ interface MetricConfig {
88
88
  aggregationType: MetricsAggregationType;
89
89
  legend?: string;
90
90
  legendUnit?: string;
91
+ /*
92
+ * OpenTelemetry attribute keys to fan the query out across (e.g.
93
+ * ["host.name"] for one series per host). When set, the chart renders
94
+ * one series per unique value combination.
95
+ */
96
+ groupByAttributeKeys?: Array<string>;
97
+ /*
98
+ * Plot the per-second rate of change instead of the raw cumulative
99
+ * counter. Required for OTel cumulative counters such as
100
+ * `system.disk.io` and `system.network.io` so the chart shows I/O rate
101
+ * rather than bytes-since-boot.
102
+ */
103
+ transformAsRate?: boolean;
91
104
  }
92
105
 
93
106
  function buildMetricQueryConfig(config: MetricConfig): Record<string, unknown> {
@@ -104,8 +117,10 @@ function buildMetricQueryConfig(config: MetricConfig): Record<string, unknown> {
104
117
  metricName: config.metricName,
105
118
  aggegationType: config.aggregationType,
106
119
  },
107
- groupBy: undefined,
120
+ groupBy: config.groupByAttributeKeys ? { attributes: true } : undefined,
121
+ groupByAttributeKeys: config.groupByAttributeKeys,
108
122
  },
123
+ transformAsRate: config.transformAsRate,
109
124
  };
110
125
  }
111
126
 
@@ -383,6 +398,31 @@ function createKubernetesNodeListComponent(data: {
383
398
  };
384
399
  }
385
400
 
401
+ /*
402
+ * Template variables are pre-built TelemetryAttribute variables that
403
+ * ship with the template — the toolbar renders a "Cluster" /
404
+ * "Namespace" / "Host" picker without the user having to open the
405
+ * Variables modal. Resource attributes from the OTel collector are
406
+ * stored in ClickHouse under the `resource.` prefix (see the comment
407
+ * in MonitorAlert.ts), so the binding keys here mirror what the
408
+ * Kubernetes / Host detail pages already filter on.
409
+ */
410
+ function createTelemetryAttributeVariable(data: {
411
+ name: string;
412
+ label: string;
413
+ attributeKey: string;
414
+ isMultiSelect?: boolean;
415
+ }): DashboardVariable {
416
+ return {
417
+ id: ObjectID.generate().toString(),
418
+ name: data.name,
419
+ label: data.label,
420
+ type: DashboardVariableType.TelemetryAttribute,
421
+ attributeKey: data.attributeKey,
422
+ isMultiSelect: data.isMultiSelect ?? false,
423
+ };
424
+ }
425
+
386
426
  function createHostListComponent(data: {
387
427
  title: string;
388
428
  top: number;
@@ -412,33 +452,6 @@ function createHostListComponent(data: {
412
452
  };
413
453
  }
414
454
 
415
- function createHostMetricChartComponent(data: {
416
- title: string;
417
- description?: string;
418
- metricKind: HostMetricKind;
419
- top: number;
420
- left: number;
421
- width: number;
422
- height: number;
423
- }): DashboardBaseComponent {
424
- return {
425
- _type: ObjectType.DashboardComponent,
426
- componentType: DashboardComponentType.HostMetricChart,
427
- componentId: ObjectID.generate(),
428
- topInDashboardUnits: data.top,
429
- leftInDashboardUnits: data.left,
430
- widthInDashboardUnits: data.width,
431
- heightInDashboardUnits: data.height,
432
- minHeightInDashboardUnits: 3,
433
- minWidthInDashboardUnits: 6,
434
- arguments: {
435
- title: data.title,
436
- description: data.description,
437
- metricKind: data.metricKind,
438
- },
439
- };
440
- }
441
-
442
455
  // -- Dashboard configs --
443
456
 
444
457
  function createMonitorDashboardConfig(): DashboardViewConfig {
@@ -630,9 +643,25 @@ function createMonitorDashboardConfig(): DashboardViewConfig {
630
643
  }),
631
644
  ];
632
645
 
646
+ /*
647
+ * Monitor metrics are stored with bare attribute keys (`monitorName`,
648
+ * `probeName`) rather than the OTel `resource.*` prefix — see
649
+ * MonitorMetricUtil.buildAttributes — so the variable binds to the
650
+ * bare key. Multi-select lets users pin a small group of monitors.
651
+ */
652
+ const variables: Array<DashboardVariable> = [
653
+ createTelemetryAttributeVariable({
654
+ name: "monitor",
655
+ label: "Monitor",
656
+ attributeKey: "monitorName",
657
+ isMultiSelect: true,
658
+ }),
659
+ ];
660
+
633
661
  return {
634
662
  _type: ObjectType.DashboardViewConfig,
635
663
  components,
664
+ variables,
636
665
  heightInDashboardUnits: Math.max(DashboardSize.heightInDashboardUnits, 13),
637
666
  };
638
667
  }
@@ -1122,9 +1151,31 @@ function createKubernetesDashboardConfig(): DashboardViewConfig {
1122
1151
  }),
1123
1152
  ];
1124
1153
 
1154
+ /*
1155
+ * Pre-built variables let the user scope every widget on the dashboard
1156
+ * to a single cluster / namespace from the toolbar. Multi-select is on
1157
+ * for namespace so users can pick a couple of namespaces at once;
1158
+ * cluster stays single-select since the typical "compare two clusters"
1159
+ * workflow lives on the Compare page.
1160
+ */
1161
+ const variables: Array<DashboardVariable> = [
1162
+ createTelemetryAttributeVariable({
1163
+ name: "cluster",
1164
+ label: "Cluster",
1165
+ attributeKey: "resource.k8s.cluster.name",
1166
+ }),
1167
+ createTelemetryAttributeVariable({
1168
+ name: "namespace",
1169
+ label: "Namespace",
1170
+ attributeKey: "resource.k8s.namespace.name",
1171
+ isMultiSelect: true,
1172
+ }),
1173
+ ];
1174
+
1125
1175
  return {
1126
1176
  _type: ObjectType.DashboardViewConfig,
1127
1177
  components,
1178
+ variables,
1128
1179
  heightInDashboardUnits: Math.max(DashboardSize.heightInDashboardUnits, 21),
1129
1180
  };
1130
1181
  }
@@ -1442,9 +1493,25 @@ function createMetricsDashboardConfig(): DashboardViewConfig {
1442
1493
  }),
1443
1494
  ];
1444
1495
 
1496
+ /*
1497
+ * Most HTTP / runtime metrics on this dashboard carry the standard
1498
+ * OTel `resource.service.name` attribute, so scoping by service is
1499
+ * the most useful default. Multi-select keeps the cross-service view
1500
+ * available — e.g. compare API and worker on one chart.
1501
+ */
1502
+ const variables: Array<DashboardVariable> = [
1503
+ createTelemetryAttributeVariable({
1504
+ name: "service",
1505
+ label: "Service",
1506
+ attributeKey: "resource.service.name",
1507
+ isMultiSelect: true,
1508
+ }),
1509
+ ];
1510
+
1445
1511
  return {
1446
1512
  _type: ObjectType.DashboardViewConfig,
1447
1513
  components,
1514
+ variables,
1448
1515
  heightInDashboardUnits: Math.max(DashboardSize.heightInDashboardUnits, 24),
1449
1516
  };
1450
1517
  }
@@ -1453,11 +1520,10 @@ function createHostDashboardConfig(): DashboardViewConfig {
1453
1520
  /*
1454
1521
  * Layout notes:
1455
1522
  *
1456
- * - The HostMetricChart widget groups by `host.name` and plots one
1457
- * series per host (or a single series when filtered to one host).
1458
- * The OTel host receiver emits `system.cpu.utilization` and
1459
- * `system.memory.utilization` as [0, 1] ratios, which Value/Gauge
1460
- * widgets auto-scale to percent at render time (see
1523
+ * - Per-host charts fan out via `groupByAttributeKeys: ["host.name"]`
1524
+ * so a single chart renders one series per host. The OTel host
1525
+ * receiver emits `system.cpu.utilization` as a [0, 1] ratio, which
1526
+ * Value/Gauge widgets auto-scale to percent at render time (see
1461
1527
  * splitFormattedValue / isFractionScale).
1462
1528
  *
1463
1529
  * - The Value widget for "Avg Memory" uses `system.memory.usage`
@@ -1465,11 +1531,10 @@ function createHostDashboardConfig(): DashboardViewConfig {
1465
1531
  * `system.memory.utilization` is not always emitted by default OTel
1466
1532
  * host metrics.
1467
1533
  *
1468
- * - Disk and Network I/O Value widgets aggregate the raw byte counters
1469
- * with Sum. HostMetricChart turns these into per-second rates for
1470
- * the chart view; the Value tile shows the unrated total so users
1471
- * reading "Disk I/O" against the time window get an absolute byte
1472
- * figure rather than a noisy snapshot.
1534
+ * - Disk and Network I/O charts set `transformAsRate: true` so the
1535
+ * cumulative byte counters render as per-second rates rather than
1536
+ * bytes-since-boot. The matching Value tiles in row 1 keep the
1537
+ * unrated Sum so users see an absolute byte figure over the window.
1473
1538
  */
1474
1539
  const components: Array<DashboardBaseComponent> = [
1475
1540
  // Row 0: Title
@@ -1529,21 +1594,31 @@ function createHostDashboardConfig(): DashboardViewConfig {
1529
1594
  }),
1530
1595
 
1531
1596
  // Row 2-4: Per-host CPU and Memory charts
1532
- createHostMetricChartComponent({
1597
+ createChartComponent({
1533
1598
  title: "CPU Utilization by Host",
1534
- metricKind: HostMetricKind.CpuUtilization,
1599
+ chartType: DashboardChartType.Line,
1535
1600
  top: 2,
1536
1601
  left: 0,
1537
1602
  width: 6,
1538
1603
  height: 3,
1604
+ metricConfig: {
1605
+ metricName: MetricDashboardMetricType.SystemCpuUtilization,
1606
+ aggregationType: MetricsAggregationType.Avg,
1607
+ groupByAttributeKeys: ["host.name"],
1608
+ },
1539
1609
  }),
1540
- createHostMetricChartComponent({
1610
+ createChartComponent({
1541
1611
  title: "Memory Usage by Host",
1542
- metricKind: HostMetricKind.MemoryUsage,
1612
+ chartType: DashboardChartType.Line,
1543
1613
  top: 2,
1544
1614
  left: 6,
1545
1615
  width: 6,
1546
1616
  height: 3,
1617
+ metricConfig: {
1618
+ metricName: MetricDashboardMetricType.SystemMemoryUsage,
1619
+ aggregationType: MetricsAggregationType.Avg,
1620
+ groupByAttributeKeys: ["host.name"],
1621
+ },
1547
1622
  }),
1548
1623
 
1549
1624
  // Row 5: Section header
@@ -1600,13 +1675,18 @@ function createHostDashboardConfig(): DashboardViewConfig {
1600
1675
  aggregationType: MetricsAggregationType.Avg,
1601
1676
  },
1602
1677
  }),
1603
- createHostMetricChartComponent({
1678
+ createChartComponent({
1604
1679
  title: "Filesystem Usage by Host",
1605
- metricKind: HostMetricKind.Filesystem,
1680
+ chartType: DashboardChartType.Line,
1606
1681
  top: 11,
1607
1682
  left: 4,
1608
1683
  width: 8,
1609
1684
  height: 3,
1685
+ metricConfig: {
1686
+ metricName: "system.filesystem.usage",
1687
+ aggregationType: MetricsAggregationType.Avg,
1688
+ groupByAttributeKeys: ["host.name"],
1689
+ },
1610
1690
  }),
1611
1691
 
1612
1692
  // Row 14: Section header
@@ -1620,21 +1700,33 @@ function createHostDashboardConfig(): DashboardViewConfig {
1620
1700
  }),
1621
1701
 
1622
1702
  // Row 15-17: Disk and network I/O rates per host
1623
- createHostMetricChartComponent({
1703
+ createChartComponent({
1624
1704
  title: "Disk I/O by Host",
1625
- metricKind: HostMetricKind.DiskIo,
1705
+ chartType: DashboardChartType.Line,
1626
1706
  top: 15,
1627
1707
  left: 0,
1628
1708
  width: 6,
1629
1709
  height: 3,
1710
+ metricConfig: {
1711
+ metricName: MetricDashboardMetricType.SystemDiskIo,
1712
+ aggregationType: MetricsAggregationType.Sum,
1713
+ groupByAttributeKeys: ["host.name"],
1714
+ transformAsRate: true,
1715
+ },
1630
1716
  }),
1631
- createHostMetricChartComponent({
1717
+ createChartComponent({
1632
1718
  title: "Network I/O by Host",
1633
- metricKind: HostMetricKind.NetworkIo,
1719
+ chartType: DashboardChartType.Line,
1634
1720
  top: 15,
1635
1721
  left: 6,
1636
1722
  width: 6,
1637
1723
  height: 3,
1724
+ metricConfig: {
1725
+ metricName: MetricDashboardMetricType.SystemNetworkIo,
1726
+ aggregationType: MetricsAggregationType.Sum,
1727
+ groupByAttributeKeys: ["host.name"],
1728
+ transformAsRate: true,
1729
+ },
1638
1730
  }),
1639
1731
 
1640
1732
  // Row 18: Section header
@@ -1648,13 +1740,18 @@ function createHostDashboardConfig(): DashboardViewConfig {
1648
1740
  }),
1649
1741
 
1650
1742
  // Row 19-21: Process count chart and recent logs
1651
- createHostMetricChartComponent({
1743
+ createChartComponent({
1652
1744
  title: "Process Count by Host",
1653
- metricKind: HostMetricKind.ProcessCount,
1745
+ chartType: DashboardChartType.Line,
1654
1746
  top: 19,
1655
1747
  left: 0,
1656
1748
  width: 6,
1657
1749
  height: 3,
1750
+ metricConfig: {
1751
+ metricName: "system.processes.count",
1752
+ aggregationType: MetricsAggregationType.Avg,
1753
+ groupByAttributeKeys: ["host.name"],
1754
+ },
1658
1755
  }),
1659
1756
  createLogStreamComponent({
1660
1757
  title: "Recent Logs",
@@ -1665,9 +1762,25 @@ function createHostDashboardConfig(): DashboardViewConfig {
1665
1762
  }),
1666
1763
  ];
1667
1764
 
1765
+ /*
1766
+ * Per-host scoping: the variable defaults to multi-select because the
1767
+ * dashboard's by-host charts already split rendering per host; the
1768
+ * selector lets users narrow to a subset (e.g. just two prod hosts)
1769
+ * without losing the per-host breakdown.
1770
+ */
1771
+ const variables: Array<DashboardVariable> = [
1772
+ createTelemetryAttributeVariable({
1773
+ name: "host",
1774
+ label: "Host",
1775
+ attributeKey: "resource.host.name",
1776
+ isMultiSelect: true,
1777
+ }),
1778
+ ];
1779
+
1668
1780
  return {
1669
1781
  _type: ObjectType.DashboardViewConfig,
1670
1782
  components,
1783
+ variables,
1671
1784
  heightInDashboardUnits: Math.max(DashboardSize.heightInDashboardUnits, 22),
1672
1785
  };
1673
1786
  }
@@ -83,7 +83,7 @@ export class MonitorTypeHelper {
83
83
  },
84
84
  {
85
85
  label: "Infrastructure",
86
- monitorTypes: [MonitorType.Server, MonitorType.SNMP],
86
+ monitorTypes: [MonitorType.SNMP],
87
87
  },
88
88
  {
89
89
  label: "Kubernetes",
@@ -27,22 +27,49 @@ export const OVERRIDE_META_KEY: string = "_override";
27
27
 
28
28
  export default class UserOverrideUtil {
29
29
  /**
30
- * Returns true when this override should be applied on top of the schedule
31
- * events. Global overrides always apply; policy-scoped overrides apply to
32
- * any schedule, since a schedule's calendar shows coverage information for
33
- * every user who could potentially be paged through it.
30
+ * Decides whether an override should affect resolution for a given policy
31
+ * context. Global overrides (no policy id) always apply. Policy-scoped
32
+ * overrides only apply when their policy matches the caller's policy.
33
+ * When the caller has no policy context, only global overrides apply.
34
34
  */
35
- public static isOverrideApplicable(_override: UserOverrideRecord): boolean {
36
- return true;
35
+ public static isOverrideApplicable(
36
+ override: UserOverrideRecord,
37
+ currentOnCallDutyPolicyId?: string | null | undefined,
38
+ ): boolean {
39
+ if (!override.onCallDutyPolicyId) {
40
+ return true;
41
+ }
42
+
43
+ if (!currentOnCallDutyPolicyId) {
44
+ return false;
45
+ }
46
+
47
+ return override.onCallDutyPolicyId === currentOnCallDutyPolicyId;
37
48
  }
38
49
 
39
50
  public static applyOverridesToEvents(data: {
40
51
  events: Array<CalendarEvent>;
41
52
  overrides: Array<UserOverrideRecord>;
53
+ currentOnCallDutyPolicyId?: string | null | undefined;
42
54
  }): Array<CalendarEvent> {
43
- const applicable: Array<UserOverrideRecord> = data.overrides.filter(
44
- UserOverrideUtil.isOverrideApplicable,
45
- );
55
+ const applicable: Array<UserOverrideRecord> = data.overrides
56
+ .filter((o: UserOverrideRecord) => {
57
+ return UserOverrideUtil.isOverrideApplicable(
58
+ o,
59
+ data.currentOnCallDutyPolicyId,
60
+ );
61
+ })
62
+ /*
63
+ * Apply policy-specific overrides before globals so that when both
64
+ * target the same user/window, the policy-specific substitution wins.
65
+ * splitEventByOverride only matches on the original user id, so the
66
+ * first override that consumes a segment claims it.
67
+ */
68
+ .sort((a: UserOverrideRecord, b: UserOverrideRecord) => {
69
+ const aPolicyScoped: number = a.onCallDutyPolicyId ? 0 : 1;
70
+ const bPolicyScoped: number = b.onCallDutyPolicyId ? 0 : 1;
71
+ return aPolicyScoped - bPolicyScoped;
72
+ });
46
73
 
47
74
  if (applicable.length === 0) {
48
75
  return data.events;
@@ -1124,11 +1124,6 @@ enum Permission {
1124
1124
  EditService = "EditService",
1125
1125
  ReadService = "ReadService",
1126
1126
 
1127
- CreateServiceDependency = "CreateServiceDependency",
1128
- DeleteServiceDependency = "DeleteServiceDependency",
1129
- EditServiceDependency = "EditServiceDependency",
1130
- ReadServiceDependency = "ReadServiceDependency",
1131
-
1132
1127
  CreateServiceMonitor = "CreateServiceMonitor",
1133
1128
  DeleteServiceMonitor = "DeleteServiceMonitor",
1134
1129
  EditServiceMonitor = "EditServiceMonitor",
@@ -7528,47 +7523,6 @@ export class PermissionHelper {
7528
7523
  group: PermissionGroup.ServiceCatalog,
7529
7524
  },
7530
7525
 
7531
- {
7532
- permission: Permission.CreateServiceDependency,
7533
- title: "Create Service Dependency",
7534
- description:
7535
- "This permission can create Service Dependencies in this project.",
7536
- isAssignableToTenant: true,
7537
- isAccessControlPermission: false,
7538
- isRolePermission: false,
7539
- group: PermissionGroup.ServiceCatalog,
7540
- },
7541
- {
7542
- permission: Permission.DeleteServiceDependency,
7543
- title: "Delete Service Dependency",
7544
- description:
7545
- "This permission can delete Service Dependencies of this project.",
7546
- isAssignableToTenant: true,
7547
- isAccessControlPermission: false,
7548
- isRolePermission: false,
7549
- group: PermissionGroup.ServiceCatalog,
7550
- },
7551
- {
7552
- permission: Permission.EditServiceDependency,
7553
- title: "Edit Service Dependency",
7554
- description:
7555
- "This permission can edit Service Dependencies of this project.",
7556
- isAssignableToTenant: true,
7557
- isAccessControlPermission: false,
7558
- isRolePermission: false,
7559
- group: PermissionGroup.ServiceCatalog,
7560
- },
7561
- {
7562
- permission: Permission.ReadServiceDependency,
7563
- title: "Read Service Dependency",
7564
- description:
7565
- "This permission can read Service Dependencies of this project.",
7566
- isAssignableToTenant: true,
7567
- isAccessControlPermission: false,
7568
- isRolePermission: false,
7569
- group: PermissionGroup.ServiceCatalog,
7570
- },
7571
-
7572
7526
  {
7573
7527
  permission: Permission.CreateServiceMonitor,
7574
7528
  title: "Create Service Monitor",