Skip to content

Commit 12c3c3b

Browse files
committed
feat: add statistics chart for Datav Log panel #292
1 parent 72af52b commit 12c3c3b

File tree

11 files changed

+1229
-73
lines changed

11 files changed

+1229
-73
lines changed

ui/src/pages/Test.tsx

Lines changed: 870 additions & 2 deletions
Large diffs are not rendered by default.

ui/src/theme/colors.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ const customColors = {
5252
scrollBg: {
5353
light: 'rgba(36,41,46,0.07)',
5454
dark: 'rgba(204,204,220,0.16)'
55+
},
56+
error: {
57+
light : 'rgb(255,93,91)',
58+
dark: 'rgb(255,93,91)'
5559
}
5660
}
5761

ui/src/theme/custom-classes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ export function customClasses(props) {
133133
whiteSpace: 'nowrap'
134134
},
135135
'.error-text': {
136-
color: 'rgb(255,93,91)'
136+
color: customColors.error.light
137137
}
138138
}
139139
}

ui/src/utils/format.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313

1414
import { uniq } from "lodash";
15+
import moment from "moment";
1516
import { isEmpty } from "./validate";
1617

1718
// parse all the {{xxx}} to [xxx]
@@ -98,4 +99,42 @@ export const jsonToEqualPairs1 = v => {
9899
s += "}"
99100

100101
return s
102+
}
103+
104+
105+
// start, end : ms
106+
// step: second
107+
export const getTimeFormatForChart = (start, end, step?) => {
108+
const mstart = moment(start)
109+
const mend = moment(end)
110+
const now = moment()
111+
let format;
112+
113+
const isSameYear = now.isSame(mend, "year") && now.isSame(mstart, "year")
114+
const isSameMonth = now.isSame(mend, "month") && now.isSame(mstart, "month")
115+
const isSameDay = now.isSame(mend, "day") && now.isSame(mstart, "day")
116+
117+
if (isSameYear) {
118+
format = ""
119+
} else {
120+
format = "YYYY-"
121+
}
122+
123+
if (isSameYear && isSameMonth) {
124+
format += ""
125+
} else {
126+
format += "M-"
127+
}
128+
129+
if (isSameYear && isSameMonth && isSameDay) {
130+
format += "HH:mm"
131+
} else {
132+
format += "DD HH:mm"
133+
}
134+
135+
if (step && step < 60) {
136+
format += ":ss"
137+
}
138+
139+
return format
101140
}

ui/src/views/dashboard/plugins/built-in/panel/bar/BarChart.tsx

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -403,42 +403,8 @@ export default BarChart
403403

404404

405405

406-
// start, end : ms
407-
// step: second
408-
const getTimeFormat = (start, end, step) => {
409-
const mstart = moment(start)
410-
const mend = moment(end)
411-
const now = moment()
412-
let format;
413-
414-
const isSameYear = now.isSame(mend, "year") && now.isSame(mstart, "year")
415-
const isSameMonth = now.isSame(mend, "month") && now.isSame(mstart, "month")
416-
const isSameDay = now.isSame(mend, "day") && now.isSame(mstart, "day")
417-
418-
if (isSameYear) {
419-
format = ""
420-
} else {
421-
format = "YYYY-"
422-
}
423-
424-
if (isSameYear && isSameMonth) {
425-
format += ""
426-
} else {
427-
format += "M-"
428-
}
429-
430-
if (isSameYear && isSameMonth && isSameDay) {
431-
format += "HH:mm"
432-
} else {
433-
format += "DD HH:mm"
434-
}
435406

436-
if (step < 60) {
437-
format += ":ss"
438-
}
439407

440-
return format
441-
}
442408

