@oneuptime/common 10.0.65 → 10.0.66

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 (210) hide show
  1. package/Models/DatabaseModels/DockerHostOwnerTeam.ts +464 -0
  2. package/Models/DatabaseModels/DockerHostOwnerUser.ts +463 -0
  3. package/Models/DatabaseModels/Index.ts +24 -0
  4. package/Models/DatabaseModels/KubernetesClusterOwnerTeam.ts +464 -0
  5. package/Models/DatabaseModels/KubernetesClusterOwnerUser.ts +463 -0
  6. package/Models/DatabaseModels/KubernetesResource.ts +548 -0
  7. package/Models/DatabaseModels/MetricPipelineRule.ts +804 -0
  8. package/Models/DatabaseModels/MetricRecordingRule.ts +470 -0
  9. package/Models/DatabaseModels/Monitor.ts +2 -0
  10. package/Models/DatabaseModels/Project.ts +53 -0
  11. package/Models/DatabaseModels/Service.ts +79 -0
  12. package/Models/DatabaseModels/TraceDropFilter.ts +508 -0
  13. package/Models/DatabaseModels/TracePipeline.ts +436 -0
  14. package/Models/DatabaseModels/TracePipelineProcessor.ts +454 -0
  15. package/Models/DatabaseModels/TraceRecordingRule.ts +470 -0
  16. package/Models/DatabaseModels/TraceScrubRule.ts +546 -0
  17. package/Server/API/KubernetesResourceAPI.ts +129 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.ts +399 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.ts +205 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.ts +335 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.ts +29 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.ts +53 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -1
  24. package/Server/Services/DockerHostOwnerTeamService.ts +10 -0
  25. package/Server/Services/DockerHostOwnerUserService.ts +10 -0
  26. package/Server/Services/KubernetesClusterOwnerTeamService.ts +10 -0
  27. package/Server/Services/KubernetesClusterOwnerUserService.ts +10 -0
  28. package/Server/Services/KubernetesResourceService.ts +351 -0
  29. package/Server/Services/MetricPipelineRuleService.ts +10 -0
  30. package/Server/Services/MetricRecordingRuleService.ts +10 -0
  31. package/Server/Services/TraceDropFilterService.ts +10 -0
  32. package/Server/Services/TracePipelineProcessorService.ts +10 -0
  33. package/Server/Services/TracePipelineService.ts +10 -0
  34. package/Server/Services/TraceRecordingRuleService.ts +10 -0
  35. package/Server/Services/TraceScrubRuleService.ts +10 -0
  36. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +71 -9
  37. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +483 -75
  38. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +379 -6
  39. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +502 -0
  40. package/Tests/Utils/MetricUnitUtil.test.ts +216 -0
  41. package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +269 -0
  42. package/Tests/Utils/Metrics/MetricResultUnitConverter.test.ts +231 -0
  43. package/Tests/Utils/RecordingRuleExpression.test.ts +177 -0
  44. package/Types/Kubernetes/KubernetesInventoryExtractor.ts +327 -0
  45. package/Types/Kubernetes/KubernetesObjectParser.ts +1949 -0
  46. package/Types/Metrics/MetricDownsamplingRetentionDays.ts +49 -0
  47. package/Types/Metrics/MetricFormulaConfigData.ts +4 -0
  48. package/Types/Metrics/MetricPipelineRuleFilterCondition.ts +136 -0
  49. package/Types/Metrics/MetricPipelineRuleType.ts +27 -0
  50. package/Types/Metrics/RecordingRuleDefinition.ts +180 -0
  51. package/Types/Monitor/CriteriaFilter.ts +43 -0
  52. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +70 -0
  53. package/Types/Permission.ts +520 -0
  54. package/Types/Trace/TraceAggregationType.ts +17 -0
  55. package/Types/Trace/TraceDropFilterAction.ts +6 -0
  56. package/Types/Trace/TracePipelineProcessorType.ts +56 -0
  57. package/Types/Trace/TraceRecordingRuleDefinition.ts +218 -0
  58. package/Types/Trace/TraceScrubAction.ts +7 -0
  59. package/Types/Trace/TraceScrubField.ts +8 -0
  60. package/Types/Trace/TraceScrubPatternType.ts +10 -0
  61. package/UI/Components/CardSelect/CardSelect.tsx +9 -1
  62. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +6 -10
  63. package/UI/Components/Forms/Fields/FormField.tsx +1 -0
  64. package/UI/Components/Forms/Types/Field.ts +1 -0
  65. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +57 -0
  66. package/UI/Components/Page/Page.tsx +6 -0
  67. package/Utils/MetricUnitUtil.ts +289 -0
  68. package/Utils/Metrics/MetricFormulaEvaluator.ts +610 -0
  69. package/Utils/Metrics/MetricResultUnitConverter.ts +91 -0
  70. package/Utils/Metrics/RecordingRuleExpression.ts +359 -0
  71. package/Utils/ValueFormatter.ts +137 -13
  72. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js +480 -0
  73. package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js.map +1 -0
  74. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js +479 -0
  75. package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js.map +1 -0
  76. package/build/dist/Models/DatabaseModels/Index.js +24 -0
  77. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  78. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js +480 -0
  79. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js.map +1 -0
  80. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js +479 -0
  81. package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js.map +1 -0
  82. package/build/dist/Models/DatabaseModels/KubernetesResource.js +590 -0
  83. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -0
  84. package/build/dist/Models/DatabaseModels/MetricPipelineRule.js +836 -0
  85. package/build/dist/Models/DatabaseModels/MetricPipelineRule.js.map +1 -0
  86. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js +497 -0
  87. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js.map +1 -0
  88. package/build/dist/Models/DatabaseModels/Monitor.js +2 -0
  89. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  90. package/build/dist/Models/DatabaseModels/Project.js +53 -0
  91. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  92. package/build/dist/Models/DatabaseModels/Service.js +79 -0
  93. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  94. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +536 -0
  95. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -0
  96. package/build/dist/Models/DatabaseModels/TracePipeline.js +462 -0
  97. package/build/dist/Models/DatabaseModels/TracePipeline.js.map +1 -0
  98. package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js +476 -0
  99. package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js.map +1 -0
  100. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js +497 -0
  101. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js.map +1 -0
  102. package/build/dist/Models/DatabaseModels/TraceScrubRule.js +575 -0
  103. package/build/dist/Models/DatabaseModels/TraceScrubRule.js.map +1 -0
  104. package/build/dist/Server/API/KubernetesResourceAPI.js +98 -0
  105. package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -0
  106. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js +144 -0
  107. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js.map +1 -0
  108. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js +82 -0
  109. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js.map +1 -0
  110. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js +118 -0
  111. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js.map +1 -0
  112. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js +16 -0
  113. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js.map +1 -0
  114. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js +24 -0
  115. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js.map +1 -0
  116. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  117. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  118. package/build/dist/Server/Services/DockerHostOwnerTeamService.js +9 -0
  119. package/build/dist/Server/Services/DockerHostOwnerTeamService.js.map +1 -0
  120. package/build/dist/Server/Services/DockerHostOwnerUserService.js +9 -0
  121. package/build/dist/Server/Services/DockerHostOwnerUserService.js.map +1 -0
  122. package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js +9 -0
  123. package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js.map +1 -0
  124. package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js +9 -0
  125. package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js.map +1 -0
  126. package/build/dist/Server/Services/KubernetesResourceService.js +237 -0
  127. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -0
  128. package/build/dist/Server/Services/MetricPipelineRuleService.js +9 -0
  129. package/build/dist/Server/Services/MetricPipelineRuleService.js.map +1 -0
  130. package/build/dist/Server/Services/MetricRecordingRuleService.js +9 -0
  131. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -0
  132. package/build/dist/Server/Services/TraceDropFilterService.js +9 -0
  133. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -0
  134. package/build/dist/Server/Services/TracePipelineProcessorService.js +9 -0
  135. package/build/dist/Server/Services/TracePipelineProcessorService.js.map +1 -0
  136. package/build/dist/Server/Services/TracePipelineService.js +9 -0
  137. package/build/dist/Server/Services/TracePipelineService.js.map +1 -0
  138. package/build/dist/Server/Services/TraceRecordingRuleService.js +9 -0
  139. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -0
  140. package/build/dist/Server/Services/TraceScrubRuleService.js +9 -0
  141. package/build/dist/Server/Services/TraceScrubRuleService.js.map +1 -0
  142. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +56 -9
  143. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  144. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +335 -53
  145. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  146. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +277 -5
  147. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  148. package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js +407 -0
  149. package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js.map +1 -0
  150. package/build/dist/Tests/Utils/MetricUnitUtil.test.js +159 -0
  151. package/build/dist/Tests/Utils/MetricUnitUtil.test.js.map +1 -0
  152. package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js +224 -0
  153. package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js.map +1 -0
  154. package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js +180 -0
  155. package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js.map +1 -0
  156. package/build/dist/Tests/Utils/RecordingRuleExpression.test.js +142 -0
  157. package/build/dist/Tests/Utils/RecordingRuleExpression.test.js.map +1 -0
  158. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js +200 -0
  159. package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js.map +1 -0
  160. package/build/dist/Types/Kubernetes/KubernetesObjectParser.js +1205 -0
  161. package/build/dist/Types/Kubernetes/KubernetesObjectParser.js.map +1 -0
  162. package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js +32 -0
  163. package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js.map +1 -0
  164. package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js +103 -0
  165. package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js.map +1 -0
  166. package/build/dist/Types/Metrics/MetricPipelineRuleType.js +27 -0
  167. package/build/dist/Types/Metrics/MetricPipelineRuleType.js.map +1 -0
  168. package/build/dist/Types/Metrics/RecordingRuleDefinition.js +110 -0
  169. package/build/dist/Types/Metrics/RecordingRuleDefinition.js.map +1 -0
  170. package/build/dist/Types/Monitor/CriteriaFilter.js +22 -0
  171. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  172. package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js +2 -0
  173. package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js.map +1 -0
  174. package/build/dist/Types/Permission.js +454 -0
  175. package/build/dist/Types/Permission.js.map +1 -1
  176. package/build/dist/Types/Trace/TraceAggregationType.js +18 -0
  177. package/build/dist/Types/Trace/TraceAggregationType.js.map +1 -0
  178. package/build/dist/Types/Trace/TraceDropFilterAction.js +7 -0
  179. package/build/dist/Types/Trace/TraceDropFilterAction.js.map +1 -0
  180. package/build/dist/Types/Trace/TracePipelineProcessorType.js +10 -0
  181. package/build/dist/Types/Trace/TracePipelineProcessorType.js.map +1 -0
  182. package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js +145 -0
  183. package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js.map +1 -0
  184. package/build/dist/Types/Trace/TraceScrubAction.js +8 -0
  185. package/build/dist/Types/Trace/TraceScrubAction.js.map +1 -0
  186. package/build/dist/Types/Trace/TraceScrubField.js +9 -0
  187. package/build/dist/Types/Trace/TraceScrubField.js.map +1 -0
  188. package/build/dist/Types/Trace/TraceScrubPatternType.js +11 -0
  189. package/build/dist/Types/Trace/TraceScrubPatternType.js.map +1 -0
  190. package/build/dist/UI/Components/CardSelect/CardSelect.js +3 -1
  191. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -9
  193. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  194. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  195. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  196. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +30 -0
  197. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  198. package/build/dist/UI/Components/Page/Page.js +1 -0
  199. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  200. package/build/dist/Utils/MetricUnitUtil.js +232 -0
  201. package/build/dist/Utils/MetricUnitUtil.js.map +1 -0
  202. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +453 -0
  203. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -0
  204. package/build/dist/Utils/Metrics/MetricResultUnitConverter.js +61 -0
  205. package/build/dist/Utils/Metrics/MetricResultUnitConverter.js.map +1 -0
  206. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +298 -0
  207. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -0
  208. package/build/dist/Utils/ValueFormatter.js +123 -13
  209. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  210. package/package.json +1 -1
