@oneuptime/common 11.5.8 → 11.5.9
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/AIAgentTaskPullRequest.ts +15 -6
- package/Models/DatabaseModels/AIRun.ts +37 -0
- package/Models/DatabaseModels/AIRunEvent.ts +34 -1
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +215 -0
- package/Models/DatabaseModels/Project.ts +25 -0
- package/Models/DatabaseModels/StatusPage.ts +42 -0
- package/Server/API/AIAgentTaskAPI.ts +38 -12
- package/Server/API/AIAgentTaskLogAPI.ts +49 -0
- package/Server/API/AIChatAPI.ts +16 -0
- package/Server/API/AIReadinessAPI.ts +84 -0
- package/Server/API/CodeFixRunAPI.ts +182 -0
- package/Server/API/TelemetryExceptionAPI.ts +6 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.ts +95 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Services/AIRunEventService.ts +15 -1
- package/Server/Services/AIRunService.ts +38 -1
- package/Server/Services/LlmProviderService.ts +2 -0
- package/Server/Services/ProjectService.ts +42 -0
- package/Server/Services/StatusPageService.ts +87 -0
- package/Server/Services/TelemetryExceptionService.ts +19 -90
- package/Server/Types/Markdown.ts +9 -9
- package/Server/Types/MarkdownSlugify.ts +47 -0
- package/Server/Utils/AI/AIRunTranscript.ts +240 -0
- package/Server/Utils/AI/Chat/ChatAgentRunner.ts +9 -0
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +119 -5
- package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +75 -0
- package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +235 -0
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +2 -3
- package/Server/Utils/AI/Toolbox/CodeTools.ts +883 -0
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +519 -0
- package/Server/Utils/AI/Toolbox/Index.ts +27 -0
- package/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.ts +279 -0
- package/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.ts +19 -1
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +600 -0
- package/Server/Utils/CodeRepository/StackTraceRepoResolver.ts +7 -2
- package/Server/Utils/LLM/LLMService.ts +397 -18
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +4 -11
- package/Tests/Models/StatusPageEnableMcpServer.test.ts +125 -0
- package/Tests/Server/Services/StatusPageServiceMcp.test.ts +223 -0
- package/Tests/Server/Services/TelemetryExceptionAIFixReadiness.test.ts +26 -3
- package/Tests/Server/Services/TelemetryExceptionCodeFixRun.test.ts +12 -0
- package/Tests/Server/Types/Markdown.test.ts +106 -0
- package/Tests/Server/Utils/AI/AIRunTranscript.test.ts +182 -0
- package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +411 -0
- package/Tests/Server/Utils/AI/CodeTools.test.ts +596 -0
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +475 -0
- package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +548 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +142 -0
- package/Tests/Server/Utils/AI/ScheduledMaintenanceTools.test.ts +176 -0
- package/Tests/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.test.ts +63 -0
- package/Tests/Server/Utils/GitHubGetFileContent.test.ts +197 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +502 -0
- package/Tests/Types/AI/AIAgentTaskStatus.test.ts +7 -6
- package/Tests/Types/AI/AIChatPageContext.test.ts +0 -0
- package/Tests/Types/AI/AIRunStatus.test.ts +42 -0
- package/Tests/Types/Log/LogSeverity.test.ts +78 -0
- package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +167 -0
- package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +66 -0
- package/Tests/UI/Utils/AIChatExport/ChatWidgetData.test.ts +319 -0
- package/Tests/UI/Utils/AIChatExport/ChatWidgetMarkdown.test.ts +188 -0
- package/Types/AI/AIAgentTaskStatus.ts +13 -0
- package/Types/AI/AIChatPageContext.ts +137 -0
- package/Types/AI/AIChatTypes.ts +44 -0
- package/Types/AI/AIFixReadiness.ts +46 -0
- package/Types/AI/AIRunStatus.ts +11 -0
- package/Types/Log/LogSeverity.ts +61 -0
- package/Types/Monitor/SnmpMonitor/SnmpVersion.ts +40 -0
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +8 -2
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +3 -1
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +8 -2
- package/UI/Components/Forms/BasicForm.tsx +26 -8
- package/UI/Styles/Theme.css +1314 -0
- package/UI/Utils/AIChatExport/ChatWidgetData.ts +316 -0
- package/UI/Utils/AIChatExport/ChatWidgetMarkdown.ts +349 -0
- package/UI/Utils/AIChatExport/ConversationMarkdown.ts +177 -0
- package/UI/Utils/AIChatExport/MarkdownBlocks.ts +327 -0
- package/UI/Utils/AIChatExport/MarkdownSafety.ts +215 -0
- package/UI/Utils/DownloadFile.ts +54 -0
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js +15 -7
- package/build/dist/Models/DatabaseModels/AIAgentTaskPullRequest.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIRun.js +38 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AIRunEvent.js +31 -0
- package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +225 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +27 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +43 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskAPI.js +37 -11
- package/build/dist/Server/API/AIAgentTaskAPI.js.map +1 -1
- package/build/dist/Server/API/AIAgentTaskLogAPI.js +32 -7
- package/build/dist/Server/API/AIAgentTaskLogAPI.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +9 -0
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/AIReadinessAPI.js +57 -0
- package/build/dist/Server/API/AIReadinessAPI.js.map +1 -0
- package/build/dist/Server/API/CodeFixRunAPI.js +142 -0
- package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryExceptionAPI.js +4 -0
- package/build/dist/Server/API/TelemetryExceptionAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js +80 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784124919694-AddAITaskNumberAndRunTranscript.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js +37 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784135099754-AllowNullAiAgentOnPullRequest.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784137457184-AddEnableMcpServerToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784200000000-AddSnmpV3ColumnsToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIRunEventService.js +8 -0
- package/build/dist/Server/Services/AIRunEventService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +29 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/LlmProviderService.js +2 -0
- package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +39 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +81 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryExceptionService.js +14 -61
- package/build/dist/Server/Services/TelemetryExceptionService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +8 -8
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/MarkdownSlugify.js +47 -0
- package/build/dist/Server/Types/MarkdownSlugify.js.map +1 -0
- package/build/dist/Server/Utils/AI/AIRunTranscript.js +180 -0
- package/build/dist/Server/Utils/AI/AIRunTranscript.js.map +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +1 -0
- package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +103 -5
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +55 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +211 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +654 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +389 -0
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js +19 -0
- package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js +239 -0
- package/build/dist/Server/Utils/AI/Toolbox/ScheduledMaintenanceTools.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js +19 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/ClickhouseCapacity.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +439 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js +1 -1
- package/build/dist/Server/Utils/CodeRepository/StackTraceRepoResolver.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +275 -19
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +2 -11
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Types/AI/AIAgentTaskStatus.js +12 -0
- package/build/dist/Types/AI/AIAgentTaskStatus.js.map +1 -1
- package/build/dist/Types/AI/AIChatPageContext.js +101 -0
- package/build/dist/Types/AI/AIChatPageContext.js.map +1 -0
- package/build/dist/Types/AI/AIChatTypes.js +2 -0
- package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
- package/build/dist/Types/AI/AIFixReadiness.js +9 -0
- package/build/dist/Types/AI/AIFixReadiness.js.map +1 -0
- package/build/dist/Types/AI/AIRunStatus.js +11 -0
- package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
- package/build/dist/Types/Log/LogSeverity.js +56 -0
- package/build/dist/Types/Log/LogSeverity.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js +38 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVersion.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +9 -2
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +3 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +9 -2
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +24 -6
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js +217 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetData.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js +234 -0
- package/build/dist/UI/Utils/AIChatExport/ChatWidgetMarkdown.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +111 -0
- package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js +233 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownBlocks.js.map +1 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js +134 -0
- package/build/dist/UI/Utils/AIChatExport/MarkdownSafety.js.map +1 -0
- package/build/dist/UI/Utils/DownloadFile.js +41 -0
- package/build/dist/UI/Utils/DownloadFile.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import {
|
|
3
|
+
AIChatToolActionStatus,
|
|
4
|
+
AIChatWidget,
|
|
5
|
+
AIChatWidgetType,
|
|
6
|
+
} from "../../../../Types/AI/AIChatTypes";
|
|
7
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
8
|
+
import {
|
|
9
|
+
citationsToMarkdown,
|
|
10
|
+
toolActionsToMarkdown,
|
|
11
|
+
widgetToMarkdown,
|
|
12
|
+
} from "../../../../UI/Utils/AIChatExport/ChatWidgetMarkdown";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* The chat caps how much of a widget it shows, and says so. An export that
|
|
16
|
+
* quietly dropped the overflow — or quietly included it — would misrepresent
|
|
17
|
+
* the answer either way, so the caps and their captions are pinned here.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
function rows(count: number): Array<JSONObject> {
|
|
21
|
+
return Array.from({ length: count }, (_unused: unknown, index: number) => {
|
|
22
|
+
return { name: `row-${index}` };
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("ChatWidgetMarkdown", () => {
|
|
27
|
+
describe("widgetToMarkdown", () => {
|
|
28
|
+
test("renders the title and description", () => {
|
|
29
|
+
const markdown: string = widgetToMarkdown({
|
|
30
|
+
id: "W1",
|
|
31
|
+
type: AIChatWidgetType.StatCards,
|
|
32
|
+
title: "Summary",
|
|
33
|
+
description: "Last hour",
|
|
34
|
+
data: { stats: [{ label: "Errors", value: 3 }] },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(markdown).toContain("#### Summary");
|
|
38
|
+
expect(markdown).toContain("_Last hour_");
|
|
39
|
+
expect(markdown).toContain("| Errors | 3 |");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("caps table rows at 25 and says how many were shown", () => {
|
|
43
|
+
const widget: AIChatWidget = {
|
|
44
|
+
id: "W1",
|
|
45
|
+
type: AIChatWidgetType.Table,
|
|
46
|
+
title: "Rows",
|
|
47
|
+
data: {
|
|
48
|
+
columns: [{ key: "name", title: "Name" }],
|
|
49
|
+
rows: rows(40),
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const markdown: string = widgetToMarkdown(widget);
|
|
54
|
+
|
|
55
|
+
expect(markdown).toContain("row-24");
|
|
56
|
+
expect(markdown).not.toContain("row-25");
|
|
57
|
+
expect(markdown).toContain("_Showing 25 of 40 rows._");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("caps entity lists at 12", () => {
|
|
61
|
+
const widget: AIChatWidget = {
|
|
62
|
+
id: "W1",
|
|
63
|
+
type: AIChatWidgetType.IncidentList,
|
|
64
|
+
title: "Incidents",
|
|
65
|
+
data: {
|
|
66
|
+
items: Array.from({ length: 20 }, (_u: unknown, i: number) => {
|
|
67
|
+
return { title: `incident-${i}` };
|
|
68
|
+
}),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const markdown: string = widgetToMarkdown(widget);
|
|
73
|
+
|
|
74
|
+
expect(markdown).toContain("incident-11");
|
|
75
|
+
expect(markdown).not.toContain("incident-12");
|
|
76
|
+
expect(markdown).toContain("_Showing 12 of 20._");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("escapes a pipe so it cannot break the table", () => {
|
|
80
|
+
const markdown: string = widgetToMarkdown({
|
|
81
|
+
id: "W1",
|
|
82
|
+
type: AIChatWidgetType.Table,
|
|
83
|
+
title: "Rows",
|
|
84
|
+
data: {
|
|
85
|
+
columns: [{ key: "name", title: "Name" }],
|
|
86
|
+
rows: [{ name: "a|b" }],
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(markdown).toContain("a\\|b");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("empty widgets say so rather than rendering an empty table", () => {
|
|
94
|
+
expect(
|
|
95
|
+
widgetToMarkdown({
|
|
96
|
+
id: "W1",
|
|
97
|
+
type: AIChatWidgetType.Table,
|
|
98
|
+
title: "Rows",
|
|
99
|
+
data: { columns: [], rows: [] },
|
|
100
|
+
}),
|
|
101
|
+
).toContain("_No rows._");
|
|
102
|
+
|
|
103
|
+
expect(
|
|
104
|
+
widgetToMarkdown({
|
|
105
|
+
id: "W2",
|
|
106
|
+
type: AIChatWidgetType.TimeSeriesChart,
|
|
107
|
+
title: "Chart",
|
|
108
|
+
data: { series: [] },
|
|
109
|
+
}),
|
|
110
|
+
).toContain("_No data points in this range._");
|
|
111
|
+
|
|
112
|
+
expect(
|
|
113
|
+
widgetToMarkdown({
|
|
114
|
+
id: "W3",
|
|
115
|
+
type: AIChatWidgetType.IncidentList,
|
|
116
|
+
title: "Incidents",
|
|
117
|
+
data: { items: [] },
|
|
118
|
+
}),
|
|
119
|
+
).toContain("_Nothing here._");
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("toolActionsToMarkdown", () => {
|
|
124
|
+
test("leads with the status so a denied action cannot read as a done one", () => {
|
|
125
|
+
const markdown: string = toolActionsToMarkdown([
|
|
126
|
+
{
|
|
127
|
+
id: "t1",
|
|
128
|
+
toolName: "restart",
|
|
129
|
+
title: "Restart payment-svc",
|
|
130
|
+
arguments: { service: "payment-svc" },
|
|
131
|
+
isMutation: true,
|
|
132
|
+
requiresApproval: true,
|
|
133
|
+
status: AIChatToolActionStatus.Denied,
|
|
134
|
+
},
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
expect(markdown).toContain("- **Denied** — Restart payment-svc");
|
|
138
|
+
expect(markdown).toContain("service: payment-svc");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("is empty when there are no actions", () => {
|
|
142
|
+
expect(toolActionsToMarkdown([])).toBe("");
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("citationsToMarkdown", () => {
|
|
147
|
+
test("spells out a zero row count as evidence of absence", () => {
|
|
148
|
+
const markdown: string = citationsToMarkdown([
|
|
149
|
+
{
|
|
150
|
+
id: "C1",
|
|
151
|
+
toolName: "logs.query",
|
|
152
|
+
label: "Logs for payment-svc",
|
|
153
|
+
queryArguments: { service: "payment-svc" },
|
|
154
|
+
rowCount: 0,
|
|
155
|
+
},
|
|
156
|
+
]);
|
|
157
|
+
|
|
158
|
+
expect(markdown).toContain("checked, found nothing");
|
|
159
|
+
expect(markdown).toContain('{"service":"payment-svc"}');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("pluralizes a real row count", () => {
|
|
163
|
+
expect(
|
|
164
|
+
citationsToMarkdown([
|
|
165
|
+
{
|
|
166
|
+
id: "C1",
|
|
167
|
+
toolName: "t",
|
|
168
|
+
label: "l",
|
|
169
|
+
queryArguments: {},
|
|
170
|
+
rowCount: 1,
|
|
171
|
+
},
|
|
172
|
+
]),
|
|
173
|
+
).toContain("1 row");
|
|
174
|
+
|
|
175
|
+
expect(
|
|
176
|
+
citationsToMarkdown([
|
|
177
|
+
{
|
|
178
|
+
id: "C2",
|
|
179
|
+
toolName: "t",
|
|
180
|
+
label: "l",
|
|
181
|
+
queryArguments: {},
|
|
182
|
+
rowCount: 5,
|
|
183
|
+
},
|
|
184
|
+
]),
|
|
185
|
+
).toContain("5 rows");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
@@ -2,6 +2,12 @@ enum AIAgentTaskStatus {
|
|
|
2
2
|
Scheduled = "Scheduled",
|
|
3
3
|
InProgress = "InProgress",
|
|
4
4
|
Completed = "Completed",
|
|
5
|
+
/*
|
|
6
|
+
* The agent finished cleanly but had no fix to propose, so it opened no
|
|
7
|
+
* pull request. Reported instead of Error so a negative result is not
|
|
8
|
+
* counted as a failure — see AIRunStatus.NoFixFound, which this maps to.
|
|
9
|
+
*/
|
|
10
|
+
NoFixFound = "NoFixFound",
|
|
5
11
|
Error = "Error",
|
|
6
12
|
}
|
|
7
13
|
|
|
@@ -32,6 +38,12 @@ export class AIAgentTaskStatusHelper {
|
|
|
32
38
|
title: "Completed",
|
|
33
39
|
description: "Task has been completed successfully.",
|
|
34
40
|
},
|
|
41
|
+
{
|
|
42
|
+
status: AIAgentTaskStatus.NoFixFound,
|
|
43
|
+
title: "No Fix Found",
|
|
44
|
+
description:
|
|
45
|
+
"Task ran successfully but AI did not find a fix to propose.",
|
|
46
|
+
},
|
|
35
47
|
{
|
|
36
48
|
status: AIAgentTaskStatus.Error,
|
|
37
49
|
title: "Error",
|
|
@@ -59,6 +71,7 @@ export class AIAgentTaskStatusHelper {
|
|
|
59
71
|
public static isTerminalStatus(status: AIAgentTaskStatus): boolean {
|
|
60
72
|
return (
|
|
61
73
|
status === AIAgentTaskStatus.Completed ||
|
|
74
|
+
status === AIAgentTaskStatus.NoFixFound ||
|
|
62
75
|
status === AIAgentTaskStatus.Error
|
|
63
76
|
);
|
|
64
77
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { JSONObject } from "../JSON";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* "Page context" makes Ask AI aware of what the user is looking at in the
|
|
5
|
+
* dashboard. The client detects the current page (an incident, a monitor, a
|
|
6
|
+
* trace waterfall, the logs explorer, …) and attaches this small descriptor to
|
|
7
|
+
* each message it sends; the server folds it into the system prompt so "this
|
|
8
|
+
* incident" resolves to the entity on screen. It is a per-turn hint, never
|
|
9
|
+
* persisted — the user can detach it in the composer at any time.
|
|
10
|
+
*/
|
|
11
|
+
enum AIChatPageContextType {
|
|
12
|
+
// Entity pages — carry the entity's id (and usually a display title).
|
|
13
|
+
Incident = "Incident",
|
|
14
|
+
Alert = "Alert",
|
|
15
|
+
Monitor = "Monitor",
|
|
16
|
+
ScheduledMaintenanceEvent = "ScheduledMaintenanceEvent",
|
|
17
|
+
TelemetryService = "TelemetryService",
|
|
18
|
+
Trace = "Trace",
|
|
19
|
+
Exception = "Exception",
|
|
20
|
+
|
|
21
|
+
// Area pages — no id; the user is browsing a list or an explorer.
|
|
22
|
+
IncidentsList = "IncidentsList",
|
|
23
|
+
AlertsList = "AlertsList",
|
|
24
|
+
MonitorsList = "MonitorsList",
|
|
25
|
+
ScheduledMaintenanceList = "ScheduledMaintenanceList",
|
|
26
|
+
LogsExplorer = "LogsExplorer",
|
|
27
|
+
TracesExplorer = "TracesExplorer",
|
|
28
|
+
MetricsExplorer = "MetricsExplorer",
|
|
29
|
+
ExceptionsList = "ExceptionsList",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default AIChatPageContextType;
|
|
33
|
+
|
|
34
|
+
export interface AIChatPageContext {
|
|
35
|
+
type: AIChatPageContextType;
|
|
36
|
+
// The entity on screen (UUID, or a hex trace id). Only set for entity types.
|
|
37
|
+
entityId?: string | undefined;
|
|
38
|
+
// Display title of the entity (incident title, monitor name, …). Optional.
|
|
39
|
+
entityTitle?: string | undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* Ids are OneUptime ObjectIDs (UUIDs) — except traces, whose ids are
|
|
44
|
+
* OpenTelemetry hex strings. Anything else is rejected: the id is echoed into
|
|
45
|
+
* the LLM prompt and into tool suggestions, so it must never carry free-form
|
|
46
|
+
* text (e.g. a static route segment like "overview" that a :id URL wildcard
|
|
47
|
+
* can capture).
|
|
48
|
+
*/
|
|
49
|
+
const UUID_REGEX: RegExp =
|
|
50
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
51
|
+
const TRACE_ID_REGEX: RegExp = /^[0-9a-fA-F]{8,64}$/;
|
|
52
|
+
|
|
53
|
+
const MAX_ENTITY_TITLE_LENGTH: number = 200;
|
|
54
|
+
|
|
55
|
+
const ENTITY_TYPES: Array<AIChatPageContextType> = [
|
|
56
|
+
AIChatPageContextType.Incident,
|
|
57
|
+
AIChatPageContextType.Alert,
|
|
58
|
+
AIChatPageContextType.Monitor,
|
|
59
|
+
AIChatPageContextType.ScheduledMaintenanceEvent,
|
|
60
|
+
AIChatPageContextType.TelemetryService,
|
|
61
|
+
AIChatPageContextType.Trace,
|
|
62
|
+
AIChatPageContextType.Exception,
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
export class AIChatPageContextHelper {
|
|
66
|
+
public static isValidType(
|
|
67
|
+
value: string | undefined,
|
|
68
|
+
): value is AIChatPageContextType {
|
|
69
|
+
return Object.values(AIChatPageContextType).includes(
|
|
70
|
+
value as AIChatPageContextType,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Entity types point at one specific record and require an entityId.
|
|
75
|
+
public static isEntityType(type: AIChatPageContextType): boolean {
|
|
76
|
+
return ENTITY_TYPES.includes(type);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* Validate and sanitize an untrusted client-supplied page context. Returns
|
|
81
|
+
* undefined when the payload is missing or invalid — page context is a hint,
|
|
82
|
+
* so a bad one is dropped rather than failing the message.
|
|
83
|
+
*/
|
|
84
|
+
public static sanitize(
|
|
85
|
+
json: JSONObject | undefined | null,
|
|
86
|
+
): AIChatPageContext | undefined {
|
|
87
|
+
if (!json || typeof json !== "object" || Array.isArray(json)) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const type: string | undefined =
|
|
92
|
+
typeof json["type"] === "string" ? (json["type"] as string) : undefined;
|
|
93
|
+
|
|
94
|
+
if (!this.isValidType(type)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const context: AIChatPageContext = { type: type };
|
|
99
|
+
|
|
100
|
+
if (this.isEntityType(type)) {
|
|
101
|
+
const entityId: string =
|
|
102
|
+
typeof json["entityId"] === "string"
|
|
103
|
+
? (json["entityId"] as string).trim()
|
|
104
|
+
: "";
|
|
105
|
+
|
|
106
|
+
const idRegex: RegExp =
|
|
107
|
+
type === AIChatPageContextType.Trace ? TRACE_ID_REGEX : UUID_REGEX;
|
|
108
|
+
|
|
109
|
+
// An entity context without a usable id is meaningless — drop it whole.
|
|
110
|
+
if (!idRegex.test(entityId)) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
context.entityId = entityId;
|
|
115
|
+
|
|
116
|
+
if (typeof json["entityTitle"] === "string") {
|
|
117
|
+
/*
|
|
118
|
+
* The title is echoed into the system prompt: collapse whitespace and
|
|
119
|
+
* control characters so it cannot introduce new lines or fake
|
|
120
|
+
* prompt structure, and cap the length.
|
|
121
|
+
*/
|
|
122
|
+
const entityTitle: string = (json["entityTitle"] as string)
|
|
123
|
+
// eslint-disable-next-line no-control-regex
|
|
124
|
+
.replace(/[\u0000-\u001F\u007F]+/g, " ")
|
|
125
|
+
.replace(/\s+/g, " ")
|
|
126
|
+
.trim()
|
|
127
|
+
.substring(0, MAX_ENTITY_TITLE_LENGTH);
|
|
128
|
+
|
|
129
|
+
if (entityTitle) {
|
|
130
|
+
context.entityTitle = entityTitle;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return context;
|
|
136
|
+
}
|
|
137
|
+
}
|
package/Types/AI/AIChatTypes.ts
CHANGED
|
@@ -22,6 +22,8 @@ export enum AIChatCitationTargetType {
|
|
|
22
22
|
AlertView = "AlertView",
|
|
23
23
|
Monitors = "Monitors",
|
|
24
24
|
MonitorView = "MonitorView",
|
|
25
|
+
ScheduledMaintenanceEvents = "ScheduledMaintenanceEvents",
|
|
26
|
+
ScheduledMaintenanceView = "ScheduledMaintenanceView",
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
export interface AIChatCitationTarget {
|
|
@@ -197,6 +199,48 @@ export interface AIRunEventResultSummary {
|
|
|
197
199
|
severity?: string | undefined;
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
/*
|
|
203
|
+
* The verbatim content behind one run event — the raw material for debugging
|
|
204
|
+
* a bad run: exactly what was sent to the model, exactly what it said back,
|
|
205
|
+
* and exactly what a tool returned.
|
|
206
|
+
*
|
|
207
|
+
* This is the ONLY place a code-fix run's LLM content is persisted. It lives
|
|
208
|
+
* on AIRunEvent.contentPayload, whose read ACL is empty precisely because
|
|
209
|
+
* this content embeds customer source code: LlmLog deliberately redacts the
|
|
210
|
+
* same content (CodeFixAgentCompletion passes storeContentPreviews: false)
|
|
211
|
+
* because LlmLog is readable project-wide, and that redaction stays. Reach it
|
|
212
|
+
* only through GET /code-fix-run/logs, which gates on ProjectOwner or
|
|
213
|
+
* ProjectAdmin — the same "sensitive content behind a narrow endpoint" shape
|
|
214
|
+
* AIRun.pausedState and AIRun.taskContext already use.
|
|
215
|
+
*
|
|
216
|
+
* Every field is capped at write time (see AIRunTranscript.ts) so one run can
|
|
217
|
+
* never write an unbounded row.
|
|
218
|
+
*/
|
|
219
|
+
export interface AIRunEventContentPayload {
|
|
220
|
+
// Messages newly sent to the model on this call — not the whole history.
|
|
221
|
+
requestMessages?: Array<{
|
|
222
|
+
role: string;
|
|
223
|
+
content: string;
|
|
224
|
+
}>;
|
|
225
|
+
// The model's verbatim reply.
|
|
226
|
+
responseContent?: string | undefined;
|
|
227
|
+
// Tool calls the model asked for, with their full arguments.
|
|
228
|
+
responseToolCalls?: Array<{
|
|
229
|
+
id?: string | undefined;
|
|
230
|
+
name: string;
|
|
231
|
+
arguments?: JSONObject | undefined;
|
|
232
|
+
}>;
|
|
233
|
+
// A tool's verbatim return value (for tool events).
|
|
234
|
+
toolResult?: string | undefined;
|
|
235
|
+
modelName?: string | undefined;
|
|
236
|
+
stopReason?: string | undefined;
|
|
237
|
+
promptTokens?: number | undefined;
|
|
238
|
+
completionTokens?: number | undefined;
|
|
239
|
+
totalTokens?: number | undefined;
|
|
240
|
+
// Set when any field above was clipped to its cap.
|
|
241
|
+
isTruncated?: boolean | undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
200
244
|
// What was sent to which LLM during a run — the per-run egress manifest.
|
|
201
245
|
export interface AIRunEgressManifestToolEntry {
|
|
202
246
|
toolName: string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* What a CodeFix run needs before it can complete, as a wire contract shared
|
|
3
|
+
* by the server checks and every UI that renders them. Two surfaces consume
|
|
4
|
+
* this today: the per-exception "Fix with AI Agent" panel
|
|
5
|
+
* (GET /telemetry-exception/ai-fix-readiness/:id) and the project-wide AI
|
|
6
|
+
* Tasks page (POST /ai-readiness/code-fix).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* The repository gate comes in two strengths, and they are deliberately
|
|
11
|
+
* distinct ids — a UI that conflates them would promise more than the check
|
|
12
|
+
* verified:
|
|
13
|
+
*
|
|
14
|
+
* - repositoryResolved: a repository matches THIS exception's stack trace.
|
|
15
|
+
* Per-exception, and the stronger claim.
|
|
16
|
+
* - repositoryConnected: the project has at least one GitHub-App-connected
|
|
17
|
+
* repository. Project-wide, and all a page-level check can honestly assert
|
|
18
|
+
* — it says nothing about whether any given exception will resolve.
|
|
19
|
+
*/
|
|
20
|
+
export type AIFixReadinessCheckId =
|
|
21
|
+
| "llmProvider"
|
|
22
|
+
| "repositoryResolved"
|
|
23
|
+
| "repositoryConnected"
|
|
24
|
+
| "agentAvailable";
|
|
25
|
+
|
|
26
|
+
export interface AIFixReadinessCheck {
|
|
27
|
+
id: AIFixReadinessCheckId;
|
|
28
|
+
ok: boolean;
|
|
29
|
+
/*
|
|
30
|
+
* The gate's headline. Checks fill in what they actually found where that
|
|
31
|
+
* is useful ("Repository resolved: acme/api"), so this is not a fixed
|
|
32
|
+
* label per id.
|
|
33
|
+
*/
|
|
34
|
+
title: string;
|
|
35
|
+
/*
|
|
36
|
+
* When ok is false: exactly what to do next. When ok is true: what is
|
|
37
|
+
* configured, so the user can tell a project-owned provider from the
|
|
38
|
+
* shared one without leaving the page. May be empty.
|
|
39
|
+
*/
|
|
40
|
+
detail: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AIFixReadiness {
|
|
44
|
+
ready: boolean;
|
|
45
|
+
checks: Array<AIFixReadinessCheck>;
|
|
46
|
+
}
|
package/Types/AI/AIRunStatus.ts
CHANGED
|
@@ -18,6 +18,16 @@ enum AIRunStatus {
|
|
|
18
18
|
*/
|
|
19
19
|
WaitingForApproval = "WaitingForApproval",
|
|
20
20
|
Completed = "Completed",
|
|
21
|
+
/*
|
|
22
|
+
* The run did its job and concluded there was nothing to change — the agent
|
|
23
|
+
* read the code and found no fix worth proposing, so it opened no pull
|
|
24
|
+
* request. A negative result, NOT a failure: nothing broke, and retrying the
|
|
25
|
+
* same run unchanged would likely reach the same conclusion. Kept distinct
|
|
26
|
+
* from Error so a quiet "no fix" never lands in an error rate, an alert, or
|
|
27
|
+
* a red pill. Contrast with Error, which means the run could not finish
|
|
28
|
+
* (clone failed, LLM errored, no repository resolved).
|
|
29
|
+
*/
|
|
30
|
+
NoFixFound = "NoFixFound",
|
|
21
31
|
Error = "Error",
|
|
22
32
|
Cancelled = "Cancelled",
|
|
23
33
|
Stale = "Stale",
|
|
@@ -29,6 +39,7 @@ export class AIRunStatusHelper {
|
|
|
29
39
|
public static isTerminalStatus(status: AIRunStatus): boolean {
|
|
30
40
|
return (
|
|
31
41
|
status === AIRunStatus.Completed ||
|
|
42
|
+
status === AIRunStatus.NoFixFound ||
|
|
32
43
|
status === AIRunStatus.Error ||
|
|
33
44
|
status === AIRunStatus.Cancelled ||
|
|
34
45
|
status === AIRunStatus.Stale
|
package/Types/Log/LogSeverity.ts
CHANGED
|
@@ -8,4 +8,65 @@ enum LogSeverity {
|
|
|
8
8
|
Fatal = "Fatal",
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/*
|
|
12
|
+
* The OTLP severity number stored alongside each level.
|
|
13
|
+
*
|
|
14
|
+
* These are the low end of each OTLP range (Trace 1-4, Debug 5-8, Info 9-12,
|
|
15
|
+
* Warn 13-16, Error 17-20, Fatal 21-24), so they are the inverse of the
|
|
16
|
+
* bucketing OtelLogsIngestService.getSeverityText applies on ingest. Anything
|
|
17
|
+
* that writes severityText must take the number from here too, or the row says
|
|
18
|
+
* one thing in its text and another in its number.
|
|
19
|
+
*
|
|
20
|
+
* https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber
|
|
21
|
+
*/
|
|
22
|
+
export const LogSeverityNumber: Record<LogSeverity, number> = {
|
|
23
|
+
[LogSeverity.Unspecified]: 0,
|
|
24
|
+
[LogSeverity.Trace]: 1,
|
|
25
|
+
[LogSeverity.Debug]: 5,
|
|
26
|
+
[LogSeverity.Information]: 9,
|
|
27
|
+
[LogSeverity.Warning]: 13,
|
|
28
|
+
[LogSeverity.Error]: 17,
|
|
29
|
+
[LogSeverity.Fatal]: 21,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Loose severity text -> the enum member actually stored on a log row.
|
|
34
|
+
*
|
|
35
|
+
* Only these seven strings ever reach the database: ingest discards whatever
|
|
36
|
+
* severityText a client sent and re-derives it from severityNumber. So a value
|
|
37
|
+
* that is merely severity-shaped ("INFO", "warn") matches nothing — and since
|
|
38
|
+
* `=` and `IN` are case-sensitive, it fails silently rather than erroring.
|
|
39
|
+
*
|
|
40
|
+
* This exists because the filter and severity-remapper dropdowns spent a long
|
|
41
|
+
* time emitting TRACE/DEBUG/INFO/WARNING/ERROR/FATAL. Those values are still
|
|
42
|
+
* sitting in saved pipeline configs, so the remapper normalises through here on
|
|
43
|
+
* the way in rather than trusting what was stored.
|
|
44
|
+
*
|
|
45
|
+
* Returns null for anything unrecognised. Callers decide what to do about it —
|
|
46
|
+
* guessing a severity is worse than admitting we cannot tell.
|
|
47
|
+
*/
|
|
48
|
+
export function normalizeLogSeverity(text: string): LogSeverity | null {
|
|
49
|
+
const normalized: string = (text || "").trim().toUpperCase();
|
|
50
|
+
|
|
51
|
+
if (!normalized) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const aliases: Record<string, LogSeverity> = {
|
|
56
|
+
UNSPECIFIED: LogSeverity.Unspecified,
|
|
57
|
+
TRACE: LogSeverity.Trace,
|
|
58
|
+
DEBUG: LogSeverity.Debug,
|
|
59
|
+
// INFO and WARN are the two the old dropdowns got wrong by more than case.
|
|
60
|
+
INFO: LogSeverity.Information,
|
|
61
|
+
INFORMATION: LogSeverity.Information,
|
|
62
|
+
WARN: LogSeverity.Warning,
|
|
63
|
+
WARNING: LogSeverity.Warning,
|
|
64
|
+
ERR: LogSeverity.Error,
|
|
65
|
+
ERROR: LogSeverity.Error,
|
|
66
|
+
FATAL: LogSeverity.Fatal,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return aliases[normalized] || null;
|
|
70
|
+
}
|
|
71
|
+
|
|
11
72
|
export default LogSeverity;
|
|
@@ -4,4 +4,44 @@ enum SnmpVersion {
|
|
|
4
4
|
V3 = "3",
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
/*
|
|
8
|
+
* Two spellings exist, and they belong to two different layers:
|
|
9
|
+
*
|
|
10
|
+
* - These enum VALUES ("1"/"2c"/"3") are the probe-contract spelling.
|
|
11
|
+
* MonitorStepSnmpMonitor.snmpVersion is typed as this enum, and
|
|
12
|
+
* SnmpMonitor branches on it to pick the session type.
|
|
13
|
+
* - The KEYS ("V1"/"V2c"/"V3") are the stored spelling. The free-text
|
|
14
|
+
* snmpVersion column on NetworkDevice / NetworkDeviceDiscoveryScan holds
|
|
15
|
+
* these: it is what every form writes, what the column default is, and
|
|
16
|
+
* what the public API reference documents as the allowed values.
|
|
17
|
+
*
|
|
18
|
+
* parse() is the conversion at that seam, and it is the only correct way to
|
|
19
|
+
* read the column. Comparing the raw column against an enum member instead
|
|
20
|
+
* silently takes the wrong branch — a stored "V3" is not === SnmpVersion.V3
|
|
21
|
+
* ("3"), so a v3 device reads as v2c and gets polled in cleartext.
|
|
22
|
+
*
|
|
23
|
+
* parse() also accepts the value spelling and mixed case, so a row written by
|
|
24
|
+
* hand (direct API call, manual DB edit) can't strand a device in the wrong
|
|
25
|
+
* branch. No product path writes that spelling — the tolerance is a guard, not
|
|
26
|
+
* a sign that the column is expected to hold both.
|
|
27
|
+
*/
|
|
28
|
+
export class SnmpVersionUtil {
|
|
29
|
+
public static parse(value: string | undefined | null): SnmpVersion {
|
|
30
|
+
switch ((value || "").trim().toLowerCase()) {
|
|
31
|
+
case "1":
|
|
32
|
+
case "v1":
|
|
33
|
+
return SnmpVersion.V1;
|
|
34
|
+
case "3":
|
|
35
|
+
case "v3":
|
|
36
|
+
return SnmpVersion.V3;
|
|
37
|
+
default:
|
|
38
|
+
return SnmpVersion.V2c;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public static isV3(value: string | undefined | null): boolean {
|
|
43
|
+
return SnmpVersionUtil.parse(value) === SnmpVersion.V3;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
7
47
|
export default SnmpVersion;
|
|
@@ -762,6 +762,7 @@ const AreaChart: React.ForwardRefExoticComponent<
|
|
|
762
762
|
transform: "translate(0, 6)",
|
|
763
763
|
fontSize: 10,
|
|
764
764
|
fontWeight: 500,
|
|
765
|
+
fill: "var(--ou-chart-tick)",
|
|
765
766
|
}}
|
|
766
767
|
ticks={
|
|
767
768
|
startEndOnly
|
|
@@ -802,6 +803,7 @@ const AreaChart: React.ForwardRefExoticComponent<
|
|
|
802
803
|
transform: "translate(-4, 0)",
|
|
803
804
|
fontSize: 10,
|
|
804
805
|
fontWeight: 500,
|
|
806
|
+
fill: "var(--ou-chart-tick)",
|
|
805
807
|
}}
|
|
806
808
|
fill=""
|
|
807
809
|
stroke=""
|
|
@@ -822,7 +824,7 @@ const AreaChart: React.ForwardRefExoticComponent<
|
|
|
822
824
|
)}
|
|
823
825
|
</YAxis>
|
|
824
826
|
<Tooltip
|
|
825
|
-
wrapperStyle={{ outline: "none" }}
|
|
827
|
+
wrapperStyle={{ outline: "none", zIndex: 10 }}
|
|
826
828
|
isAnimationActive={true}
|
|
827
829
|
animationDuration={100}
|
|
828
830
|
cursor={{
|
|
@@ -1076,7 +1078,11 @@ const AreaChart: React.ForwardRefExoticComponent<
|
|
|
1076
1078
|
<Label
|
|
1077
1079
|
value="E"
|
|
1078
1080
|
position="center"
|
|
1079
|
-
|
|
1081
|
+
/*
|
|
1082
|
+
* Sits on the dot's purple, not on the surface, so it must
|
|
1083
|
+
* not follow the ring token that flips dark with the theme.
|
|
1084
|
+
*/
|
|
1085
|
+
fill="#ffffff"
|
|
1080
1086
|
fontSize={8}
|
|
1081
1087
|
fontWeight={700}
|
|
1082
1088
|
/>
|
|
@@ -836,6 +836,7 @@ const BarChart: React.ForwardRefExoticComponent<
|
|
|
836
836
|
layout !== "vertical" ? "translate(0, 6)" : undefined,
|
|
837
837
|
fontSize: 10,
|
|
838
838
|
fontWeight: 500,
|
|
839
|
+
fill: "var(--ou-chart-tick)",
|
|
839
840
|
}}
|
|
840
841
|
fill=""
|
|
841
842
|
stroke=""
|
|
@@ -904,6 +905,7 @@ const BarChart: React.ForwardRefExoticComponent<
|
|
|
904
905
|
: "translate(0, 0)",
|
|
905
906
|
fontSize: 10,
|
|
906
907
|
fontWeight: 500,
|
|
908
|
+
fill: "var(--ou-chart-tick)",
|
|
907
909
|
}}
|
|
908
910
|
{...(layout !== "vertical"
|
|
909
911
|
? {
|
|
@@ -940,7 +942,7 @@ const BarChart: React.ForwardRefExoticComponent<
|
|
|
940
942
|
)}
|
|
941
943
|
</YAxis>
|
|
942
944
|
<Tooltip
|
|
943
|
-
wrapperStyle={{ outline: "none" }}
|
|
945
|
+
wrapperStyle={{ outline: "none", zIndex: 10 }}
|
|
944
946
|
isAnimationActive={true}
|
|
945
947
|
animationDuration={100}
|
|
946
948
|
cursor={{
|