@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.
- package/Models/DatabaseModels/DockerHostOwnerTeam.ts +464 -0
- package/Models/DatabaseModels/DockerHostOwnerUser.ts +463 -0
- package/Models/DatabaseModels/Index.ts +24 -0
- package/Models/DatabaseModels/KubernetesClusterOwnerTeam.ts +464 -0
- package/Models/DatabaseModels/KubernetesClusterOwnerUser.ts +463 -0
- package/Models/DatabaseModels/KubernetesResource.ts +548 -0
- package/Models/DatabaseModels/MetricPipelineRule.ts +804 -0
- package/Models/DatabaseModels/MetricRecordingRule.ts +470 -0
- package/Models/DatabaseModels/Monitor.ts +2 -0
- package/Models/DatabaseModels/Project.ts +53 -0
- package/Models/DatabaseModels/Service.ts +79 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +508 -0
- package/Models/DatabaseModels/TracePipeline.ts +436 -0
- package/Models/DatabaseModels/TracePipelineProcessor.ts +454 -0
- package/Models/DatabaseModels/TraceRecordingRule.ts +470 -0
- package/Models/DatabaseModels/TraceScrubRule.ts +546 -0
- package/Server/API/KubernetesResourceAPI.ts +129 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.ts +399 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.ts +205 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.ts +335 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.ts +53 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -1
- package/Server/Services/DockerHostOwnerTeamService.ts +10 -0
- package/Server/Services/DockerHostOwnerUserService.ts +10 -0
- package/Server/Services/KubernetesClusterOwnerTeamService.ts +10 -0
- package/Server/Services/KubernetesClusterOwnerUserService.ts +10 -0
- package/Server/Services/KubernetesResourceService.ts +351 -0
- package/Server/Services/MetricPipelineRuleService.ts +10 -0
- package/Server/Services/MetricRecordingRuleService.ts +10 -0
- package/Server/Services/TraceDropFilterService.ts +10 -0
- package/Server/Services/TracePipelineProcessorService.ts +10 -0
- package/Server/Services/TracePipelineService.ts +10 -0
- package/Server/Services/TraceRecordingRuleService.ts +10 -0
- package/Server/Services/TraceScrubRuleService.ts +10 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +71 -9
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +483 -75
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +379 -6
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +502 -0
- package/Tests/Utils/MetricUnitUtil.test.ts +216 -0
- package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +269 -0
- package/Tests/Utils/Metrics/MetricResultUnitConverter.test.ts +231 -0
- package/Tests/Utils/RecordingRuleExpression.test.ts +177 -0
- package/Types/Kubernetes/KubernetesInventoryExtractor.ts +327 -0
- package/Types/Kubernetes/KubernetesObjectParser.ts +1949 -0
- package/Types/Metrics/MetricDownsamplingRetentionDays.ts +49 -0
- package/Types/Metrics/MetricFormulaConfigData.ts +4 -0
- package/Types/Metrics/MetricPipelineRuleFilterCondition.ts +136 -0
- package/Types/Metrics/MetricPipelineRuleType.ts +27 -0
- package/Types/Metrics/RecordingRuleDefinition.ts +180 -0
- package/Types/Monitor/CriteriaFilter.ts +43 -0
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +70 -0
- package/Types/Permission.ts +520 -0
- package/Types/Trace/TraceAggregationType.ts +17 -0
- package/Types/Trace/TraceDropFilterAction.ts +6 -0
- package/Types/Trace/TracePipelineProcessorType.ts +56 -0
- package/Types/Trace/TraceRecordingRuleDefinition.ts +218 -0
- package/Types/Trace/TraceScrubAction.ts +7 -0
- package/Types/Trace/TraceScrubField.ts +8 -0
- package/Types/Trace/TraceScrubPatternType.ts +10 -0
- package/UI/Components/CardSelect/CardSelect.tsx +9 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +6 -10
- package/UI/Components/Forms/Fields/FormField.tsx +1 -0
- package/UI/Components/Forms/Types/Field.ts +1 -0
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +57 -0
- package/UI/Components/Page/Page.tsx +6 -0
- package/Utils/MetricUnitUtil.ts +289 -0
- package/Utils/Metrics/MetricFormulaEvaluator.ts +610 -0
- package/Utils/Metrics/MetricResultUnitConverter.ts +91 -0
- package/Utils/Metrics/RecordingRuleExpression.ts +359 -0
- package/Utils/ValueFormatter.ts +137 -13
- package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js +480 -0
- package/build/dist/Models/DatabaseModels/DockerHostOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js +479 -0
- package/build/dist/Models/DatabaseModels/DockerHostOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +24 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js +480 -0
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js +479 -0
- package/build/dist/Models/DatabaseModels/KubernetesClusterOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/KubernetesResource.js +590 -0
- package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MetricPipelineRule.js +836 -0
- package/build/dist/Models/DatabaseModels/MetricPipelineRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MetricRecordingRule.js +497 -0
- package/build/dist/Models/DatabaseModels/MetricRecordingRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +53 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +79 -0
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +536 -0
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TracePipeline.js +462 -0
- package/build/dist/Models/DatabaseModels/TracePipeline.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js +476 -0
- package/build/dist/Models/DatabaseModels/TracePipelineProcessor.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TraceRecordingRule.js +497 -0
- package/build/dist/Models/DatabaseModels/TraceRecordingRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TraceScrubRule.js +575 -0
- package/build/dist/Models/DatabaseModels/TraceScrubRule.js.map +1 -0
- package/build/dist/Server/API/KubernetesResourceAPI.js +98 -0
- package/build/dist/Server/API/KubernetesResourceAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js +144 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776504277320-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js +82 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776505976155-AddTracePipelineTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js +118 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776509413763-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776541018853-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1776544084793-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/DockerHostOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/DockerHostOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DockerHostOwnerUserService.js +9 -0
- package/build/dist/Server/Services/DockerHostOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js +9 -0
- package/build/dist/Server/Services/KubernetesClusterOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js +9 -0
- package/build/dist/Server/Services/KubernetesClusterOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/KubernetesResourceService.js +237 -0
- package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -0
- package/build/dist/Server/Services/MetricPipelineRuleService.js +9 -0
- package/build/dist/Server/Services/MetricPipelineRuleService.js.map +1 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js +9 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -0
- package/build/dist/Server/Services/TraceDropFilterService.js +9 -0
- package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -0
- package/build/dist/Server/Services/TracePipelineProcessorService.js +9 -0
- package/build/dist/Server/Services/TracePipelineProcessorService.js.map +1 -0
- package/build/dist/Server/Services/TracePipelineService.js +9 -0
- package/build/dist/Server/Services/TracePipelineService.js.map +1 -0
- package/build/dist/Server/Services/TraceRecordingRuleService.js +9 -0
- package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -0
- package/build/dist/Server/Services/TraceScrubRuleService.js +9 -0
- package/build/dist/Server/Services/TraceScrubRuleService.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +56 -9
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +335 -53
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +277 -5
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js +407 -0
- package/build/dist/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.js.map +1 -0
- package/build/dist/Tests/Utils/MetricUnitUtil.test.js +159 -0
- package/build/dist/Tests/Utils/MetricUnitUtil.test.js.map +1 -0
- package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js +224 -0
- package/build/dist/Tests/Utils/Metrics/MetricFormulaEvaluator.test.js.map +1 -0
- package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js +180 -0
- package/build/dist/Tests/Utils/Metrics/MetricResultUnitConverter.test.js.map +1 -0
- package/build/dist/Tests/Utils/RecordingRuleExpression.test.js +142 -0
- package/build/dist/Tests/Utils/RecordingRuleExpression.test.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js +200 -0
- package/build/dist/Types/Kubernetes/KubernetesInventoryExtractor.js.map +1 -0
- package/build/dist/Types/Kubernetes/KubernetesObjectParser.js +1205 -0
- package/build/dist/Types/Kubernetes/KubernetesObjectParser.js.map +1 -0
- package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js +32 -0
- package/build/dist/Types/Metrics/MetricDownsamplingRetentionDays.js.map +1 -0
- package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js +103 -0
- package/build/dist/Types/Metrics/MetricPipelineRuleFilterCondition.js.map +1 -0
- package/build/dist/Types/Metrics/MetricPipelineRuleType.js +27 -0
- package/build/dist/Types/Metrics/MetricPipelineRuleType.js.map +1 -0
- package/build/dist/Types/Metrics/RecordingRuleDefinition.js +110 -0
- package/build/dist/Types/Metrics/RecordingRuleDefinition.js.map +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js +22 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js +2 -0
- package/build/dist/Types/Monitor/MetricMonitor/MetricCriteriaContext.js.map +1 -0
- package/build/dist/Types/Permission.js +454 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Trace/TraceAggregationType.js +18 -0
- package/build/dist/Types/Trace/TraceAggregationType.js.map +1 -0
- package/build/dist/Types/Trace/TraceDropFilterAction.js +7 -0
- package/build/dist/Types/Trace/TraceDropFilterAction.js.map +1 -0
- package/build/dist/Types/Trace/TracePipelineProcessorType.js +10 -0
- package/build/dist/Types/Trace/TracePipelineProcessorType.js.map +1 -0
- package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js +145 -0
- package/build/dist/Types/Trace/TraceRecordingRuleDefinition.js.map +1 -0
- package/build/dist/Types/Trace/TraceScrubAction.js +8 -0
- package/build/dist/Types/Trace/TraceScrubAction.js.map +1 -0
- package/build/dist/Types/Trace/TraceScrubField.js +9 -0
- package/build/dist/Types/Trace/TraceScrubField.js.map +1 -0
- package/build/dist/Types/Trace/TraceScrubPatternType.js +11 -0
- package/build/dist/Types/Trace/TraceScrubPatternType.js.map +1 -0
- package/build/dist/UI/Components/CardSelect/CardSelect.js +3 -1
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +6 -9
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +30 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +1 -0
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +232 -0
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +453 -0
- package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricResultUnitConverter.js +61 -0
- package/build/dist/Utils/Metrics/MetricResultUnitConverter.js.map +1 -0
- package/build/dist/Utils/Metrics/RecordingRuleExpression.js +298 -0
- package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -0
- package/build/dist/Utils/ValueFormatter.js +123 -13
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- 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
|
+
}
|
|
@@ -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
|
|
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-
|
|
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={
|
|
226
|
+
className={`bg-white ${props.chartCssClass || ""}`}
|
|
231
227
|
>
|
|
232
|
-
<div className="px-
|
|
233
|
-
<div className="mb-
|
|
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-
|
|
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-
|
|
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);
|
|
@@ -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">
|