@@ -0,0 +1,218 @@
1
+ import TraceAggregationType from "./TraceAggregationType";
2
+
3
+ /*
4
+ * A single source for a Trace Recording Rule — queries the Span table with
5
+ * the given aggregation, filtered by optional span-name regex and attribute
6
+ * match. Each source is aliased (A, B, C, ...) and referenced from the rule's
7
+ * expression string.
8
+ */
9
+ export interface TraceRecordingRuleSource {
10
+ alias: string;
11
+ aggregationType: TraceAggregationType;
12
+ // Optional filters — ANDed together.
13
+ spanNameRegex?: string;
14
+ spanKind?: string;
15
+ onlyErrors?: boolean;
16
+ filterAttributeKey?: string;
17
+ filterAttributeValue?: string;
18
+ }
19
+
20
+ /*
21
+ * Full stored definition of a Trace Recording Rule. Persisted as JSONB so new
22
+ * fields can be added without migrating Postgres.
23
+ */
24
+ export default interface TraceRecordingRuleDefinition {
25
+ sources: Array<TraceRecordingRuleSource>;
26
+ /*
27
+ * Arithmetic expression using aliases. Operators: + - * /, parentheses,
28
+ * numeric literals. Example: "A / B * 100" for error rate.
29
+ */
30
+ expression: string;
31
+ /*
32
+ * Optional attribute key (e.g. "service.name") to group by — one derived
33
+ * data point per group per evaluation bucket.
34
+ */
35
+ groupByAttribute?: string;
36
+ }
37
+
38
+ // Maximum number of sources per rule — bounds per-cron workload.
39
+ export const TRACE_RECORDING_RULE_MAX_SOURCES: number = 4;
40
+
41
+ // Maximum expression length — prevents pathological parser input.
42
+ export const TRACE_RECORDING_RULE_MAX_EXPRESSION_LENGTH: number = 500;
43
+
44
+ /*
45
+ * Alphabet used to generate source aliases. v1 caps at TRACE_RECORDING_RULE_MAX_SOURCES
46
+ * so we never exceed the first few letters in practice.
47
+ */
48
+ const ALIAS_ALPHABET: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
49
+
50
+ const ALIAS_REGEX: RegExp = /^[A-Z]$/;
51
+
52
+ const EXPRESSION_REGEX: RegExp = /^[A-Z0-9+\-*/().\s]+$/;
53
+
54
+ export class TraceRecordingRuleDefinitionUtil {
55
+ public static getAggregationOptions(): Array<{
56
+ value: TraceAggregationType;
57
+ label: string;
58
+ description: string;
59
+ }> {
60
+ return [
61
+ {
62
+ value: TraceAggregationType.Count,
63
+ label: "Count",
64
+ description: "Number of matching spans.",
65
+ },
66
+ {
67
+ value: TraceAggregationType.ErrorCount,
68
+ label: "Error Count",
69
+ description: "Spans with status = error.",
70
+ },
71
+ {
72
+ value: TraceAggregationType.AvgDurationSeconds,
73
+ label: "Avg Duration (s)",
74
+ description: "Average span duration in seconds.",
75
+ },
76
+ {
77
+ value: TraceAggregationType.P50DurationSeconds,
78
+ label: "p50 Duration (s)",
79
+ description: "Median span duration.",
80
+ },
81
+ {
82
+ value: TraceAggregationType.P95DurationSeconds,
83
+ label: "p95 Duration (s)",
84
+ description: "95th percentile span duration.",
85
+ },
86
+ {
87
+ value: TraceAggregationType.P99DurationSeconds,
88
+ label: "p99 Duration (s)",
89
+ description: "99th percentile span duration.",
90
+ },
91
+ {
92
+ value: TraceAggregationType.MaxDurationSeconds,
93
+ label: "Max Duration (s)",
94
+ description: "Longest span in the bucket.",
95
+ },
96
+ {
97
+ value: TraceAggregationType.MinDurationSeconds,
98
+ label: "Min Duration (s)",
99
+ description: "Shortest span in the bucket.",
100
+ },
101
+ ];
102
+ }
103
+
104
+ public static getSpanKindOptions(): Array<{ value: string; label: string }> {
105
+ return [
106
+ { value: "", label: "Any" },
107
+ { value: "SPAN_KIND_SERVER", label: "Server" },
108
+ { value: "SPAN_KIND_CLIENT", label: "Client" },
109
+ { value: "SPAN_KIND_PRODUCER", label: "Producer" },
110
+ { value: "SPAN_KIND_CONSUMER", label: "Consumer" },
111
+ { value: "SPAN_KIND_INTERNAL", label: "Internal" },
112
+ ];
113
+ }
114
+
115
+ public static getNextAlias(
116
+ sources: Array<TraceRecordingRuleSource> | undefined,
117
+ ): string {
118
+ const used: Set<string> = new Set<string>(
119
+ (sources || []).map((s: TraceRecordingRuleSource) => {
120
+ return s.alias;
121
+ }),
122
+ );
123
+ for (const letter of ALIAS_ALPHABET) {
124
+ if (!used.has(letter)) {
125
+ return letter;
126
+ }
127
+ }
128
+ return "A";
129
+ }
130
+
131
+ public static getEmptyDefinition(): TraceRecordingRuleDefinition {
132
+ return {
133
+ sources: [
134
+ {
135
+ alias: "A",
136
+ aggregationType: TraceAggregationType.Count,
137
+ },
138
+ ],
139
+ expression: "A",
140
+ groupByAttribute: "",
141
+ };
142
+ }
143
+
144
+ public static getValidationError(
145
+ definition: TraceRecordingRuleDefinition | undefined,
146
+ ): string | null {
147
+ if (!definition) {
148
+ return "Definition is required.";
149
+ }
150
+
151
+ const sources: Array<TraceRecordingRuleSource> = definition.sources || [];
152
+
153
+ if (sources.length === 0) {
154
+ return "Add at least one source.";
155
+ }
156
+
157
+ if (sources.length > TRACE_RECORDING_RULE_MAX_SOURCES) {
158
+ return `A rule can reference at most ${TRACE_RECORDING_RULE_MAX_SOURCES} sources.`;
159
+ }
160
+
161
+ const aliases: Set<string> = new Set<string>();
162
+ for (let i: number = 0; i < sources.length; i++) {
163
+ const source: TraceRecordingRuleSource = sources[i]!;
164
+ const prefix: string = `Source ${source.alias || `#${i + 1}`}: `;
165
+
166
+ if (!source.alias || !ALIAS_REGEX.test(source.alias)) {
167
+ return `${prefix}Alias must be a single uppercase letter A-Z.`;
168
+ }
169
+
170
+ if (aliases.has(source.alias)) {
171
+ return `${prefix}Duplicate alias. Each source must have a unique letter.`;
172
+ }
173
+ aliases.add(source.alias);
174
+
175
+ if (!source.aggregationType) {
176
+ return `${prefix}Aggregation type is required.`;
177
+ }
178
+
179
+ const hasFilterKey: boolean = Boolean(source.filterAttributeKey?.trim());
180
+ const hasFilterValue: boolean = Boolean(
181
+ source.filterAttributeValue?.trim(),
182
+ );
183
+
184
+ if (hasFilterKey !== hasFilterValue) {
185
+ return `${prefix}Attribute filter needs both a key and a value (or leave both empty).`;
186
+ }
187
+ }
188
+
189
+ const expression: string = (definition.expression || "").trim();
190
+
191
+ if (!expression) {
192
+ return "Expression is required.";
193
+ }
194
+
195
+ if (expression.length > TRACE_RECORDING_RULE_MAX_EXPRESSION_LENGTH) {
196
+ return `Expression must be ${TRACE_RECORDING_RULE_MAX_EXPRESSION_LENGTH} characters or fewer.`;
197
+ }
198
+
199
+ const referencedAliases: Set<string> = new Set<string>(
200
+ expression.match(/[A-Z]/g) || [],
201
+ );
202
+ for (const alias of referencedAliases) {
203
+ if (!aliases.has(alias)) {
204
+ return `Expression references alias '${alias}' which is not defined in sources.`;
205
+ }
206
+ }
207
+
208
+ if (referencedAliases.size === 0) {
209
+ return "Expression must reference at least one source alias (e.g. A, B).";
210
+ }
211
+
212
+ if (!EXPRESSION_REGEX.test(expression)) {
213
+ return "Expression may only contain aliases (A-Z), numbers, operators (+ - * /), parentheses, and spaces.";
214
+ }
215
+
216
+ return null;
217
+ }
218
+ }
@@ -0,0 +1,7 @@
1
+ enum TraceScrubAction {
2
+ Mask = "mask",
3
+ Hash = "hash",
4
+ Redact = "redact",
5
+ }
6
+
7
+ export default TraceScrubAction;
@@ -0,0 +1,8 @@
1
+ enum TraceScrubField {
2
+ Name = "name",
3
+ Attributes = "attributes",
4
+ Events = "events",
5
+ All = "all",
6
+ }
7
+
8
+ export default TraceScrubField;
@@ -0,0 +1,10 @@
1
+ enum TraceScrubPatternType {
2
+ Email = "email",
3
+ CreditCard = "creditCard",
4
+ SSN = "ssn",
5
+ PhoneNumber = "phoneNumber",
6
+ IPAddress = "ipAddress",
7
+ Custom = "custom",
8
+ }
9
+
10
+ export default TraceScrubPatternType;
@@ -30,6 +30,8 @@ export interface ComponentProps {
30
30
  error?: string | undefined;
31
31
  tabIndex?: number | undefined;
32
32
  dataTestId?: string | undefined;
33
+ // Force single-column (1 item per row). Default: responsive 1/2/3 grid.
34
+ singleColumn?: boolean | undefined;
33
35
  }
