-
Notifications
You must be signed in to change notification settings - Fork 406
Add RedisTimeseries plugin #312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
f7da277
Add timeseries plugin
GnaneshKunal bbbf922
Build/timeseries (#336)
egor-zalenski 5904275
- Load plugin on RANGE, REVRANGE and MREVRANGE.
GnaneshKunal 8928b01
Merge pull request #337 from RedisInsight/main
egor-zalenski 065cf7c
Use 'Graphik' font
GnaneshKunal 603c03e
Merge remote-tracking branch 'origin/timeseries-plugin' into timeseri…
GnaneshKunal d1ed9b0
Prettify error messages
GnaneshKunal 79d40a6
Parse non-multi range queries differently
GnaneshKunal ca8bebc
`main.tsx` is the main source file
GnaneshKunal 3ddc2f5
Add range slider, config menu new styles, right y axis hover fix
GnaneshKunal de313db
Add new form design
GnaneshKunal de4984f
Add button group padding and font weight fix
GnaneshKunal 7d67428
Use date-fns, add types, move interfaces to interfaces file, remove d…
GnaneshKunal c4bb694
Merge branch 'main' into timeseries-plugin
egor-zalenski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules/ | ||
dist/ | ||
.parcel-cache/ |
34 changes: 34 additions & 0 deletions
34
redisinsight/ui/src/packages/redistimeseries-app/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# RedisTimeseries Plugin for RedisInsight v2 | ||
|
||
The example has been created using React, TypeScript, and [Elastic UI](https://elastic.github.io/eui/#/). | ||
[Parcel](https://parceljs.org/) is used to build the plugin. | ||
|
||
## Running locally | ||
|
||
The following commands will install dependencies and start the server to run the plugin locally: | ||
``` | ||
yarn | ||
yarn start | ||
``` | ||
These commands will install dependencies and start the server. | ||
|
||
_Note_: Base styles are included to `index.html` from the repository. | ||
|
||
This command will generate the `vendor` folder with styles and fonts of the core app. Add this folder | ||
inside the folder for your plugin and include appropriate styles to the `index.html` file. | ||
|
||
``` | ||
yarn build:statics - for Linux or MacOs | ||
yarn build:statics:win - for Windows | ||
``` | ||
|
||
## Build plugin | ||
|
||
The following commands will build plugins to be used in RedisInsight: | ||
``` | ||
yarn | ||
yarn build | ||
``` | ||
|
||
[Add](../../../../../docs/plugins/installation.md) the package.json file and the | ||
`dist` folder to the folder with your plugin, which should be located in the `plugins` folder. |
69 changes: 69 additions & 0 deletions
69
redisinsight/ui/src/packages/redistimeseries-app/package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"author": { | ||
"name": "Redis Ltd.", | ||
"email": "support@redis.com", | ||
"url": "https://redis.com/redis-enterprise/redis-insight" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/" | ||
}, | ||
"description": "RedisTimeseries module", | ||
"source": "./src/main.tsx", | ||
"styles": "./dist/styles.css", | ||
"main": "./dist/index.js", | ||
"name": "redistimeseries", | ||
"version": "0.0.1", | ||
"scripts": { | ||
"start": "cross-env NODE_ENV=development parcel serve src/index.html", | ||
"build": "rimraf dist && cross-env NODE_ENV=production concurrently \"yarn build:js && yarn minify:js\" \"yarn build:css\" \"yarn build:assets\"", | ||
"build:js": "parcel build src/main.tsx --dist-dir dist", | ||
"build:css": "parcel build src/styles/styles.less --dist-dir dist", | ||
"build:assets": "parcel build src/assets/**/* --dist-dir dist", | ||
"minify:js": "terser --compress --mangle -- dist/main.js > dist/index.js && rimraf dist/main.js" | ||
}, | ||
"targets": { | ||
"main": false, | ||
"module": { | ||
"includeNodeModules": true | ||
} | ||
}, | ||
"visualizations": [ | ||
{ | ||
"id": "redistimeseries-chart", | ||
"name": "Chart", | ||
"activationMethod": "renderChart", | ||
"matchCommands": [ | ||
"TS.MRANGE", | ||
"TS.MREVRANGE", | ||
"TS.RANGE", | ||
"TS.REVRANGE" | ||
], | ||
"description": "Redistimeseries chart view", | ||
"default": true | ||
} | ||
], | ||
"devDependencies": { | ||
"@parcel/compressor-brotli": "^2.0.0", | ||
"@parcel/compressor-gzip": "^2.0.0", | ||
"@parcel/transformer-less": "^2.0.1", | ||
"@parcel/transformer-sass": "2.3.2", | ||
"@types/file-saver": "^2.0.5", | ||
"@types/plotly.js-dist-min": "^2.3.0", | ||
"concurrently": "^6.3.0", | ||
"cross-env": "^7.0.3", | ||
"parcel": "^2.0.0", | ||
"rimraf": "^3.0.2", | ||
"terser": "^5.9.0" | ||
}, | ||
"dependencies": { | ||
"@elastic/eui": "34.6.0", | ||
"@emotion/react": "^11.7.1", | ||
"classnames": "^2.3.1", | ||
"date-fns": "^2.28.0", | ||
"file-saver": "^2.0.5", | ||
"fscreen": "^1.2.0", | ||
"plotly.js-dist-min": "^2.9.0", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2" | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
redisinsight/ui/src/packages/redistimeseries-app/src/App.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from 'react' | ||
import ChartResultView from './components/Chart/ChartResultView' | ||
|
||
interface Props { | ||
command: string | ||
result?: { response: any, status: string }[] | ||
} | ||
|
||
enum TS_CMD_RANGE_PREFIX { | ||
RANGE = 'TS.RANGE', | ||
REVRANGE = 'TS.REVRANGE', | ||
} | ||
|
||
const App = (props: Props) => { | ||
const { result: [{ response = '', status = '' } = {}] = [] } = props | ||
|
||
if (status === 'fail') { | ||
return <div className="responseFail">{response}</div> | ||
} | ||
|
||
if (status === 'success' && typeof(response) === 'string') { | ||
return <div className="responseFail">{response}</div> | ||
} | ||
|
||
function responseParser(command: string, data: any) { | ||
|
||
let [cmd, key, ..._] = command.split(' ') | ||
|
||
if ([TS_CMD_RANGE_PREFIX.RANGE.toString(), TS_CMD_RANGE_PREFIX.REVRANGE.toString()].includes(cmd)) { | ||
return [{ | ||
key, | ||
datapoints: data, | ||
}] | ||
} | ||
|
||
return data.map(e => ({ | ||
key: e[0], | ||
labels: e[1], | ||
datapoints: e[2], | ||
})) | ||
} | ||
|
||
return ( | ||
<ChartResultView | ||
data={responseParser(props.command, props.result[0].response) as any} | ||
/> | ||
) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same. |
||
|
||
export default App |
149 changes: 149 additions & 0 deletions
149
redisinsight/ui/src/packages/redistimeseries-app/src/components/Chart/Chart.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React, { useRef, useEffect } from 'react' | ||
import Plotly from 'plotly.js-dist-min' | ||
import { Legend, LayoutAxis, PlotData, PlotMouseEvent, Layout, PlotRelayoutEvent } from 'plotly.js' | ||
import { format } from 'date-fns' | ||
import { hexToRGBA, IGoodColor, GoodColorPicker, COLORS, COLORS_DARK } from './utils' | ||
|
||
import { | ||
Datapoint, | ||
GraphMode, | ||
ChartProps, | ||
PlotlyEvents, | ||
} from './interfaces' | ||
|
||
const GRAPH_MODE_MAP: { [mode: string]: 'lines' | 'markers' } = { | ||
[GraphMode.line]: 'lines', | ||
[GraphMode.points]: 'markers', | ||
} | ||
|
||
const isDarkTheme = document.body.classList.contains('theme_DARK') | ||
|
||
const colorPicker = (COLORS: IGoodColor[]) => { | ||
const color = new GoodColorPicker(COLORS) | ||
return (label: string) => color.getColor(label).color | ||
} | ||
|
||
const labelColors = colorPicker(isDarkTheme ? COLORS_DARK : COLORS) | ||
|
||
export default function Chart(props: ChartProps) { | ||
const chartContainer = useRef<any>() | ||
|
||
const colorPicker = labelColors | ||
|
||
useEffect(() => { | ||
Plotly.newPlot( | ||
chartContainer.current, | ||
getData(props), | ||
getLayout(props), | ||
{ displayModeBar: false, autosizable: true, responsive: true, setBackground: () => 'transparent', }, | ||
) | ||
chartContainer.current.on(PlotlyEvents.PLOTLY_HOVER, function (eventdata: PlotMouseEvent) { | ||
const points = eventdata.points[0] | ||
const pointNum = points.pointNumber | ||
Plotly.Fx.hover( | ||
chartContainer.current, | ||
props.data.map((_, i) => ({ | ||
curveNumber: i, | ||
pointNumber: pointNum | ||
})), | ||
Object.keys((chartContainer.current)._fullLayout._plots)) | ||
}) | ||
chartContainer.current.on(PlotlyEvents.PLOTLY_RELAYOUT, function (eventdata: PlotRelayoutEvent) { | ||
if (eventdata.autosize === undefined && eventdata['xaxis.autorange'] === undefined) { | ||
props.onRelayout() | ||
} | ||
}) | ||
|
||
chartContainer.current.on(PlotlyEvents.PLOTLY_DBLCLICK, () => props.onDoubleClick()) | ||
}, [props.chartConfig]) | ||
|
||
function getData(props: ChartProps): Partial<PlotData>[] { | ||
return props.data.map((timeSeries, i) => { | ||
|
||
const currentData = chartContainer.current.data | ||
const dataUnchanged = currentData && props.data === props.data | ||
/* | ||
* Time format for inclusion of milliseconds: | ||
* https://github.com/moment/moment/issues/4864#issuecomment-440142542 | ||
*/ | ||
const x = dataUnchanged ? currentData[i].x | ||
: selectCol(timeSeries.datapoints, 0).map((time: number) => format(time, 'yyyy-MM-dd HH:mm:ss.SSS')) | ||
const y = dataUnchanged ? currentData[i].y : selectCol(timeSeries.datapoints, 1) | ||
|
||
return { | ||
x, | ||
y, | ||
yaxis: props.chartConfig.yAxis2 && props.chartConfig.keyToY2Axis[timeSeries.key] ? 'y2' : 'y', | ||
name: timeSeries.key, | ||
type: 'scatter', | ||
marker: { color: colorPicker(timeSeries.key) }, | ||
fill: props.chartConfig.fill ? 'tozeroy' : undefined, | ||
fillcolor: hexToRGBA(colorPicker(timeSeries.key), 0.3), | ||
mode: GRAPH_MODE_MAP[props.chartConfig.mode], | ||
line: { shape: props.chartConfig.staircase ? 'hv' : 'spline' }, | ||
} | ||
}) | ||
} | ||
|
||
function getLayout(props: ChartProps): Partial<Layout> { | ||
const axisConfig: { [key: string]: Partial<LayoutAxis> } = { | ||
xaxis: { | ||
title: props.chartConfig.xlabel, | ||
rangeslider: { | ||
visible: true, | ||
thickness: 0.03, | ||
bgcolor: isDarkTheme ? '#3D3D3D' : '#CDD7EA', | ||
bordercolor: 'red', | ||
}, | ||
color: isDarkTheme ? '#898A90' : '#527298' | ||
}, | ||
yaxis: { | ||
title: props.chartConfig.yAxisConfig.label, | ||
type: props.chartConfig.yAxisConfig.scale, | ||
fixedrange: true, | ||
color: isDarkTheme ? '#898A90' : '#527298', | ||
gridcolor: isDarkTheme ? '#898A90' : '#527298', | ||
}, | ||
yaxis2: { | ||
visible: props.chartConfig.yAxis2, | ||
title: props.chartConfig.yAxis2Config.label, | ||
type: props.chartConfig.yAxis2Config.scale, | ||
overlaying: 'y', | ||
side: 'right', | ||
fixedrange: true, | ||
color: isDarkTheme ? '#8191CF' : '#6E6E6E', | ||
gridcolor: isDarkTheme ? '#8191CF' : '#6E6E6E', | ||
} as LayoutAxis, | ||
} | ||
|
||
const legend: Partial<Legend> = { | ||
xanchor: 'center', | ||
yanchor: 'top', | ||
x: 0.5, | ||
y: -0.3, | ||
orientation: 'h', | ||
} | ||
return { | ||
...axisConfig, | ||
legend, | ||
showlegend: true, | ||
title: props.chartConfig.title, | ||
uirevision: 1, | ||
autosize: true, | ||
font: { color: isDarkTheme ? 'darkgrey' : 'black' }, | ||
paper_bgcolor: 'rgba(0,0,0,0)', | ||
plot_bgcolor: 'rgba(0,0,0,0)', | ||
margin: { | ||
pad: 6 | ||
} | ||
} | ||
} | ||
|
||
function selectCol(twoDArray: Datapoint[], colIndex: number) { | ||
return twoDArray.map(arr => arr[colIndex]) | ||
} | ||
|
||
return ( | ||
<div ref={chartContainer}></div> | ||
) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, remove one empty line