@perses-dev/scatter-chart-plugin 0.6.0
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/LICENSE +201 -0
- package/README.md +41 -0
- package/__mf/css/async/341.9c79ef64.css +1 -0
- package/__mf/css/async/564.9c79ef64.css +1 -0
- package/__mf/font/lato-all-300-normal.322bdf14.woff +0 -0
- package/__mf/font/lato-all-400-normal.63513b00.woff +0 -0
- package/__mf/font/lato-all-700-normal.bb27db94.woff +0 -0
- package/__mf/font/lato-all-900-normal.a27049a3.woff +0 -0
- package/__mf/font/lato-latin-300-normal.c5195215.woff2 +0 -0
- package/__mf/font/lato-latin-400-normal.b7ffde23.woff2 +0 -0
- package/__mf/font/lato-latin-700-normal.d5eb20bc.woff2 +0 -0
- package/__mf/font/lato-latin-900-normal.d884a71c.woff2 +0 -0
- package/__mf/font/lato-latin-ext-300-normal.abcc64a9.woff2 +0 -0
- package/__mf/font/lato-latin-ext-400-normal.6ebed106.woff2 +0 -0
- package/__mf/font/lato-latin-ext-700-normal.8697d1d5.woff2 +0 -0
- package/__mf/font/lato-latin-ext-900-normal.20a2b415.woff2 +0 -0
- package/__mf/js/527.d3310177.js +2 -0
- package/__mf/js/527.d3310177.js.LICENSE.txt +24 -0
- package/__mf/js/792.6224e3b1.js +6 -0
- package/__mf/js/792.6224e3b1.js.LICENSE.txt +9 -0
- package/__mf/js/ScatterChart.907123a8.js +5 -0
- package/__mf/js/async/150.4fc9e087.js +2 -0
- package/__mf/js/async/150.4fc9e087.js.LICENSE.txt +21 -0
- package/__mf/js/async/156.c11b1700.js +1 -0
- package/__mf/js/async/173.c19d3b98.js +2 -0
- package/__mf/js/async/173.c19d3b98.js.LICENSE.txt +19 -0
- package/__mf/js/async/507.3d416130.js +174 -0
- package/__mf/js/async/507.3d416130.js.LICENSE.txt +55 -0
- package/__mf/js/async/564.e5b95c38.js +2 -0
- package/__mf/js/async/564.e5b95c38.js.LICENSE.txt +9 -0
- package/__mf/js/async/651.791f807e.js +1 -0
- package/__mf/js/async/694.903128f9.js +1 -0
- package/__mf/js/async/740.c78d3483.js +1 -0
- package/__mf/js/async/75.06e41df4.js +1 -0
- package/__mf/js/async/770.da7255d0.js +1 -0
- package/__mf/js/async/960.e791a996.js +2 -0
- package/__mf/js/async/960.e791a996.js.LICENSE.txt +8 -0
- package/__mf/js/async/964.34b88a18.js +2 -0
- package/__mf/js/async/964.34b88a18.js.LICENSE.txt +9 -0
- package/__mf/js/async/__federation_expose_ScatterChart.9e6627ee.js +2 -0
- package/__mf/js/async/__federation_expose_ScatterChart.9e6627ee.js.LICENSE.txt +9 -0
- package/__mf/js/index.b48f09c4.js +1 -0
- package/lib/ScatterChart.d.ts +8 -0
- package/lib/ScatterChart.d.ts.map +1 -0
- package/lib/ScatterChart.js +27 -0
- package/lib/ScatterChart.js.map +1 -0
- package/lib/ScatterChartPanel.d.ts +37 -0
- package/lib/ScatterChartPanel.d.ts.map +1 -0
- package/lib/ScatterChartPanel.js +182 -0
- package/lib/ScatterChartPanel.js.map +1 -0
- package/lib/Scatterplot.d.ts +11 -0
- package/lib/Scatterplot.d.ts.map +1 -0
- package/lib/Scatterplot.js +113 -0
- package/lib/Scatterplot.js.map +1 -0
- package/lib/bootstrap.d.ts +2 -0
- package/lib/bootstrap.d.ts.map +1 -0
- package/lib/bootstrap.js +19 -0
- package/lib/bootstrap.js.map +1 -0
- package/lib/cjs/ScatterChart.js +33 -0
- package/lib/cjs/ScatterChartPanel.js +183 -0
- package/lib/cjs/Scatterplot.js +121 -0
- package/lib/cjs/bootstrap.js +26 -0
- package/lib/cjs/env.d.js +14 -0
- package/lib/cjs/getPluginModule.js +27 -0
- package/lib/cjs/index-federation.js +55 -0
- package/lib/cjs/index.js +28 -0
- package/lib/cjs/mock-trace-data.js +145 -0
- package/lib/cjs/scatter-chart-model.js +25 -0
- package/lib/cjs/setup-tests.js +19 -0
- package/lib/env.d.js +15 -0
- package/lib/env.d.js.map +1 -0
- package/lib/getPluginModule.d.ts +6 -0
- package/lib/getPluginModule.d.ts.map +1 -0
- package/lib/getPluginModule.js +16 -0
- package/lib/getPluginModule.js.map +1 -0
- package/lib/index-federation.d.ts +1 -0
- package/lib/index-federation.d.ts.map +1 -0
- package/lib/index-federation.js +15 -0
- package/lib/index-federation.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/mock-trace-data.d.ts +88 -0
- package/lib/mock-trace-data.d.ts.map +1 -0
- package/lib/mock-trace-data.js +129 -0
- package/lib/mock-trace-data.js.map +1 -0
- package/lib/scatter-chart-model.d.ts +14 -0
- package/lib/scatter-chart-model.d.ts.map +1 -0
- package/lib/scatter-chart-model.js +19 -0
- package/lib/scatter-chart-model.js.map +1 -0
- package/lib/setup-tests.d.ts +2 -0
- package/lib/setup-tests.d.ts.map +1 -0
- package/lib/setup-tests.js +17 -0
- package/lib/setup-tests.js.map +1 -0
- package/mf-manifest.json +212 -0
- package/mf-stats.json +235 -0
- package/package.json +55 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import { useMemo } from 'react';
|
|
15
|
+
import { NoDataOverlay, useChartsTheme } from '@perses-dev/components';
|
|
16
|
+
import { Scatterplot } from './Scatterplot';
|
|
17
|
+
/** default size range of the circles diameter */ const DEFAULT_SIZE_RANGE = [
|
|
18
|
+
6,
|
|
19
|
+
20
|
|
20
|
+
];
|
|
21
|
+
// Navigate to the Gantt Chart on the explore page by default
|
|
22
|
+
function defaultClickHandler(data) {
|
|
23
|
+
// clone the original query spec (including the datasource) and replace the query value with the trace id
|
|
24
|
+
const query = JSON.parse(JSON.stringify(data.query));
|
|
25
|
+
query.spec.plugin.spec.query = data.traceId;
|
|
26
|
+
const exploreParams = new URLSearchParams({
|
|
27
|
+
explorer: 'traces',
|
|
28
|
+
data: JSON.stringify({
|
|
29
|
+
queries: [
|
|
30
|
+
query
|
|
31
|
+
]
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
// do not use react-router here, as downstream products, which embed this panel, may not have a compatible version of it
|
|
35
|
+
window.location.href = `/explore?${exploreParams}`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* ScatterChartPanel receives data from the DataQueriesProvider and transforms it
|
|
39
|
+
* into a `dataset` object that Apache ECharts can consume. Additionally,
|
|
40
|
+
* data formatting is also dictated in this component. Formatting includes
|
|
41
|
+
* datapoint size and color.
|
|
42
|
+
*
|
|
43
|
+
* Documentation for data structures accepted by Apache ECharts:
|
|
44
|
+
* https://echarts.apache.org/handbook/en/concepts/dataset
|
|
45
|
+
*
|
|
46
|
+
* Examples for scatter chart formatting in Apache ECharts:
|
|
47
|
+
* https://echarts.apache.org/examples/en/index.html#chart-type-scatter
|
|
48
|
+
*
|
|
49
|
+
* @returns a `ScatterPlot` component that contains an EChart which will handle
|
|
50
|
+
* visualization of the data.
|
|
51
|
+
*/ export function ScatterChartPanel(props) {
|
|
52
|
+
const { spec, contentDimensions, queryResults: traceResults, onClick } = props;
|
|
53
|
+
const chartsTheme = useChartsTheme();
|
|
54
|
+
const defaultColor = chartsTheme.thresholds.defaultColor || 'blue';
|
|
55
|
+
const sizeRange = spec.sizeRange || DEFAULT_SIZE_RANGE;
|
|
56
|
+
// Generate dataset
|
|
57
|
+
// Transform Tempo API response to fit 'dataset' structure from Apache ECharts
|
|
58
|
+
// https://echarts.apache.org/handbook/en/concepts/dataset
|
|
59
|
+
const { dataset, minSpanCount, maxSpanCount } = useMemo(()=>{
|
|
60
|
+
const dataset = [];
|
|
61
|
+
let minSpanCount;
|
|
62
|
+
let maxSpanCount;
|
|
63
|
+
for (const result of traceResults){
|
|
64
|
+
if (result.data.searchResult === undefined) continue;
|
|
65
|
+
const dataSeries = result.data.searchResult.map((trace)=>{
|
|
66
|
+
let spanCount = 0;
|
|
67
|
+
let errorCount = 0;
|
|
68
|
+
for (const stats of Object.values(trace.serviceStats)){
|
|
69
|
+
spanCount += stats.spanCount;
|
|
70
|
+
errorCount += stats.errorCount ?? 0;
|
|
71
|
+
}
|
|
72
|
+
if (minSpanCount === undefined || spanCount < minSpanCount) {
|
|
73
|
+
minSpanCount = spanCount;
|
|
74
|
+
}
|
|
75
|
+
if (maxSpanCount === undefined || spanCount > maxSpanCount) {
|
|
76
|
+
maxSpanCount = spanCount;
|
|
77
|
+
}
|
|
78
|
+
const newTraceValue = {
|
|
79
|
+
...trace,
|
|
80
|
+
query: result.definition,
|
|
81
|
+
name: `${trace.rootServiceName}: ${trace.rootTraceName}`,
|
|
82
|
+
startTime: new Date(trace.startTimeUnixMs),
|
|
83
|
+
spanCount,
|
|
84
|
+
errorCount
|
|
85
|
+
};
|
|
86
|
+
return newTraceValue;
|
|
87
|
+
});
|
|
88
|
+
dataset.push({
|
|
89
|
+
source: dataSeries
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
dataset,
|
|
94
|
+
minSpanCount: minSpanCount ?? 0,
|
|
95
|
+
maxSpanCount: maxSpanCount ?? 0
|
|
96
|
+
};
|
|
97
|
+
}, [
|
|
98
|
+
traceResults
|
|
99
|
+
]);
|
|
100
|
+
// Formatting for the dataset
|
|
101
|
+
// 1. Map x,y coordinates
|
|
102
|
+
// 2. Datapoint size corresponds to the number of spans in a trace
|
|
103
|
+
// 3. Color datapoint red if the trace contains an error
|
|
104
|
+
const series = useMemo(()=>{
|
|
105
|
+
const seriesTemplate2 = {
|
|
106
|
+
type: 'scatter',
|
|
107
|
+
encode: {
|
|
108
|
+
// Map to x-axis.
|
|
109
|
+
x: 'startTime',
|
|
110
|
+
// Map to y-axis.
|
|
111
|
+
y: 'durationMs'
|
|
112
|
+
},
|
|
113
|
+
symbolSize: function(data) {
|
|
114
|
+
// returns the diameter of the circles
|
|
115
|
+
return getSymbolSize(data.spanCount, [
|
|
116
|
+
minSpanCount,
|
|
117
|
+
maxSpanCount
|
|
118
|
+
], sizeRange);
|
|
119
|
+
},
|
|
120
|
+
itemStyle: {
|
|
121
|
+
color: function(params) {
|
|
122
|
+
const traceData = params.data;
|
|
123
|
+
// If the trace contains an error, color the datapoint in red
|
|
124
|
+
if (traceData.errorCount > 0) {
|
|
125
|
+
return 'red';
|
|
126
|
+
}
|
|
127
|
+
// Else return default color
|
|
128
|
+
return defaultColor;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
// Each data set needs to have a corresponding series formatting object
|
|
133
|
+
const series = [];
|
|
134
|
+
for(let i = 0; i < dataset.length; i++){
|
|
135
|
+
series.push({
|
|
136
|
+
...seriesTemplate2,
|
|
137
|
+
datasetIndex: i
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return series;
|
|
141
|
+
}, [
|
|
142
|
+
dataset,
|
|
143
|
+
defaultColor,
|
|
144
|
+
minSpanCount,
|
|
145
|
+
maxSpanCount,
|
|
146
|
+
sizeRange
|
|
147
|
+
]);
|
|
148
|
+
const tracesFound = traceResults.some((traceData)=>(traceData.data?.searchResult ?? []).length > 0);
|
|
149
|
+
if (!tracesFound) {
|
|
150
|
+
return /*#__PURE__*/ _jsx(NoDataOverlay, {
|
|
151
|
+
resource: "traces"
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const options = {
|
|
155
|
+
dataset: dataset,
|
|
156
|
+
series: series
|
|
157
|
+
};
|
|
158
|
+
if (contentDimensions === undefined) return null;
|
|
159
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
160
|
+
"data-testid": "ScatterChartPanel_ScatterPlot",
|
|
161
|
+
children: /*#__PURE__*/ _jsx(Scatterplot, {
|
|
162
|
+
width: contentDimensions.width,
|
|
163
|
+
height: contentDimensions.height,
|
|
164
|
+
options: options,
|
|
165
|
+
onClick: onClick === null ? undefined : onClick ?? defaultClickHandler
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// exported for tests
|
|
170
|
+
export function getSymbolSize(spanCount, spanCountRange, sizeRange) {
|
|
171
|
+
const [minSize, maxSize] = sizeRange;
|
|
172
|
+
const [minSpanCount, maxSpanCount] = spanCountRange;
|
|
173
|
+
// catch divison by zero
|
|
174
|
+
if (maxSpanCount - minSpanCount === 0) {
|
|
175
|
+
return maxSize;
|
|
176
|
+
}
|
|
177
|
+
// apply linear scale of spanCount from range [minSpanCount,maxSpanCount] to a value from range [minSize,maxSize]
|
|
178
|
+
const rel = (spanCount - minSpanCount) / (maxSpanCount - minSpanCount);
|
|
179
|
+
return minSize + (maxSize - minSize) * rel;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=ScatterChartPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/ScatterChartPanel.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { PanelProps } from '@perses-dev/plugin-system';\nimport { ReactElement, useMemo } from 'react';\nimport { QueryDefinition, TraceData, TraceSearchResult } from '@perses-dev/core';\nimport { EChartsOption, SeriesOption } from 'echarts';\nimport { NoDataOverlay, useChartsTheme } from '@perses-dev/components';\nimport { Scatterplot } from './Scatterplot';\nimport { ScatterChartOptions } from './scatter-chart-model';\n\nexport interface EChartTraceValue extends Omit<TraceSearchResult, 'startTimeUnixMs' | 'serviceStats'> {\n name: string;\n query: QueryDefinition;\n startTime: Date;\n spanCount: number;\n errorCount: number;\n}\n\nexport interface ScatterChartPanelProps extends PanelProps<ScatterChartOptions, TraceData> {\n /**\n * Custom onClick event handler.\n * If this field is unset or undefined, a default handler which links to the Gantt chart on the explore page is configured.\n * Set this field explicitly to null to disable handling the click event.\n */\n onClick?: ((data: EChartTraceValue) => void) | null;\n}\n\n/** default size range of the circles diameter */\nconst DEFAULT_SIZE_RANGE: [number, number] = [6, 20];\n\n// Navigate to the Gantt Chart on the explore page by default\nfunction defaultClickHandler(data: EChartTraceValue): void {\n // clone the original query spec (including the datasource) and replace the query value with the trace id\n const query: QueryDefinition = JSON.parse(JSON.stringify(data.query));\n query.spec.plugin.spec.query = data.traceId;\n\n const exploreParams = new URLSearchParams({\n explorer: 'traces',\n data: JSON.stringify({ queries: [query] }),\n });\n\n // do not use react-router here, as downstream products, which embed this panel, may not have a compatible version of it\n window.location.href = `/explore?${exploreParams}`;\n}\n\n/**\n * ScatterChartPanel receives data from the DataQueriesProvider and transforms it\n * into a `dataset` object that Apache ECharts can consume. Additionally,\n * data formatting is also dictated in this component. Formatting includes\n * datapoint size and color.\n *\n * Documentation for data structures accepted by Apache ECharts:\n * https://echarts.apache.org/handbook/en/concepts/dataset\n *\n * Examples for scatter chart formatting in Apache ECharts:\n * https://echarts.apache.org/examples/en/index.html#chart-type-scatter\n *\n * @returns a `ScatterPlot` component that contains an EChart which will handle\n * visualization of the data.\n */\nexport function ScatterChartPanel(props: ScatterChartPanelProps): ReactElement | null {\n const { spec, contentDimensions, queryResults: traceResults, onClick } = props;\n const chartsTheme = useChartsTheme();\n const defaultColor = chartsTheme.thresholds.defaultColor || 'blue';\n const sizeRange = spec.sizeRange || DEFAULT_SIZE_RANGE;\n\n // Generate dataset\n // Transform Tempo API response to fit 'dataset' structure from Apache ECharts\n // https://echarts.apache.org/handbook/en/concepts/dataset\n const { dataset, minSpanCount, maxSpanCount } = useMemo(() => {\n const dataset = [];\n let minSpanCount: number | undefined;\n let maxSpanCount: number | undefined;\n for (const result of traceResults) {\n if (result.data.searchResult === undefined) continue;\n const dataSeries = result.data.searchResult.map((trace) => {\n let spanCount = 0;\n let errorCount = 0;\n for (const stats of Object.values(trace.serviceStats)) {\n spanCount += stats.spanCount;\n errorCount += stats.errorCount ?? 0;\n }\n\n if (minSpanCount === undefined || spanCount < minSpanCount) {\n minSpanCount = spanCount;\n }\n if (maxSpanCount === undefined || spanCount > maxSpanCount) {\n maxSpanCount = spanCount;\n }\n\n const newTraceValue: EChartTraceValue = {\n ...trace,\n query: result.definition,\n name: `${trace.rootServiceName}: ${trace.rootTraceName}`,\n startTime: new Date(trace.startTimeUnixMs), // convert unix epoch time to Date\n spanCount,\n errorCount,\n };\n return newTraceValue;\n });\n dataset.push({\n source: dataSeries,\n });\n }\n return { dataset, minSpanCount: minSpanCount ?? 0, maxSpanCount: maxSpanCount ?? 0 };\n }, [traceResults]);\n\n // Formatting for the dataset\n // 1. Map x,y coordinates\n // 2. Datapoint size corresponds to the number of spans in a trace\n // 3. Color datapoint red if the trace contains an error\n const series = useMemo(() => {\n const seriesTemplate2: SeriesOption = {\n type: 'scatter',\n encode: {\n // Map to x-axis.\n x: 'startTime',\n // Map to y-axis.\n y: 'durationMs',\n },\n symbolSize: function (data) {\n // returns the diameter of the circles\n return getSymbolSize(data.spanCount, [minSpanCount, maxSpanCount], sizeRange);\n },\n itemStyle: {\n color: function (params) {\n const traceData: EChartTraceValue = params.data as EChartTraceValue;\n // If the trace contains an error, color the datapoint in red\n if (traceData.errorCount > 0) {\n return 'red';\n }\n // Else return default color\n return defaultColor;\n },\n },\n };\n\n // Each data set needs to have a corresponding series formatting object\n const series = [];\n for (let i = 0; i < dataset.length; i++) {\n series.push({ ...seriesTemplate2, datasetIndex: i });\n }\n return series;\n }, [dataset, defaultColor, minSpanCount, maxSpanCount, sizeRange]);\n\n const tracesFound = traceResults.some((traceData) => (traceData.data?.searchResult ?? []).length > 0);\n if (!tracesFound) {\n return <NoDataOverlay resource=\"traces\" />;\n }\n\n const options: EChartsOption = {\n dataset: dataset,\n series: series,\n };\n\n if (contentDimensions === undefined) return null;\n\n return (\n <div data-testid=\"ScatterChartPanel_ScatterPlot\">\n <Scatterplot\n width={contentDimensions.width}\n height={contentDimensions.height}\n options={options}\n onClick={onClick === null ? undefined : (onClick ?? defaultClickHandler)}\n />\n </div>\n );\n}\n\n// exported for tests\nexport function getSymbolSize(\n spanCount: number,\n spanCountRange: [number, number],\n sizeRange: [number, number]\n): number {\n const [minSize, maxSize] = sizeRange;\n const [minSpanCount, maxSpanCount] = spanCountRange;\n\n // catch divison by zero\n if (maxSpanCount - minSpanCount === 0) {\n return maxSize;\n }\n\n // apply linear scale of spanCount from range [minSpanCount,maxSpanCount] to a value from range [minSize,maxSize]\n const rel = (spanCount - minSpanCount) / (maxSpanCount - minSpanCount);\n return minSize + (maxSize - minSize) * rel;\n}\n"],"names":["useMemo","NoDataOverlay","useChartsTheme","Scatterplot","DEFAULT_SIZE_RANGE","defaultClickHandler","data","query","JSON","parse","stringify","spec","plugin","traceId","exploreParams","URLSearchParams","explorer","queries","window","location","href","ScatterChartPanel","props","contentDimensions","queryResults","traceResults","onClick","chartsTheme","defaultColor","thresholds","sizeRange","dataset","minSpanCount","maxSpanCount","result","searchResult","undefined","dataSeries","map","trace","spanCount","errorCount","stats","Object","values","serviceStats","newTraceValue","definition","name","rootServiceName","rootTraceName","startTime","Date","startTimeUnixMs","push","source","series","seriesTemplate2","type","encode","x","y","symbolSize","getSymbolSize","itemStyle","color","params","traceData","i","length","datasetIndex","tracesFound","some","resource","options","div","data-testid","width","height","spanCountRange","minSize","maxSize","rel"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAGjC,SAAuBA,OAAO,QAAQ,QAAQ;AAG9C,SAASC,aAAa,EAAEC,cAAc,QAAQ,yBAAyB;AACvE,SAASC,WAAW,QAAQ,gBAAgB;AAoB5C,+CAA+C,GAC/C,MAAMC,qBAAuC;IAAC;IAAG;CAAG;AAEpD,6DAA6D;AAC7D,SAASC,oBAAoBC,IAAsB;IACjD,yGAAyG;IACzG,MAAMC,QAAyBC,KAAKC,KAAK,CAACD,KAAKE,SAAS,CAACJ,KAAKC,KAAK;IACnEA,MAAMI,IAAI,CAACC,MAAM,CAACD,IAAI,CAACJ,KAAK,GAAGD,KAAKO,OAAO;IAE3C,MAAMC,gBAAgB,IAAIC,gBAAgB;QACxCC,UAAU;QACVV,MAAME,KAAKE,SAAS,CAAC;YAAEO,SAAS;gBAACV;aAAM;QAAC;IAC1C;IAEA,wHAAwH;IACxHW,OAAOC,QAAQ,CAACC,IAAI,GAAG,CAAC,SAAS,EAAEN,eAAe;AACpD;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASO,kBAAkBC,KAA6B;IAC7D,MAAM,EAAEX,IAAI,EAAEY,iBAAiB,EAAEC,cAAcC,YAAY,EAAEC,OAAO,EAAE,GAAGJ;IACzE,MAAMK,cAAczB;IACpB,MAAM0B,eAAeD,YAAYE,UAAU,CAACD,YAAY,IAAI;IAC5D,MAAME,YAAYnB,KAAKmB,SAAS,IAAI1B;IAEpC,mBAAmB;IACnB,8EAA8E;IAC9E,0DAA0D;IAC1D,MAAM,EAAE2B,OAAO,EAAEC,YAAY,EAAEC,YAAY,EAAE,GAAGjC,QAAQ;QACtD,MAAM+B,UAAU,EAAE;QAClB,IAAIC;QACJ,IAAIC;QACJ,KAAK,MAAMC,UAAUT,aAAc;YACjC,IAAIS,OAAO5B,IAAI,CAAC6B,YAAY,KAAKC,WAAW;YAC5C,MAAMC,aAAaH,OAAO5B,IAAI,CAAC6B,YAAY,CAACG,GAAG,CAAC,CAACC;gBAC/C,IAAIC,YAAY;gBAChB,IAAIC,aAAa;gBACjB,KAAK,MAAMC,SAASC,OAAOC,MAAM,CAACL,MAAMM,YAAY,EAAG;oBACrDL,aAAaE,MAAMF,SAAS;oBAC5BC,cAAcC,MAAMD,UAAU,IAAI;gBACpC;gBAEA,IAAIT,iBAAiBI,aAAaI,YAAYR,cAAc;oBAC1DA,eAAeQ;gBACjB;gBACA,IAAIP,iBAAiBG,aAAaI,YAAYP,cAAc;oBAC1DA,eAAeO;gBACjB;gBAEA,MAAMM,gBAAkC;oBACtC,GAAGP,KAAK;oBACRhC,OAAO2B,OAAOa,UAAU;oBACxBC,MAAM,GAAGT,MAAMU,eAAe,CAAC,EAAE,EAAEV,MAAMW,aAAa,EAAE;oBACxDC,WAAW,IAAIC,KAAKb,MAAMc,eAAe;oBACzCb;oBACAC;gBACF;gBACA,OAAOK;YACT;YACAf,QAAQuB,IAAI,CAAC;gBACXC,QAAQlB;YACV;QACF;QACA,OAAO;YAAEN;YAASC,cAAcA,gBAAgB;YAAGC,cAAcA,gBAAgB;QAAE;IACrF,GAAG;QAACR;KAAa;IAEjB,6BAA6B;IAC7B,yBAAyB;IACzB,kEAAkE;IAClE,wDAAwD;IACxD,MAAM+B,SAASxD,QAAQ;QACrB,MAAMyD,kBAAgC;YACpCC,MAAM;YACNC,QAAQ;gBACN,iBAAiB;gBACjBC,GAAG;gBACH,iBAAiB;gBACjBC,GAAG;YACL;YACAC,YAAY,SAAUxD,IAAI;gBACxB,sCAAsC;gBACtC,OAAOyD,cAAczD,KAAKkC,SAAS,EAAE;oBAACR;oBAAcC;iBAAa,EAAEH;YACrE;YACAkC,WAAW;gBACTC,OAAO,SAAUC,MAAM;oBACrB,MAAMC,YAA8BD,OAAO5D,IAAI;oBAC/C,6DAA6D;oBAC7D,IAAI6D,UAAU1B,UAAU,GAAG,GAAG;wBAC5B,OAAO;oBACT;oBACA,4BAA4B;oBAC5B,OAAOb;gBACT;YACF;QACF;QAEA,uEAAuE;QACvE,MAAM4B,SAAS,EAAE;QACjB,IAAK,IAAIY,IAAI,GAAGA,IAAIrC,QAAQsC,MAAM,EAAED,IAAK;YACvCZ,OAAOF,IAAI,CAAC;gBAAE,GAAGG,eAAe;gBAAEa,cAAcF;YAAE;QACpD;QACA,OAAOZ;IACT,GAAG;QAACzB;QAASH;QAAcI;QAAcC;QAAcH;KAAU;IAEjE,MAAMyC,cAAc9C,aAAa+C,IAAI,CAAC,CAACL,YAAc,AAACA,CAAAA,UAAU7D,IAAI,EAAE6B,gBAAgB,EAAE,AAAD,EAAGkC,MAAM,GAAG;IACnG,IAAI,CAACE,aAAa;QAChB,qBAAO,KAACtE;YAAcwE,UAAS;;IACjC;IAEA,MAAMC,UAAyB;QAC7B3C,SAASA;QACTyB,QAAQA;IACV;IAEA,IAAIjC,sBAAsBa,WAAW,OAAO;IAE5C,qBACE,KAACuC;QAAIC,eAAY;kBACf,cAAA,KAACzE;YACC0E,OAAOtD,kBAAkBsD,KAAK;YAC9BC,QAAQvD,kBAAkBuD,MAAM;YAChCJ,SAASA;YACThD,SAASA,YAAY,OAAOU,YAAaV,WAAWrB;;;AAI5D;AAEA,qBAAqB;AACrB,OAAO,SAAS0D,cACdvB,SAAiB,EACjBuC,cAAgC,EAChCjD,SAA2B;IAE3B,MAAM,CAACkD,SAASC,QAAQ,GAAGnD;IAC3B,MAAM,CAACE,cAAcC,aAAa,GAAG8C;IAErC,wBAAwB;IACxB,IAAI9C,eAAeD,iBAAiB,GAAG;QACrC,OAAOiD;IACT;IAEA,iHAAiH;IACjH,MAAMC,MAAM,AAAC1C,CAAAA,YAAYR,YAAW,IAAMC,CAAAA,eAAeD,YAAW;IACpE,OAAOgD,UAAU,AAACC,CAAAA,UAAUD,OAAM,IAAKE;AACzC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { EChartsOption } from 'echarts';
|
|
3
|
+
interface ScatterplotProps<T> {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
options: EChartsOption;
|
|
7
|
+
onClick?: (data: T) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function Scatterplot<T>(props: ScatterplotProps<T>): ReactElement;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=Scatterplot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scatterplot.d.ts","sourceRoot":"","sources":["../../src/Scatterplot.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAW,MAAM,OAAO,CAAC;AAa9C,OAAO,EAAE,aAAa,EAAuB,MAAM,SAAS,CAAC;AAe7D,UAAU,gBAAgB,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;CAC7B;AAOD,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,YAAY,CA2EvE"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import { useMemo } from 'react';
|
|
15
|
+
import { EChart, useChartsTheme } from '@perses-dev/components';
|
|
16
|
+
import { use } from 'echarts/core';
|
|
17
|
+
import { ScatterChart as EChartsScatterChart } from 'echarts/charts';
|
|
18
|
+
import { DatasetComponent, DataZoomComponent, LegendComponent, GridComponent, TitleComponent, TooltipComponent } from 'echarts/components';
|
|
19
|
+
import { CanvasRenderer } from 'echarts/renderers';
|
|
20
|
+
import { formatValue } from '@perses-dev/core';
|
|
21
|
+
use([
|
|
22
|
+
DatasetComponent,
|
|
23
|
+
DataZoomComponent,
|
|
24
|
+
LegendComponent,
|
|
25
|
+
EChartsScatterChart,
|
|
26
|
+
GridComponent,
|
|
27
|
+
TitleComponent,
|
|
28
|
+
TooltipComponent,
|
|
29
|
+
CanvasRenderer
|
|
30
|
+
]);
|
|
31
|
+
const DATE_FORMATTER = new Intl.DateTimeFormat(undefined, {
|
|
32
|
+
dateStyle: 'long',
|
|
33
|
+
timeStyle: 'medium'
|
|
34
|
+
}).format;
|
|
35
|
+
export function Scatterplot(props) {
|
|
36
|
+
const { width, height, options, onClick } = props;
|
|
37
|
+
const chartsTheme = useChartsTheme();
|
|
38
|
+
// Apache EChart Options Docs: https://echarts.apache.org/en/option.html
|
|
39
|
+
const eChartOptions = {
|
|
40
|
+
dataset: options.dataset,
|
|
41
|
+
series: options.series,
|
|
42
|
+
dataZoom: options.dataZoom,
|
|
43
|
+
grid: {
|
|
44
|
+
bottom: 40,
|
|
45
|
+
top: 50,
|
|
46
|
+
left: 50,
|
|
47
|
+
right: 100
|
|
48
|
+
},
|
|
49
|
+
xAxis: {
|
|
50
|
+
type: 'time',
|
|
51
|
+
name: 'Local Time'
|
|
52
|
+
},
|
|
53
|
+
yAxis: {
|
|
54
|
+
scale: true,
|
|
55
|
+
type: 'value',
|
|
56
|
+
name: 'Duration',
|
|
57
|
+
axisLabel: {
|
|
58
|
+
formatter: (durationMs)=>formatValue(durationMs, {
|
|
59
|
+
unit: 'milliseconds'
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
animation: false,
|
|
64
|
+
tooltip: {
|
|
65
|
+
padding: 5,
|
|
66
|
+
borderWidth: 1,
|
|
67
|
+
trigger: 'axis',
|
|
68
|
+
axisPointer: {
|
|
69
|
+
type: 'cross'
|
|
70
|
+
},
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
formatter: function(params) {
|
|
73
|
+
// TODO: import type from ECharts instead of using any
|
|
74
|
+
const data = params[0].data;
|
|
75
|
+
return [
|
|
76
|
+
`<b>Service name</b>: ${data.rootServiceName}<br/>`,
|
|
77
|
+
`<b>Span name</b>: ${data.rootTraceName}<br/>`,
|
|
78
|
+
`<b>Time</b>: ${DATE_FORMATTER(data.startTime)}<br/>`,
|
|
79
|
+
`<b>Duration</b>: ${formatValue(data.durationMs, {
|
|
80
|
+
unit: 'milliseconds'
|
|
81
|
+
})}<br/>`,
|
|
82
|
+
`<b>Span count</b>: ${data.spanCount} (${data.errorCount} errors)<br/>`
|
|
83
|
+
].join('');
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
legend: {
|
|
87
|
+
show: true,
|
|
88
|
+
type: 'scroll',
|
|
89
|
+
orient: 'horizontal',
|
|
90
|
+
bottom: 0
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const handleEvents = useMemo(()=>{
|
|
94
|
+
const handlers = {};
|
|
95
|
+
if (onClick) {
|
|
96
|
+
handlers.click = (params)=>onClick(params.data);
|
|
97
|
+
}
|
|
98
|
+
return handlers;
|
|
99
|
+
}, [
|
|
100
|
+
onClick
|
|
101
|
+
]);
|
|
102
|
+
return /*#__PURE__*/ _jsx(EChart, {
|
|
103
|
+
sx: {
|
|
104
|
+
width: width,
|
|
105
|
+
height: height
|
|
106
|
+
},
|
|
107
|
+
option: eChartOptions,
|
|
108
|
+
theme: chartsTheme.echartsTheme,
|
|
109
|
+
onEvents: handleEvents
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=Scatterplot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/Scatterplot.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { EChart, OnEventsType, useChartsTheme } from '@perses-dev/components';\nimport { use, EChartsCoreOption } from 'echarts/core';\nimport { ScatterChart as EChartsScatterChart } from 'echarts/charts';\nimport {\n DatasetComponent,\n DataZoomComponent,\n LegendComponent,\n GridComponent,\n TitleComponent,\n TooltipComponent,\n} from 'echarts/components';\nimport { CanvasRenderer } from 'echarts/renderers';\nimport { EChartsOption, ScatterSeriesOption } from 'echarts';\nimport { formatValue } from '@perses-dev/core';\nimport { EChartTraceValue } from './ScatterChartPanel';\n\nuse([\n DatasetComponent,\n DataZoomComponent,\n LegendComponent,\n EChartsScatterChart,\n GridComponent,\n TitleComponent,\n TooltipComponent,\n CanvasRenderer,\n]);\n\ninterface ScatterplotProps<T> {\n width: number;\n height: number;\n options: EChartsOption;\n onClick?: (data: T) => void;\n}\n\nconst DATE_FORMATTER = new Intl.DateTimeFormat(undefined, {\n dateStyle: 'long',\n timeStyle: 'medium',\n}).format;\n\nexport function Scatterplot<T>(props: ScatterplotProps<T>): ReactElement {\n const { width, height, options, onClick } = props;\n const chartsTheme = useChartsTheme();\n\n // Apache EChart Options Docs: https://echarts.apache.org/en/option.html\n const eChartOptions: EChartsCoreOption = {\n dataset: options.dataset,\n series: options.series,\n dataZoom: options.dataZoom,\n grid: {\n bottom: 40,\n top: 50,\n left: 50,\n right: 100,\n },\n xAxis: {\n type: 'time',\n name: 'Local Time',\n },\n yAxis: {\n scale: true,\n type: 'value',\n name: 'Duration',\n axisLabel: {\n formatter: (durationMs: number) => formatValue(durationMs, { unit: 'milliseconds' }),\n },\n },\n animation: false,\n tooltip: {\n padding: 5,\n borderWidth: 1,\n trigger: 'axis',\n axisPointer: {\n type: 'cross',\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n formatter: function (params: any) {\n // TODO: import type from ECharts instead of using any\n const data = params[0].data as EChartTraceValue;\n return [\n `<b>Service name</b>: ${data.rootServiceName}<br/>`,\n `<b>Span name</b>: ${data.rootTraceName}<br/>`,\n `<b>Time</b>: ${DATE_FORMATTER(data.startTime)}<br/>`,\n `<b>Duration</b>: ${formatValue(data.durationMs, { unit: 'milliseconds' })}<br/>`,\n `<b>Span count</b>: ${data.spanCount} (${data.errorCount} errors)<br/>`,\n ].join('');\n },\n },\n legend: {\n show: true,\n type: 'scroll',\n orient: 'horizontal',\n bottom: 0,\n },\n };\n\n const handleEvents: OnEventsType<ScatterSeriesOption['data'] | unknown> = useMemo(() => {\n const handlers: OnEventsType<ScatterSeriesOption['data'] | unknown> = {};\n if (onClick) {\n handlers.click = (params): void => onClick(params.data as T);\n }\n return handlers;\n }, [onClick]);\n\n return (\n <EChart\n sx={{\n width: width,\n height: height,\n }}\n option={eChartOptions}\n theme={chartsTheme.echartsTheme}\n onEvents={handleEvents}\n />\n );\n}\n"],"names":["useMemo","EChart","useChartsTheme","use","ScatterChart","EChartsScatterChart","DatasetComponent","DataZoomComponent","LegendComponent","GridComponent","TitleComponent","TooltipComponent","CanvasRenderer","formatValue","DATE_FORMATTER","Intl","DateTimeFormat","undefined","dateStyle","timeStyle","format","Scatterplot","props","width","height","options","onClick","chartsTheme","eChartOptions","dataset","series","dataZoom","grid","bottom","top","left","right","xAxis","type","name","yAxis","scale","axisLabel","formatter","durationMs","unit","animation","tooltip","padding","borderWidth","trigger","axisPointer","params","data","rootServiceName","rootTraceName","startTime","spanCount","errorCount","join","legend","show","orient","handleEvents","handlers","click","sx","option","theme","echartsTheme","onEvents"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,MAAM,EAAgBC,cAAc,QAAQ,yBAAyB;AAC9E,SAASC,GAAG,QAA2B,eAAe;AACtD,SAASC,gBAAgBC,mBAAmB,QAAQ,iBAAiB;AACrE,SACEC,gBAAgB,EAChBC,iBAAiB,EACjBC,eAAe,EACfC,aAAa,EACbC,cAAc,EACdC,gBAAgB,QACX,qBAAqB;AAC5B,SAASC,cAAc,QAAQ,oBAAoB;AAEnD,SAASC,WAAW,QAAQ,mBAAmB;AAG/CV,IAAI;IACFG;IACAC;IACAC;IACAH;IACAI;IACAC;IACAC;IACAC;CACD;AASD,MAAME,iBAAiB,IAAIC,KAAKC,cAAc,CAACC,WAAW;IACxDC,WAAW;IACXC,WAAW;AACb,GAAGC,MAAM;AAET,OAAO,SAASC,YAAeC,KAA0B;IACvD,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAE,GAAGJ;IAC5C,MAAMK,cAAczB;IAEpB,wEAAwE;IACxE,MAAM0B,gBAAmC;QACvCC,SAASJ,QAAQI,OAAO;QACxBC,QAAQL,QAAQK,MAAM;QACtBC,UAAUN,QAAQM,QAAQ;QAC1BC,MAAM;YACJC,QAAQ;YACRC,KAAK;YACLC,MAAM;YACNC,OAAO;QACT;QACAC,OAAO;YACLC,MAAM;YACNC,MAAM;QACR;QACAC,OAAO;YACLC,OAAO;YACPH,MAAM;YACNC,MAAM;YACNG,WAAW;gBACTC,WAAW,CAACC,aAAuB/B,YAAY+B,YAAY;wBAAEC,MAAM;oBAAe;YACpF;QACF;QACAC,WAAW;QACXC,SAAS;YACPC,SAAS;YACTC,aAAa;YACbC,SAAS;YACTC,aAAa;gBACXb,MAAM;YACR;YACA,8DAA8D;YAC9DK,WAAW,SAAUS,MAAW;gBAC9B,sDAAsD;gBACtD,MAAMC,OAAOD,MAAM,CAAC,EAAE,CAACC,IAAI;gBAC3B,OAAO;oBACL,CAAC,qBAAqB,EAAEA,KAAKC,eAAe,CAAC,KAAK,CAAC;oBACnD,CAAC,kBAAkB,EAAED,KAAKE,aAAa,CAAC,KAAK,CAAC;oBAC9C,CAAC,aAAa,EAAEzC,eAAeuC,KAAKG,SAAS,EAAE,KAAK,CAAC;oBACrD,CAAC,iBAAiB,EAAE3C,YAAYwC,KAAKT,UAAU,EAAE;wBAAEC,MAAM;oBAAe,GAAG,KAAK,CAAC;oBACjF,CAAC,mBAAmB,EAAEQ,KAAKI,SAAS,CAAC,EAAE,EAAEJ,KAAKK,UAAU,CAAC,aAAa,CAAC;iBACxE,CAACC,IAAI,CAAC;YACT;QACF;QACAC,QAAQ;YACNC,MAAM;YACNvB,MAAM;YACNwB,QAAQ;YACR7B,QAAQ;QACV;IACF;IAEA,MAAM8B,eAAoE/D,QAAQ;QAChF,MAAMgE,WAAgE,CAAC;QACvE,IAAItC,SAAS;YACXsC,SAASC,KAAK,GAAG,CAACb,SAAiB1B,QAAQ0B,OAAOC,IAAI;QACxD;QACA,OAAOW;IACT,GAAG;QAACtC;KAAQ;IAEZ,qBACE,KAACzB;QACCiE,IAAI;YACF3C,OAAOA;YACPC,QAAQA;QACV;QACA2C,QAAQvC;QACRwC,OAAOzC,YAAY0C,YAAY;QAC/BC,UAAUP;;AAGhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/bootstrap.tsx"],"names":[],"mappings":""}
|
package/lib/bootstrap.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2024 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
14
|
+
import React from 'react';
|
|
15
|
+
import ReactDOM from 'react-dom/client';
|
|
16
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
17
|
+
root.render(/*#__PURE__*/ _jsx(React.StrictMode, {}));
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/bootstrap.tsx"],"sourcesContent":["// Copyright 2024 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\n\nconst root = ReactDOM.createRoot(document.getElementById('root')!);\nroot.render(<React.StrictMode></React.StrictMode>);\n"],"names":["React","ReactDOM","root","createRoot","document","getElementById","render","StrictMode"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,OAAOA,WAAW,QAAQ;AAC1B,OAAOC,cAAc,mBAAmB;AAExC,MAAMC,OAAOD,SAASE,UAAU,CAACC,SAASC,cAAc,CAAC;AACzDH,KAAKI,MAAM,eAAC,KAACN,MAAMO,UAAU"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "ScatterChart", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function() {
|
|
20
|
+
return ScatterChart;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const _scatterchartmodel = require("./scatter-chart-model");
|
|
24
|
+
const _ScatterChartPanel = require("./ScatterChartPanel");
|
|
25
|
+
const ScatterChart = {
|
|
26
|
+
PanelComponent: _ScatterChartPanel.ScatterChartPanel,
|
|
27
|
+
// TODO: add a chart options editor plugin, for example:
|
|
28
|
+
// panelOptionsEditorComponents: [{ label: 'Settings', content: ScatterChartOptionsEditorSettings }],
|
|
29
|
+
supportedQueryTypes: [
|
|
30
|
+
'TraceQuery'
|
|
31
|
+
],
|
|
32
|
+
createInitialOptions: _scatterchartmodel.createInitialScatterChartOptions
|
|
33
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Copyright 2023 The Perses Authors
|
|
2
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
+
// you may not use this file except in compliance with the License.
|
|
4
|
+
// You may obtain a copy of the License at
|
|
5
|
+
//
|
|
6
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
//
|
|
8
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
11
|
+
// See the License for the specific language governing permissions and
|
|
12
|
+
// limitations under the License.
|
|
13
|
+
"use strict";
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
function _export(target, all) {
|
|
18
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: all[name]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
_export(exports, {
|
|
24
|
+
ScatterChartPanel: function() {
|
|
25
|
+
return ScatterChartPanel;
|
|
26
|
+
},
|
|
27
|
+
getSymbolSize: function() {
|
|
28
|
+
return getSymbolSize;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const _jsxruntime = require("react/jsx-runtime");
|
|
32
|
+
const _react = require("react");
|
|
33
|
+
const _components = require("@perses-dev/components");
|
|
34
|
+
const _Scatterplot = require("./Scatterplot");
|
|
35
|
+
/** default size range of the circles diameter */ const DEFAULT_SIZE_RANGE = [
|
|
36
|
+
6,
|
|
37
|
+
20
|
|
38
|
+
];
|
|
39
|
+
// Navigate to the Gantt Chart on the explore page by default
|
|
40
|
+
function defaultClickHandler(data) {
|
|
41
|
+
// clone the original query spec (including the datasource) and replace the query value with the trace id
|
|
42
|
+
const query = JSON.parse(JSON.stringify(data.query));
|
|
43
|
+
query.spec.plugin.spec.query = data.traceId;
|
|
44
|
+
const exploreParams = new URLSearchParams({
|
|
45
|
+
explorer: 'traces',
|
|
46
|
+
data: JSON.stringify({
|
|
47
|
+
queries: [
|
|
48
|
+
query
|
|
49
|
+
]
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
// do not use react-router here, as downstream products, which embed this panel, may not have a compatible version of it
|
|
53
|
+
window.location.href = `/explore?${exploreParams}`;
|
|
54
|
+
}
|
|
55
|
+
function ScatterChartPanel(props) {
|
|
56
|
+
const { spec, contentDimensions, queryResults: traceResults, onClick } = props;
|
|
57
|
+
const chartsTheme = (0, _components.useChartsTheme)();
|
|
58
|
+
const defaultColor = chartsTheme.thresholds.defaultColor || 'blue';
|
|
59
|
+
const sizeRange = spec.sizeRange || DEFAULT_SIZE_RANGE;
|
|
60
|
+
// Generate dataset
|
|
61
|
+
// Transform Tempo API response to fit 'dataset' structure from Apache ECharts
|
|
62
|
+
// https://echarts.apache.org/handbook/en/concepts/dataset
|
|
63
|
+
const { dataset, minSpanCount, maxSpanCount } = (0, _react.useMemo)(()=>{
|
|
64
|
+
const dataset = [];
|
|
65
|
+
let minSpanCount;
|
|
66
|
+
let maxSpanCount;
|
|
67
|
+
for (const result of traceResults){
|
|
68
|
+
if (result.data.searchResult === undefined) continue;
|
|
69
|
+
const dataSeries = result.data.searchResult.map((trace)=>{
|
|
70
|
+
let spanCount = 0;
|
|
71
|
+
let errorCount = 0;
|
|
72
|
+
for (const stats of Object.values(trace.serviceStats)){
|
|
73
|
+
spanCount += stats.spanCount;
|
|
74
|
+
errorCount += stats.errorCount ?? 0;
|
|
75
|
+
}
|
|
76
|
+
if (minSpanCount === undefined || spanCount < minSpanCount) {
|
|
77
|
+
minSpanCount = spanCount;
|
|
78
|
+
}
|
|
79
|
+
if (maxSpanCount === undefined || spanCount > maxSpanCount) {
|
|
80
|
+
maxSpanCount = spanCount;
|
|
81
|
+
}
|
|
82
|
+
const newTraceValue = {
|
|
83
|
+
...trace,
|
|
84
|
+
query: result.definition,
|
|
85
|
+
name: `${trace.rootServiceName}: ${trace.rootTraceName}`,
|
|
86
|
+
startTime: new Date(trace.startTimeUnixMs),
|
|
87
|
+
spanCount,
|
|
88
|
+
errorCount
|
|
89
|
+
};
|
|
90
|
+
return newTraceValue;
|
|
91
|
+
});
|
|
92
|
+
dataset.push({
|
|
93
|
+
source: dataSeries
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
dataset,
|
|
98
|
+
minSpanCount: minSpanCount ?? 0,
|
|
99
|
+
maxSpanCount: maxSpanCount ?? 0
|
|
100
|
+
};
|
|
101
|
+
}, [
|
|
102
|
+
traceResults
|
|
103
|
+
]);
|
|
104
|
+
// Formatting for the dataset
|
|
105
|
+
// 1. Map x,y coordinates
|
|
106
|
+
// 2. Datapoint size corresponds to the number of spans in a trace
|
|
107
|
+
// 3. Color datapoint red if the trace contains an error
|
|
108
|
+
const series = (0, _react.useMemo)(()=>{
|
|
109
|
+
const seriesTemplate2 = {
|
|
110
|
+
type: 'scatter',
|
|
111
|
+
encode: {
|
|
112
|
+
// Map to x-axis.
|
|
113
|
+
x: 'startTime',
|
|
114
|
+
// Map to y-axis.
|
|
115
|
+
y: 'durationMs'
|
|
116
|
+
},
|
|
117
|
+
symbolSize: function(data) {
|
|
118
|
+
// returns the diameter of the circles
|
|
119
|
+
return getSymbolSize(data.spanCount, [
|
|
120
|
+
minSpanCount,
|
|
121
|
+
maxSpanCount
|
|
122
|
+
], sizeRange);
|
|
123
|
+
},
|
|
124
|
+
itemStyle: {
|
|
125
|
+
color: function(params) {
|
|
126
|
+
const traceData = params.data;
|
|
127
|
+
// If the trace contains an error, color the datapoint in red
|
|
128
|
+
if (traceData.errorCount > 0) {
|
|
129
|
+
return 'red';
|
|
130
|
+
}
|
|
131
|
+
// Else return default color
|
|
132
|
+
return defaultColor;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
// Each data set needs to have a corresponding series formatting object
|
|
137
|
+
const series = [];
|
|
138
|
+
for(let i = 0; i < dataset.length; i++){
|
|
139
|
+
series.push({
|
|
140
|
+
...seriesTemplate2,
|
|
141
|
+
datasetIndex: i
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return series;
|
|
145
|
+
}, [
|
|
146
|
+
dataset,
|
|
147
|
+
defaultColor,
|
|
148
|
+
minSpanCount,
|
|
149
|
+
maxSpanCount,
|
|
150
|
+
sizeRange
|
|
151
|
+
]);
|
|
152
|
+
const tracesFound = traceResults.some((traceData)=>(traceData.data?.searchResult ?? []).length > 0);
|
|
153
|
+
if (!tracesFound) {
|
|
154
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)(_components.NoDataOverlay, {
|
|
155
|
+
resource: "traces"
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const options = {
|
|
159
|
+
dataset: dataset,
|
|
160
|
+
series: series
|
|
161
|
+
};
|
|
162
|
+
if (contentDimensions === undefined) return null;
|
|
163
|
+
return /*#__PURE__*/ (0, _jsxruntime.jsx)("div", {
|
|
164
|
+
"data-testid": "ScatterChartPanel_ScatterPlot",
|
|
165
|
+
children: /*#__PURE__*/ (0, _jsxruntime.jsx)(_Scatterplot.Scatterplot, {
|
|
166
|
+
width: contentDimensions.width,
|
|
167
|
+
height: contentDimensions.height,
|
|
168
|
+
options: options,
|
|
169
|
+
onClick: onClick === null ? undefined : onClick ?? defaultClickHandler
|
|
170
|
+
})
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function getSymbolSize(spanCount, spanCountRange, sizeRange) {
|
|
174
|
+
const [minSize, maxSize] = sizeRange;
|
|
175
|
+
const [minSpanCount, maxSpanCount] = spanCountRange;
|
|
176
|
+
// catch divison by zero
|
|
177
|
+
if (maxSpanCount - minSpanCount === 0) {
|
|
178
|
+
return maxSize;
|
|
179
|
+
}
|
|
180
|
+
// apply linear scale of spanCount from range [minSpanCount,maxSpanCount] to a value from range [minSize,maxSize]
|
|
181
|
+
const rel = (spanCount - minSpanCount) / (maxSpanCount - minSpanCount);
|
|
182
|
+
return minSize + (maxSize - minSize) * rel;
|
|
183
|
+
}
|