34
36
 
35
37
  interface RenderGroup {
@@ -84,7 +86,13 @@ const CardSelect: FunctionComponent<ComponentProps> = (
84
86
  </div>
85
87
  </div>
86
88
  )}
87
- <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
89
+ <div
90
+ className={
91
+ props.singleColumn
92
+ ? "grid grid-cols-1 gap-4"
93
+ : "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
94
+ }
95
+ >
88
96
  {group.options.map((option: CardSelectOption) => {
89
97
  const isSelected: boolean = props.value === option.value;
90
98
  const currentIndex: number = cardIndex++;
@@ -52,10 +52,6 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
52
52
  const [metricInfoModalChart, setMetricInfoModalChart] =
53
53
  useState<ChartMetricInfo | null>(null);
54
54
 
55
- const isLastChart: (index: number) => boolean = (index: number): boolean => {
56
- return index === props.charts.length - 1;
57
- };
58
-
59
55
  type GetChartContentFunction = (chart: Chart, index: number) => ReactElement;
60
56
 
61
57
  const getChartContent: GetChartContentFunction = (
@@ -222,23 +218,23 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
222
218
  return (
223
219
  <>
224
220
  {renderMetricInfoModal()}
225
- <div className="space-y-0">
221
+ <div className="space-y-3">
226
222
  {props.charts.map((chart: Chart, index: number) => {
227
223
  return (
228
224
  <div
229
225
  key={index}
230
- className={`${!isLastChart(index) ? "border-b border-gray-100" : ""} ${props.chartCssClass || ""}`}
226
+ className={`bg-white ${props.chartCssClass || ""}`}
231
227
  >
232
- <div className="px-1 pt-5 pb-4">
233
- <div className="mb-1">
228
+ <div className="px-5 pt-4 pb-4">
229
+ <div className="mb-3 pb-3 border-b border-gray-100">
234
230
  <div className="flex items-center">
235
- <h3 className="text-sm font-semibold text-gray-700 tracking-tight">
231
+ <h3 className="text-sm font-semibold text-gray-800 tracking-tight">
236
232
  {chart.title}
237
233
  </h3>
238
234
  {getInfoIcon(chart)}
239
235
  </div>
240
236
  {chart.description && (
241
- <p className="mt-0.5 text-xs text-gray-400 hidden md:block">
237
+ <p className="mt-1 text-xs text-gray-500 hidden md:block">
242
238
  {chart.description}
243
239
  </p>
244
240
  )}
@@ -417,6 +417,7 @@ const FormField: <T extends GenericObject>(
417
417
  error={props.touched && props.error ? props.error : undefined}
418
418
  tabIndex={index}
419
419
  dataTestId={props.field.dataTestId}
420
+ singleColumn={props.field.cardSelectSingleColumn}
420
421
  onChange={(value: string) => {
421
422
  onChange(value);
422
423
  props.setFieldValue(props.fieldName, value);
@@ -57,6 +57,7 @@ export default interface Field<TEntity> {
57
57
  cardSelectOptions?:
58
58
  | Array<CardSelectOption | CardSelectOptionGroup>
59
59
  | undefined;
60
+ cardSelectSingleColumn?: boolean | undefined;
60
61
  fetchDropdownOptions?:
61
62
  | ((
62
63
  item: FormValues<TEntity>,
@@ -69,6 +69,16 @@ SyntaxHighlighter.registerLanguage("graphql", graphql);
69
69
  SyntaxHighlighter.registerLanguage("http", http);
70
70
  import mermaid from "mermaid";
71
71
  import DOMPurify from "dompurify";
72
+ import OneUptimeDate from "../../../Types/Date";
73
+
74
+ /*
75
+ * ISO 8601 timestamps produced by OneUptimeDate.toString() — the
76
+ * backend-generated root cause markdown inline-codes every timestamp so
77
+ * we can localize it here without needing a custom markdown plugin.
78
+ * Matches e.g. "2026-04-20T11:21:00.000Z" (Z-terminated, with ms).
79
+ */
80
+ const ISO_8601_REGEX: RegExp =
81
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/;
72
82
 
73
83
  // Initialize mermaid
74
84
  mermaid.initialize({
@@ -268,6 +278,44 @@ const CodeBlock: FunctionComponent<{
268
278
  );
269
279
  };
270
280
 
281
+ /**
282
+ * Render an ISO 8601 timestamp in the viewer's local timezone, with the
283
+ * canonical UTC instant preserved in the `title` for hover/accessibility.
284
+ * Falls back to the raw string if the date fails to parse so we never
285
+ * render "Invalid Date" in a markdown cell.
286
+ */
287
+ const LocalTime: FunctionComponent<{ isoValue: string }> = ({
288
+ isoValue,
289
+ }: {
290
+ isoValue: string;
291
+ }): ReactElement => {
292
+ const parsed: Date = new Date(isoValue);
293
+ if (isNaN(parsed.getTime())) {
294
+ return (
295
+ <code className="text-xs px-1.5 py-0.5 bg-gray-100 border border-gray-200 rounded text-gray-800 font-mono">
296
+ {isoValue}
297
+ </code>
298
+ );
299
+ }
300
+
301
+ const localFormatted: string = OneUptimeDate.getDateAsLocalFormattedString(
302
+ parsed,
303
+ false,
304
+ true,
305
+ true,
306
+ );
307
+
308
+ return (
309
+ <time
310
+ dateTime={isoValue}
311
+ title={`${isoValue} (UTC)`}
312
+ className="text-xs px-1.5 py-0.5 bg-gray-100 border border-gray-200 rounded text-gray-800 font-mono whitespace-nowrap"
313
+ >
314
+ {localFormatted}
315
+ </time>
316
+ );
317
+ };
318
+
271
319
  const MarkdownViewer: FunctionComponent<ComponentProps> = (
272
320
  props: ComponentProps,
273
321
  ): ReactElement => {
@@ -496,6 +544,15 @@ const MarkdownViewer: FunctionComponent<ComponentProps> = (
496
544
  );
497
545
  }
498
546
 
547
+ /*
548
+ * Inline ISO 8601 timestamp → render in the viewer's local
549
+ * timezone. The backend emits every root-cause timestamp in
550
+ * this format precisely so it can be re-localized here.
551
+ */
552
+ if (ISO_8601_REGEX.test(content)) {
553
+ return <LocalTime isoValue={content} />;
554
+ }
555
+
499
556
  // Inline code
500
557
  return (
501
558
  <code
@@ -16,6 +16,7 @@ export interface ComponentProps {
16
16
  isLoading?: boolean | undefined;
17
17
  error?: string | undefined;
18
18
  labels?: Array<LabelModel> | undefined;
19
+ headerRight?: ReactElement | undefined;
19
20
  }
20
21
 
21
22
  const Page: FunctionComponent<ComponentProps> = (
@@ -62,6 +63,11 @@ const Page: FunctionComponent<ComponentProps> = (
62
63
  {props.title}
63
64
  </h1>
64
65
  </div>
66
+ {props.headerRight && (
67
+ <div className="flex flex-wrap items-center sm:justify-end gap-3">
68
+ {props.headerRight}
69
+ </div>
70
+ )}
65
71
  {props.labels && props.labels.length > 0 && (
66
72
  <div className="hidden sm:flex sm:flex-wrap sm:items-center sm:justify-end sm:gap-3">
67
73
  <span className="text-xs font-semibold uppercase tracking-wide text-gray-500 whitespace-nowrap">