443409
const getTimeInterval = (width, format, fontSize, ticks) => {
444410
const formatWidth = (measureText(format, fontSize).width + 10)
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2023 Datav.io Team
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+
14+
import { useColorMode } from "@chakra-ui/react"
15+
import ChartComponent from "src/components/charts/Chart"
16+
import React, { memo, useEffect, useMemo, useState } from "react"
17+
import { Panel } from "types/dashboard"
18+
19+
import { QueryPluginData } from "types/plugin"
20+
import { dateTimeFormat } from "utils/datetime/formatter"
21+
import { getTimeFormatForChart } from "utils/format"
22+
import customColors from "theme/colors"
23+
24+
25+
interface Props {
26+
data: QueryPluginData
27+
panel: Panel
28+
width: number
29+
onSelectLabel?: any
30+
}
31+
32+
const DatavLogChart = memo((props: Props) => {
33+
const { panel, width, onSelectLabel } = props
34+
const [chart, setChart] = useState<echarts.ECharts>(null)
35+
const { colorMode } = useColorMode()
36+
37+
useEffect(() => {
38+
if (chart) {
39+
chart.on('click', function (event) {
40+
if (event.seriesName != "total") {
41+
onSelectLabel(event.seriesName)
42+
}
43+
})
44+
}
45+
return () => {
46+
chart?.off('click')
47+
}
48+
}, [chart])
49+
50+
51+
const [timeline, names, data] = useMemo(() =>{
52+
const names = props.data.columns.slice(1)
53+
54+
55+
const data = []
56+
props.data.columns.forEach((name, i) => {
57+
data.push(props.data.data.map(d => d[i]))
58+
})
59+
60+
const timeBucks = data[0]
61+
const start = Number(timeBucks[0])
62+
const step = Number(timeBucks[1]) - start
63+
const end = Number(timeBucks[timeBucks.length - 1])
64+
const timeFormat = getTimeFormatForChart(start * 1000, end * 1000, step - start )
65+
const timeline = timeBucks.map(t => dateTimeFormat(t * 1000, { format: timeFormat }))
66+
67+
return [timeline, names, data.slice(1)]
68+
},[props.data])
69+
70+
71+
72+
const chartOptions = {
73+
animation: false,
74+
animationDuration: 500,
75+
tooltip: {
76+
show: true,
77+
trigger: 'axis',
78+
appendToBody: true,
79+
axisPointer: {
80+
// Use axis to trigger tooltip
81+
type: 'none', // 'shadow' as default; can also be 'line' or 'shadow',
82+
},
83+
},
84+
grid: {
85+
left: "1%",
86+
right: "3%",
87+
top: "6%",
88+
bottom: '0%',
89+
padding: 0,
90+
containLabel: true
91+
},
92+
xAxis: {
93+
type: 'category',
94+
data: timeline,
95+
show: true,
96+
axisTick: {
97+
alignWithLabel: false,
98+
},
99+
axisLabel: {
100+
show: true,
101+
textStyle: {
102+
// align: 'center',
103+
// baseline: 'end',
104+
},
105+
fontSize: 10,
106+
interval: 5
107+
},
108+
109+
},
110+
yAxis: {
111+
type: 'value',
112+
splitLine: {
113+
show: false,
114+
},
115+
show: 'true',
116+
splitNumber: 2,
117+
axisLabel: {
118+
fontSize: 11
119+
}
120+
},
121+
series: names.map((name, i) => {
122+
return ({
123+
name: name,
124+
data: data[i],
125+
type: 'bar',
126+
stack: "total",
127+
label: {
128+
show: false,
129+
formatter: (v) => {
130+
v.data + " lines"
131+
},
132+
fontSize: 11,
133+
},
134+
color: name == "others" ? 'rgb(80,250,123)' : customColors.error.light
135+
// barWidth: '90%'
136+
})})
137+
};
138+
139+
return (<>
140+
<ChartComponent key={colorMode} options={chartOptions} clearWhenSetOption theme={colorMode} onChartCreated={c => setChart(c)} width={width} />
141+
</>)
142+
})
143+
144+
export default DatavLogChart
145+

ui/src/views/dashboard/plugins/built-in/panel/datavLog/Panel.tsx

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,53 @@
1010
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
13-
import { Box, Text, useMediaQuery } from "@chakra-ui/react"
14-
import { MarkdownRender } from "src/components/markdown/MarkdownRender"
13+
import { Box, Center, Text, useMediaQuery, VStack } from "@chakra-ui/react"
1514
import { PanelProps } from "types/dashboard"
16-
import { replaceWithVariables } from "utils/variable"
17-
import React, { useMemo } from "react";
18-
import { PanelType, DatavLogPanel } from "./types";
15+
import React, { memo, useMemo } from "react";
16+
import { DatavLogPanel } from "./types";
1917
import ColumnResizableTable from "components/table/ColumnResizableTable";
2018
import { ColumnDef } from "@tanstack/react-table";
21-
import { IsSmallScreen, MobileVerticalBreakpoint } from "src/data/constants";
19+
import { IsSmallScreen } from "src/data/constants";
2220
import moment from "moment";
21+
import { isEmpty } from "utils/validate";
22+
import NoData from "src/views/dashboard/components/PanelNoData";
23+
import DatavLogChart from "./Chart";
2324

2425
interface Props extends PanelProps {
2526
panel: DatavLogPanel
2627
}
2728

29+
const PanelWrapper = memo((props: Props) => {
30+
const data = props.data.flat()
31+
32+
if (isEmpty(data)) {
33+
return <Center height="100%"><NoData /></Center>
34+
}
35+
36+
return (<>
37+
{
38+
!isLogData(data[0])
39+
?
40+
<Center height="100%">
41+
<VStack>
42+
<Text fontWeight={500} fontSize="1.1rem">Data format not support!</Text>
43+
<Text className='color-text'>Try to change to Datav datasource to use this panel</Text>
44+
</VStack>
45+
</Center>
46+
:
47+
<Panel {...props} data={data[0]} />
48+
}
49+
</>
50+
)
51+
})
52+
53+
54+
55+
export default PanelWrapper
2856

2957

3058
const Panel = (props: Props) => {
31-
const { panel } = props
32-
const data = props.data.flat()
59+
const { panel, data } = props
3360

3461
const [isMobileScreen] = useMediaQuery(IsSmallScreen)
3562

@@ -72,7 +99,7 @@ const Panel = (props: Props) => {
7299

73100
const logs = useMemo(() => {
74101
const logs = []
75-
for (const log of data) {
102+
for (const log of data.logs) {
76103
logs.push({
77104
...log,
78105
timestamp: isMobileScreen ? moment(log.timestamp).format("MM-DD hh:mm:ss") : new Date(log.timestamp).toLocaleString()
@@ -82,8 +109,18 @@ const Panel = (props: Props) => {
82109
}, [isMobileScreen, data])
83110

84111
return (<Box px="2" height="100%" id="datav-log-panel" >
112+
<Box height="100px" mb="2">
113+
<DatavLogChart panel={panel} width={props.width} data={data.chart} />
114+
</Box>
85115
<ColumnResizableTable columns={defaultColumns} data={logs} wrapLine={wrapLine} fontSize={13} allowOverflow={false} height={props.height + 'px'} />
86116
</Box>)
87117
}
88118

89-
export default Panel
119+
120+
const isLogData = (data: any) => {
121+
if (!data.logs) {
122+
return false
123+
}
124+
125+
return true
126+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2023 Datav.io Team
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+
14+
import React from "react"
15+
16+
const Search = () => {
17+
return (<></>)
18+
}
19+
20+
export default Search

0 commit comments

Comments
 (0)