Re-implement frame and event download option.

This commit is contained in:
Orne Brocaar
2023-04-12 14:50:33 +01:00
parent ef0a97ab3d
commit f71d30ca83
4 changed files with 43 additions and 10 deletions

View File

@ -28,6 +28,7 @@
"codemirror": "^5.65.3", "codemirror": "^5.65.3",
"google-protobuf": "^3.21.2", "google-protobuf": "^3.21.2",
"grpc-web": "^1.4.2", "grpc-web": "^1.4.2",
"js-file-download": "^0.4.12",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"leaflet.awesome-markers": "^2.0.5", "leaflet.awesome-markers": "^2.0.5",
"react": "^17.0.2", "react": "^17.0.2",

View File

@ -1,8 +1,9 @@
import React, { Component } from "react"; import React, { Component } from "react";
import moment from "moment"; import moment from "moment";
import JSONTreeOriginal from "react-json-tree"; import JSONTreeOriginal from "react-json-tree";
import fileDownload from "js-file-download";
import { Tag, Drawer, Button, Table, Spin } from "antd"; import { Tag, Drawer, Button, Table, Spin, Space } from "antd";
import { ZoomInOutlined } from "@ant-design/icons"; import { ZoomInOutlined } from "@ant-design/icons";
import { LogItem } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb"; import { LogItem } from "@chirpstack/chirpstack-api-grpc-web/api/internal_pb";
@ -14,6 +15,7 @@ interface IProps {
interface IState { interface IState {
drawerOpen: boolean; drawerOpen: boolean;
body: any; body: any;
drawerTitle: any;
} }
class LogTable extends Component<IProps, IState> { class LogTable extends Component<IProps, IState> {
@ -23,6 +25,7 @@ class LogTable extends Component<IProps, IState> {
this.state = { this.state = {
drawerOpen: false, drawerOpen: false,
body: null, body: null,
drawerTitle: null,
}; };
} }
@ -32,15 +35,29 @@ class LogTable extends Component<IProps, IState> {
}); });
}; };
onDrawerOpen = (body: any) => { onDrawerOpen = (time: any, body: any) => {
let ts = new Date(0);
ts.setUTCSeconds(time.seconds);
let drawerTitle = moment(ts).format("YYYY-MM-DD HH:mm:ss");
return () => { return () => {
this.setState({ this.setState({
body: body, body: body,
drawerTitle: drawerTitle,
drawerOpen: true, drawerOpen: true,
}); });
}; };
}; };
downloadSingleFrame = () => {
fileDownload(JSON.stringify(JSON.parse(this.state.body), null, 4), "single-log.json", "application/json");
};
downloadFrames = () => {
let items = this.props.logs.map((l, i) => JSON.parse(l.getBody()));
fileDownload(JSON.stringify(items, null, 4), "log.json");
};
render() { render() {
let items = this.props.logs.map((l, i) => l.toObject()); let items = this.props.logs.map((l, i) => l.toObject());
let body = JSON.parse(this.state.body); let body = JSON.parse(this.state.body);
@ -67,13 +84,14 @@ class LogTable extends Component<IProps, IState> {
}; };
return ( return (
<div> <Space direction="vertical" size="large" style={{ width: "100%" }}>
<Drawer <Drawer
title="Details" title={`Details: ${this.state.drawerTitle}`}
placement="right" placement="right"
width={650} width={650}
onClose={this.onDrawerClose} onClose={this.onDrawerClose}
visible={this.state.drawerOpen} visible={this.state.drawerOpen}
extra={<Button onClick={this.downloadSingleFrame}>Download</Button>}
> >
<JSONTreeOriginal <JSONTreeOriginal
data={body} data={body}
@ -85,9 +103,10 @@ class LogTable extends Component<IProps, IState> {
/> />
</Drawer> </Drawer>
{items.length !== 0 && ( {items.length !== 0 && (
<div className="spinner"> <Space direction="horizontal" style={{ float: "right" }} size="large">
<Spin /> <Spin size="small" />
</div> <Button onClick={this.downloadFrames}>Download</Button>
</Space>
)} )}
<Table <Table
showHeader={false} showHeader={false}
@ -117,7 +136,7 @@ class LogTable extends Component<IProps, IState> {
type="primary" type="primary"
shape="round" shape="round"
size="small" size="small"
onClick={this.onDrawerOpen(obj.body)} onClick={this.onDrawerOpen(obj.time, obj.body)}
> >
{text} {text}
</Button> </Button>
@ -144,7 +163,7 @@ class LogTable extends Component<IProps, IState> {
}, },
]} ]}
/> />
</div> </Space>
); );
} }
} }

View File

@ -111,3 +111,11 @@ pre {
.CodeMirror { .CodeMirror {
height: 600px; height: 600px;
} }
.ant-drawer {
padding-top: 64px;
}
.ant-drawer-body {
padding-bottom: 88px; /* 64 + 24 */
}

View File

@ -1881,7 +1881,7 @@
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web": "@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web":
version "4.3.0" version "4.3.1"
dependencies: dependencies:
"@types/google-protobuf" "^3.15.6" "@types/google-protobuf" "^3.15.6"
google-protobuf "^3.21.2" google-protobuf "^3.21.2"
@ -7025,6 +7025,11 @@ jest@^27.4.3:
import-local "^3.0.2" import-local "^3.0.2"
jest-cli "^27.5.1" jest-cli "^27.5.1"
js-file-download@^0.4.12:
version "0.4.12"
resolved "https://registry.yarnpkg.com/js-file-download/-/js-file-download-0.4.12.tgz#10c70ef362559a5b23cdbdc3bd6f399c3d91d821"
integrity sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"