@oneuptime/common 10.0.43 → 10.0.45
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/Workflow.ts +29 -0
- package/Server/API/StatusPageAPI.ts +48 -0
- package/Server/EnvironmentConfig.ts +5 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1774559064920-MigrationName.ts +22 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertService.ts +45 -0
- package/Server/Services/IncidentService.ts +81 -13
- package/Server/Services/LogAggregationService.ts +1 -0
- package/Server/Services/WorkflowService.ts +28 -1
- package/Server/Types/Workflow/Components/Webhook.ts +28 -5
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +29 -13
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +163 -26
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +92 -0
- package/Server/Utils/Profiling.ts +101 -0
- package/Server/Utils/VM/VMRunner.ts +88 -0
- package/Types/Dashboard/DashboardTemplates.ts +1149 -0
- package/Types/Exception/ExceptionMetricType.ts +15 -0
- package/Types/IsolatedVM/ReturnResult.ts +3 -0
- package/Types/Metrics/MetricDashboardMetricType.ts +28 -0
- package/Types/Metrics/MetricsQuery.ts +2 -1
- package/Types/Monitor/CustomCodeMonitor/CapturedMetric.ts +7 -0
- package/Types/Monitor/CustomCodeMonitor/CustomCodeMonitorResponse.ts +2 -0
- package/Types/Monitor/UptimeBarTooltipIncident.ts +21 -0
- package/Types/Profile/ProfileMetricType.ts +16 -0
- package/Types/Span/SpanMetricType.ts +17 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +40 -33
- package/UI/Components/Charts/Bar/BarChart.tsx +37 -30
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +196 -51
- package/UI/Components/Charts/ChartGroup/NoDataMessage.tsx +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +39 -32
- package/UI/Components/Forms/BasicForm.tsx +1 -1
- package/UI/Components/Graphs/DayUptimeGraph.tsx +88 -35
- package/UI/Components/Graphs/UptimeBarTooltip.tsx +547 -0
- package/UI/Components/MonitorGraphs/Uptime.tsx +7 -0
- package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +225 -0
- package/UI/Components/RadioButtons/GroupRadioButtons.tsx +1 -0
- package/UI/Components/Tooltip/Tooltip.tsx +29 -4
- package/UI/Components/Workflow/ComponentSettingsModal.tsx +2 -0
- package/UI/Components/Workflow/DocumentationViewer.tsx +5 -0
- package/UI/Components/Workflow/Workflow.tsx +2 -0
- package/Utils/Alerts/AlertMetricType.ts +98 -0
- package/Utils/Incident/IncidentMetricType.ts +130 -0
- package/build/dist/Models/DatabaseModels/Workflow.js +30 -0
- package/build/dist/Models/DatabaseModels/Workflow.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +42 -0
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +2 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1774559064920-MigrationName.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1774559064920-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +34 -0
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +52 -9
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/WorkflowService.js +25 -0
- package/build/dist/Server/Services/WorkflowService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Webhook.js +23 -5
- package/build/dist/Server/Types/Workflow/Components/Webhook.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +21 -7
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +120 -21
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +68 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Profiling.js +80 -0
- package/build/dist/Server/Utils/Profiling.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js +68 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +1095 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Exception/ExceptionMetricType.js +16 -0
- package/build/dist/Types/Exception/ExceptionMetricType.js.map +1 -0
- package/build/dist/Types/Metrics/MetricDashboardMetricType.js +26 -0
- package/build/dist/Types/Metrics/MetricDashboardMetricType.js.map +1 -0
- package/build/dist/Types/Monitor/CustomCodeMonitor/CapturedMetric.js +2 -0
- package/build/dist/Types/Monitor/CustomCodeMonitor/CapturedMetric.js.map +1 -0
- package/build/dist/Types/Monitor/UptimeBarTooltipIncident.js +2 -0
- package/build/dist/Types/Monitor/UptimeBarTooltipIncident.js.map +1 -0
- package/build/dist/Types/Profile/ProfileMetricType.js +17 -0
- package/build/dist/Types/Profile/ProfileMetricType.js.map +1 -0
- package/build/dist/Types/Span/SpanMetricType.js +18 -0
- package/build/dist/Types/Span/SpanMetricType.js.map +1 -0
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +21 -16
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +20 -15
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +73 -15
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/NoDataMessage.js +7 -0
- package/build/dist/UI/Components/Charts/ChartGroup/NoDataMessage.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +20 -15
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +46 -20
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +303 -0
- package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -0
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +118 -0
- package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -0
- package/build/dist/UI/Components/RadioButtons/GroupRadioButtons.js +1 -1
- package/build/dist/UI/Components/RadioButtons/GroupRadioButtons.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/Tooltip.js +13 -3
- package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +1 -1
- package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/DocumentationViewer.js +1 -0
- package/build/dist/UI/Components/Workflow/DocumentationViewer.js.map +1 -1
- package/build/dist/UI/Components/Workflow/Workflow.js +1 -1
- package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
- package/build/dist/Utils/Alerts/AlertMetricType.js +84 -0
- package/build/dist/Utils/Alerts/AlertMetricType.js.map +1 -0
- package/build/dist/Utils/Incident/IncidentMetricType.js +114 -0
- package/build/dist/Utils/Incident/IncidentMetricType.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
enum ExceptionMetricType {
|
|
2
|
+
ExceptionCount = "oneuptime.exception.count",
|
|
3
|
+
ExceptionRate = "oneuptime.exception.rate",
|
|
4
|
+
ExceptionCountByType = "oneuptime.exception.count.by.type",
|
|
5
|
+
ExceptionCountByService = "oneuptime.exception.count.by.service",
|
|
6
|
+
UnresolvedExceptionCount = "oneuptime.exception.unresolved.count",
|
|
7
|
+
ResolvedExceptionCount = "oneuptime.exception.resolved.count",
|
|
8
|
+
MutedExceptionCount = "oneuptime.exception.muted.count",
|
|
9
|
+
ExceptionFirstSeenTime = "oneuptime.exception.first.seen.time",
|
|
10
|
+
ExceptionLastSeenTime = "oneuptime.exception.last.seen.time",
|
|
11
|
+
ExceptionOccurrenceCount = "oneuptime.exception.occurrence.count",
|
|
12
|
+
ExceptionAffectedServiceCount = "oneuptime.exception.affected.service.count",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default ExceptionMetricType;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
enum MetricDashboardMetricType {
|
|
2
|
+
// HTTP metrics
|
|
3
|
+
HttpRequestDuration = "http.server.request.duration",
|
|
4
|
+
HttpRequestCount = "http.server.request.count",
|
|
5
|
+
HttpRequestErrorRate = "http.server.request.error.rate",
|
|
6
|
+
HttpResponseSize = "http.server.response.body.size",
|
|
7
|
+
HttpRequestSize = "http.server.request.body.size",
|
|
8
|
+
HttpActiveRequests = "http.server.active_requests",
|
|
9
|
+
|
|
10
|
+
// System metrics
|
|
11
|
+
SystemCpuUtilization = "system.cpu.utilization",
|
|
12
|
+
SystemMemoryUsage = "system.memory.usage",
|
|
13
|
+
SystemDiskIo = "system.disk.io",
|
|
14
|
+
SystemNetworkIo = "system.network.io",
|
|
15
|
+
|
|
16
|
+
// Runtime metrics
|
|
17
|
+
ProcessCpuUtilization = "process.cpu.utilization",
|
|
18
|
+
ProcessMemoryUsage = "process.runtime.jvm.memory.usage",
|
|
19
|
+
GcDuration = "process.runtime.jvm.gc.duration",
|
|
20
|
+
ThreadCount = "process.runtime.jvm.threads.count",
|
|
21
|
+
|
|
22
|
+
// Custom application metrics
|
|
23
|
+
CustomCounter = "custom.counter",
|
|
24
|
+
CustomGauge = "custom.gauge",
|
|
25
|
+
CustomHistogram = "custom.histogram",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default MetricDashboardMetricType;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import Search from "../BaseDatabase/Search";
|
|
1
2
|
import Dictionary from "../Dictionary";
|
|
2
3
|
import MetricsAggregationType from "./MetricsAggregationType";
|
|
3
4
|
|
|
4
5
|
export default interface MetricsQuery {
|
|
5
6
|
metricName: string;
|
|
6
|
-
attributes: Dictionary<string | boolean | number
|
|
7
|
+
attributes: Dictionary<string | boolean | number | Search<string>>;
|
|
7
8
|
aggegationType: MetricsAggregationType;
|
|
8
9
|
aggregateBy: Dictionary<boolean>;
|
|
9
10
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import CapturedMetric from "./CapturedMetric";
|
|
1
2
|
import { JSONObject } from "../../JSON";
|
|
2
3
|
|
|
3
4
|
export default interface CustomCodeMonitorResponse {
|
|
4
5
|
result: string | number | boolean | JSONObject | undefined;
|
|
5
6
|
scriptError?: string | undefined;
|
|
6
7
|
logMessages: string[];
|
|
8
|
+
capturedMetrics: CapturedMetric[];
|
|
7
9
|
executionTimeInMS: number;
|
|
8
10
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Color from "../Color";
|
|
2
|
+
import ObjectID from "../ObjectID";
|
|
3
|
+
|
|
4
|
+
export default interface UptimeBarTooltipIncident {
|
|
5
|
+
id: string;
|
|
6
|
+
title: string;
|
|
7
|
+
declaredAt: Date;
|
|
8
|
+
incidentSeverity?:
|
|
9
|
+
| {
|
|
10
|
+
name: string;
|
|
11
|
+
color: Color;
|
|
12
|
+
}
|
|
13
|
+
| undefined;
|
|
14
|
+
currentIncidentState?:
|
|
15
|
+
| {
|
|
16
|
+
name: string;
|
|
17
|
+
color: Color;
|
|
18
|
+
}
|
|
19
|
+
| undefined;
|
|
20
|
+
monitorIds: Array<ObjectID>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
enum ProfileMetricType {
|
|
2
|
+
CpuProfileDuration = "oneuptime.profile.cpu.duration",
|
|
3
|
+
CpuProfileSampleCount = "oneuptime.profile.cpu.sample.count",
|
|
4
|
+
WallClockDuration = "oneuptime.profile.wall.duration",
|
|
5
|
+
MemoryAllocationSize = "oneuptime.profile.memory.allocation.size",
|
|
6
|
+
MemoryAllocationCount = "oneuptime.profile.memory.allocation.count",
|
|
7
|
+
HeapUsage = "oneuptime.profile.heap.usage",
|
|
8
|
+
GoroutineCount = "oneuptime.profile.goroutine.count",
|
|
9
|
+
ThreadCount = "oneuptime.profile.thread.count",
|
|
10
|
+
ProfileSampleRate = "oneuptime.profile.sample.rate",
|
|
11
|
+
ProfileCount = "oneuptime.profile.count",
|
|
12
|
+
TopFunctionCpuTime = "oneuptime.profile.top.function.cpu.time",
|
|
13
|
+
TopFunctionAllocations = "oneuptime.profile.top.function.allocations",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default ProfileMetricType;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
enum SpanMetricType {
|
|
2
|
+
SpanCount = "oneuptime.span.count",
|
|
3
|
+
SpanDuration = "oneuptime.span.duration",
|
|
4
|
+
SpanErrorCount = "oneuptime.span.error.count",
|
|
5
|
+
SpanErrorRate = "oneuptime.span.error.rate",
|
|
6
|
+
SpanRequestRate = "oneuptime.span.request.rate",
|
|
7
|
+
SpanP50Duration = "oneuptime.span.duration.p50",
|
|
8
|
+
SpanP90Duration = "oneuptime.span.duration.p90",
|
|
9
|
+
SpanP95Duration = "oneuptime.span.duration.p95",
|
|
10
|
+
SpanP99Duration = "oneuptime.span.duration.p99",
|
|
11
|
+
SpanStatusOk = "oneuptime.span.status.ok",
|
|
12
|
+
SpanStatusError = "oneuptime.span.status.error",
|
|
13
|
+
SpanStatusUnset = "oneuptime.span.status.unset",
|
|
14
|
+
SpanThroughput = "oneuptime.span.throughput",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default SpanMetricType;
|
|
@@ -7,6 +7,7 @@ import ChartCurve from "../Types/ChartCurve";
|
|
|
7
7
|
import ChartDataPoint from "../ChartLibrary/Types/ChartDataPoint";
|
|
8
8
|
import DataPointUtil from "../Utils/DataPoint";
|
|
9
9
|
import ChartReferenceLineProps from "../Types/ReferenceLineProps";
|
|
10
|
+
import NoDataMessage from "../ChartGroup/NoDataMessage";
|
|
10
11
|
|
|
11
12
|
export interface ComponentProps {
|
|
12
13
|
data: Array<SeriesPoint>;
|
|
@@ -32,12 +33,8 @@ const AreaChartElement: FunctionComponent<AreaInternalProps> = (
|
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
useEffect(() => {
|
|
35
|
-
if (!props.data || props.data.length === 0) {
|
|
36
|
-
setRecords([]);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
const records: Array<ChartDataPoint> = DataPointUtil.getChartDataPoints({
|
|
40
|
-
seriesPoints: props.data,
|
|
37
|
+
seriesPoints: props.data || [],
|
|
41
38
|
xAxis: props.xAxis,
|
|
42
39
|
yAxis: props.yAxis,
|
|
43
40
|
});
|
|
@@ -50,35 +47,45 @@ const AreaChartElement: FunctionComponent<AreaInternalProps> = (
|
|
|
50
47
|
? { height: `${props.heightInPx}px` }
|
|
51
48
|
: {};
|
|
52
49
|
|
|
50
|
+
const hasNoData: boolean =
|
|
51
|
+
!props.data ||
|
|
52
|
+
props.data.length === 0 ||
|
|
53
|
+
props.data.every((series: SeriesPoint) => {
|
|
54
|
+
return series.data.length === 0;
|
|
55
|
+
});
|
|
56
|
+
|
|
53
57
|
return (
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
58
|
+
<div className="relative">
|
|
59
|
+
<AreaChart
|
|
60
|
+
className={className}
|
|
61
|
+
style={style}
|
|
62
|
+
data={records}
|
|
63
|
+
tickGap={1}
|
|
64
|
+
index={"Time"}
|
|
65
|
+
categories={categories}
|
|
66
|
+
colors={[
|
|
67
|
+
"blue",
|
|
68
|
+
"emerald",
|
|
69
|
+
"violet",
|
|
70
|
+
"amber",
|
|
71
|
+
"cyan",
|
|
72
|
+
"pink",
|
|
73
|
+
"lime",
|
|
74
|
+
"fuchsia",
|
|
75
|
+
"indigo",
|
|
76
|
+
"rose",
|
|
77
|
+
]}
|
|
78
|
+
valueFormatter={props.yAxis.options.formatter || undefined}
|
|
79
|
+
showTooltip={true}
|
|
80
|
+
connectNulls={true}
|
|
81
|
+
curve={props.curve || ChartCurve.MONOTONE}
|
|
82
|
+
syncid={props.sync ? props.syncid : undefined}
|
|
83
|
+
yAxisWidth={60}
|
|
84
|
+
onValueChange={() => {}}
|
|
85
|
+
referenceLines={props.referenceLines}
|
|
86
|
+
/>
|
|
87
|
+
{hasNoData && <NoDataMessage />}
|
|
88
|
+
</div>
|
|
82
89
|
);
|
|
83
90
|
};
|
|
84
91
|
|
|
@@ -6,6 +6,7 @@ import YAxis from "../Types/YAxis/YAxis";
|
|
|
6
6
|
import ChartDataPoint from "../ChartLibrary/Types/ChartDataPoint";
|
|
7
7
|
import DataPointUtil from "../Utils/DataPoint";
|
|
8
8
|
import ChartReferenceLineProps from "../Types/ReferenceLineProps";
|
|
9
|
+
import NoDataMessage from "../ChartGroup/NoDataMessage";
|
|
9
10
|
|
|
10
11
|
export interface ComponentProps {
|
|
11
12
|
data: Array<SeriesPoint>;
|
|
@@ -30,12 +31,8 @@ const BarChartElement: FunctionComponent<BarInternalProps> = (
|
|
|
30
31
|
});
|
|
31
32
|
|
|
32
33
|
useEffect(() => {
|
|
33
|
-
if (!props.data || props.data.length === 0) {
|
|
34
|
-
setRecords([]);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
34
|
const records: Array<ChartDataPoint> = DataPointUtil.getChartDataPoints({
|
|
38
|
-
seriesPoints: props.data,
|
|
35
|
+
seriesPoints: props.data || [],
|
|
39
36
|
xAxis: props.xAxis,
|
|
40
37
|
yAxis: props.yAxis,
|
|
41
38
|
});
|
|
@@ -48,32 +45,42 @@ const BarChartElement: FunctionComponent<BarInternalProps> = (
|
|
|
48
45
|
? { height: `${props.heightInPx}px` }
|
|
49
46
|
: {};
|
|
50
47
|
|
|
48
|
+
const hasNoData: boolean =
|
|
49
|
+
!props.data ||
|
|
50
|
+
props.data.length === 0 ||
|
|
51
|
+
props.data.every((series: SeriesPoint) => {
|
|
52
|
+
return series.data.length === 0;
|
|
53
|
+
});
|
|
54
|
+
|
|
51
55
|
return (
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
<div className="relative">
|
|
57
|
+
<BarChart
|
|
58
|
+
className={className}
|
|
59
|
+
style={style}
|
|
60
|
+
data={records}
|
|
61
|
+
tickGap={1}
|
|
62
|
+
index={"Time"}
|
|
63
|
+
categories={categories}
|
|
64
|
+
colors={[
|
|
65
|
+
"indigo",
|
|
66
|
+
"rose",
|
|
67
|
+
"emerald",
|
|
68
|
+
"amber",
|
|
69
|
+
"cyan",
|
|
70
|
+
"gray",
|
|
71
|
+
"pink",
|
|
72
|
+
"lime",
|
|
73
|
+
"fuchsia",
|
|
74
|
+
]}
|
|
75
|
+
valueFormatter={props.yAxis.options.formatter || undefined}
|
|
76
|
+
showTooltip={true}
|
|
77
|
+
yAxisWidth={60}
|
|
78
|
+
syncid={props.sync ? props.syncid : undefined}
|
|
79
|
+
onValueChange={() => {}}
|
|
80
|
+
referenceLines={props.referenceLines}
|
|
81
|
+
/>
|
|
82
|
+
{hasNoData && <NoDataMessage />}
|
|
83
|
+
</div>
|
|
77
84
|
);
|
|
78
85
|
};
|
|
79
86
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Text from "../../../../Types/Text";
|
|
2
|
+
import Dictionary from "../../../../Types/Dictionary";
|
|
2
3
|
import LineChart, { ComponentProps as LineChartProps } from "../Line/LineChart";
|
|
3
4
|
import BarChartElement, {
|
|
4
5
|
ComponentProps as BarChartProps,
|
|
@@ -6,7 +7,10 @@ import BarChartElement, {
|
|
|
6
7
|
import AreaChartElement, {
|
|
7
8
|
ComponentProps as AreaChartProps,
|
|
8
9
|
} from "../Area/AreaChart";
|
|
9
|
-
import
|
|
10
|
+
import Icon, { SizeProp } from "../../Icon/Icon";
|
|
11
|
+
import IconProp from "../../../../Types/Icon/IconProp";
|
|
12
|
+
import Modal, { ModalWidth } from "../../Modal/Modal";
|
|
13
|
+
import React, { FunctionComponent, ReactElement, useState } from "react";
|
|
10
14
|
|
|
11
15
|
export enum ChartType {
|
|
12
16
|
LINE = "line",
|
|
@@ -14,12 +18,21 @@ export enum ChartType {
|
|
|
14
18
|
AREA = "area",
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
export interface ChartMetricInfo {
|
|
22
|
+
metricName: string;
|
|
23
|
+
aggregationType: string;
|
|
24
|
+
attributes?: Dictionary<string> | undefined;
|
|
25
|
+
groupByAttribute?: string | undefined;
|
|
26
|
+
unit?: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
export interface Chart {
|
|
18
30
|
id: string;
|
|
19
31
|
title: string;
|
|
20
32
|
description?: string | undefined;
|
|
21
33
|
type: ChartType;
|
|
22
34
|
props: LineChartProps | BarChartProps | AreaChartProps;
|
|
35
|
+
metricInfo?: ChartMetricInfo | undefined;
|
|
23
36
|
}
|
|
24
37
|
|
|
25
38
|
export interface ComponentProps {
|
|
@@ -33,6 +46,8 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
|
|
|
33
46
|
props: ComponentProps,
|
|
34
47
|
): ReactElement => {
|
|
35
48
|
const syncId: string = Text.generateRandomText(10);
|
|
49
|
+
const [metricInfoModalChart, setMetricInfoModalChart] =
|
|
50
|
+
useState<ChartMetricInfo | null>(null);
|
|
36
51
|
|
|
37
52
|
const isLastChart: (index: number) => boolean = (index: number): boolean => {
|
|
38
53
|
return index === props.charts.length - 1;
|
|
@@ -77,33 +92,157 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
|
|
|
77
92
|
}
|
|
78
93
|
};
|
|
79
94
|
|
|
95
|
+
type GetInfoIconFunction = (chart: Chart) => ReactElement;
|
|
96
|
+
|
|
97
|
+
const getInfoIcon: GetInfoIconFunction = (chart: Chart): ReactElement => {
|
|
98
|
+
if (!chart.metricInfo) {
|
|
99
|
+
return <></>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
className="ml-1.5 inline-flex items-center justify-center rounded-full w-5 h-5 text-gray-300 hover:text-gray-500 hover:bg-gray-100 transition-all duration-150"
|
|
106
|
+
title="View metric details"
|
|
107
|
+
onClick={() => {
|
|
108
|
+
setMetricInfoModalChart(chart.metricInfo || null);
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<Icon
|
|
112
|
+
icon={IconProp.InformationCircle}
|
|
113
|
+
size={SizeProp.Smaller}
|
|
114
|
+
className="h-3.5 w-3.5"
|
|
115
|
+
/>
|
|
116
|
+
</button>
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const renderMetricInfoModal: () => ReactElement = (): ReactElement => {
|
|
121
|
+
if (!metricInfoModalChart) {
|
|
122
|
+
return <></>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const attributes: Dictionary<string> =
|
|
126
|
+
metricInfoModalChart.attributes || {};
|
|
127
|
+
const attributeKeys: Array<string> = Object.keys(attributes);
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Modal
|
|
131
|
+
title="Metric Details"
|
|
132
|
+
onClose={() => {
|
|
133
|
+
setMetricInfoModalChart(null);
|
|
134
|
+
}}
|
|
135
|
+
onSubmit={() => {
|
|
136
|
+
setMetricInfoModalChart(null);
|
|
137
|
+
}}
|
|
138
|
+
submitButtonText="Close"
|
|
139
|
+
modalWidth={ModalWidth.Normal}
|
|
140
|
+
>
|
|
141
|
+
<div className="space-y-4">
|
|
142
|
+
<div className="rounded-lg border border-gray-200 bg-gray-50 p-4">
|
|
143
|
+
<table className="w-full text-sm">
|
|
144
|
+
<tbody>
|
|
145
|
+
<tr className="border-b border-gray-200">
|
|
146
|
+
<td className="py-2.5 pr-4 font-medium text-gray-500 whitespace-nowrap">
|
|
147
|
+
Metric Name
|
|
148
|
+
</td>
|
|
149
|
+
<td className="py-2.5 text-gray-900 font-mono text-xs">
|
|
150
|
+
{metricInfoModalChart.metricName}
|
|
151
|
+
</td>
|
|
152
|
+
</tr>
|
|
153
|
+
<tr className="border-b border-gray-200">
|
|
154
|
+
<td className="py-2.5 pr-4 font-medium text-gray-500 whitespace-nowrap">
|
|
155
|
+
Aggregation
|
|
156
|
+
</td>
|
|
157
|
+
<td className="py-2.5 text-gray-900">
|
|
158
|
+
{metricInfoModalChart.aggregationType}
|
|
159
|
+
</td>
|
|
160
|
+
</tr>
|
|
161
|
+
{metricInfoModalChart.unit && (
|
|
162
|
+
<tr className="border-b border-gray-200">
|
|
163
|
+
<td className="py-2.5 pr-4 font-medium text-gray-500 whitespace-nowrap">
|
|
164
|
+
Unit
|
|
165
|
+
</td>
|
|
166
|
+
<td className="py-2.5 text-gray-900">
|
|
167
|
+
{metricInfoModalChart.unit}
|
|
168
|
+
</td>
|
|
169
|
+
</tr>
|
|
170
|
+
)}
|
|
171
|
+
{metricInfoModalChart.groupByAttribute && (
|
|
172
|
+
<tr className="border-b border-gray-200">
|
|
173
|
+
<td className="py-2.5 pr-4 font-medium text-gray-500 whitespace-nowrap">
|
|
174
|
+
Grouped By
|
|
175
|
+
</td>
|
|
176
|
+
<td className="py-2.5 text-gray-900 font-mono text-xs">
|
|
177
|
+
{metricInfoModalChart.groupByAttribute}
|
|
178
|
+
</td>
|
|
179
|
+
</tr>
|
|
180
|
+
)}
|
|
181
|
+
{attributeKeys.length > 0 && (
|
|
182
|
+
<tr>
|
|
183
|
+
<td className="py-2.5 pr-4 font-medium text-gray-500 whitespace-nowrap align-top">
|
|
184
|
+
Attributes
|
|
185
|
+
</td>
|
|
186
|
+
<td className="py-2.5">
|
|
187
|
+
<div className="space-y-1.5">
|
|
188
|
+
{attributeKeys.map((key: string) => {
|
|
189
|
+
return (
|
|
190
|
+
<div key={key} className="flex items-center gap-2">
|
|
191
|
+
<span className="inline-flex items-center rounded bg-gray-200 px-2 py-0.5 text-xs font-mono text-gray-700">
|
|
192
|
+
{key}
|
|
193
|
+
</span>
|
|
194
|
+
<span className="text-gray-400">=</span>
|
|
195
|
+
<span className="text-xs text-gray-900 font-mono">
|
|
196
|
+
{attributes[key]}
|
|
197
|
+
</span>
|
|
198
|
+
</div>
|
|
199
|
+
);
|
|
200
|
+
})}
|
|
201
|
+
</div>
|
|
202
|
+
</td>
|
|
203
|
+
</tr>
|
|
204
|
+
)}
|
|
205
|
+
</tbody>
|
|
206
|
+
</table>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
</Modal>
|
|
210
|
+
);
|
|
211
|
+
};
|
|
212
|
+
|
|
80
213
|
// When hideCard is true, render charts in a clean vertical stack with dividers
|
|
81
214
|
if (props.hideCard) {
|
|
82
215
|
return (
|
|
83
|
-
|
|
84
|
-
{
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
216
|
+
<>
|
|
217
|
+
{renderMetricInfoModal()}
|
|
218
|
+
<div className="space-y-0">
|
|
219
|
+
{props.charts.map((chart: Chart, index: number) => {
|
|
220
|
+
return (
|
|
221
|
+
<div
|
|
222
|
+
key={index}
|
|
223
|
+
className={`${!isLastChart(index) ? "border-b border-gray-100" : ""} ${props.chartCssClass || ""}`}
|
|
224
|
+
>
|
|
225
|
+
<div className="px-1 pt-5 pb-4">
|
|
226
|
+
<div className="mb-1">
|
|
227
|
+
<div className="flex items-center">
|
|
228
|
+
<h3 className="text-sm font-semibold text-gray-700 tracking-tight">
|
|
229
|
+
{chart.title}
|
|
230
|
+
</h3>
|
|
231
|
+
{getInfoIcon(chart)}
|
|
232
|
+
</div>
|
|
233
|
+
{chart.description && (
|
|
234
|
+
<p className="mt-0.5 text-xs text-gray-400 hidden md:block">
|
|
235
|
+
{chart.description}
|
|
236
|
+
</p>
|
|
237
|
+
)}
|
|
238
|
+
</div>
|
|
239
|
+
{getChartContent(chart, index)}
|
|
100
240
|
</div>
|
|
101
|
-
{getChartContent(chart, index)}
|
|
102
241
|
</div>
|
|
103
|
-
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
242
|
+
);
|
|
243
|
+
})}
|
|
244
|
+
</div>
|
|
245
|
+
</>
|
|
107
246
|
);
|
|
108
247
|
}
|
|
109
248
|
|
|
@@ -112,35 +251,41 @@ const ChartGroup: FunctionComponent<ComponentProps> = (
|
|
|
112
251
|
props.charts.length > 1 ? "lg:grid-cols-2" : "lg:grid-cols-1";
|
|
113
252
|
|
|
114
253
|
return (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
data-testid="card-details-heading"
|
|
126
|
-
id="card-details-heading"
|
|
127
|
-
className="text-base font-semibold leading-6 text-gray-900"
|
|
254
|
+
<>
|
|
255
|
+
{renderMetricInfoModal()}
|
|
256
|
+
<div
|
|
257
|
+
className={`grid grid-cols-1 ${gridCols} gap-4 space-y-4 lg:space-y-0`}
|
|
258
|
+
>
|
|
259
|
+
{props.charts.map((chart: Chart, index: number) => {
|
|
260
|
+
return (
|
|
261
|
+
<div
|
|
262
|
+
key={index}
|
|
263
|
+
className={`p-5 rounded-lg border border-gray-200 bg-white shadow-sm ${props.chartCssClass || ""}`}
|
|
128
264
|
>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
265
|
+
<div className="flex items-center">
|
|
266
|
+
<h2
|
|
267
|
+
data-testid="card-details-heading"
|
|
268
|
+
id="card-details-heading"
|
|
269
|
+
className="text-base font-semibold leading-6 text-gray-900"
|
|
270
|
+
>
|
|
271
|
+
{chart.title}
|
|
272
|
+
</h2>
|
|
273
|
+
{getInfoIcon(chart)}
|
|
274
|
+
</div>
|
|
275
|
+
{chart.description && (
|
|
276
|
+
<p
|
|
277
|
+
data-testid="card-description"
|
|
278
|
+
className="mt-0.5 text-sm text-gray-500 w-full hidden md:block"
|
|
279
|
+
>
|
|
280
|
+
{chart.description}
|
|
281
|
+
</p>
|
|
282
|
+
)}
|
|
283
|
+
{getChartContent(chart, index)}
|
|
284
|
+
</div>
|
|
285
|
+
);
|
|
286
|
+
})}
|
|
287
|
+
</div>
|
|
288
|
+
</>
|
|
144
289
|
);
|
|
145
290
|
};
|
|
146
291
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { FunctionComponent, ReactElement } from "react";
|
|
2
|
+
|
|
3
|
+
const NoDataMessage: FunctionComponent = (): ReactElement => {
|
|
4
|
+
return (
|
|
5
|
+
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
|
6
|
+
<span className="text-sm text-gray-400 bg-white/90 border border-gray-100 rounded-full px-4 py-1.5 shadow-sm">
|
|
7
|
+
No data available
|
|
8
|
+
</span>
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default NoDataMessage;
|