mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
dashboard: yarn commands, small fixes
This commit is contained in:
parent
dbf5d53d58
commit
45c916790f
12 changed files with 802 additions and 810 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -42,5 +42,6 @@ profile.cov
|
|||
/dashboard/assets/node_modules
|
||||
/dashboard/assets/stats.json
|
||||
/dashboard/assets/bundle.js
|
||||
/dashboard/assets/yarn-error.log
|
||||
/dashboard/assets/package-lock.json
|
||||
|
||||
**/yarn-error.log
|
||||
|
|
|
|||
|
|
@ -12,23 +12,20 @@ The client's UI uses [React][React] with JSX syntax, which is validated by the [
|
|||
As the dashboard depends on certain NPM packages (which are not included in the `go-ethereum` repo), these need to be installed first:
|
||||
|
||||
```
|
||||
$ (cd dashboard/assets && yarn install)
|
||||
$ (cd dashboard/assets && ./node_modules/.bin/flow-typed install)
|
||||
$ (cd dashboard/assets && yarn install && yarn flow)
|
||||
```
|
||||
|
||||
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `webpack-dev-server` to run a `geth` independent server which automatically rebundles the UI, and uses external assets to make connection with `geth`, which this way does not rely on compiled resources:
|
||||
Normally the dashboard assets are bundled into Geth via `go-bindata` to avoid external dependencies. Rebuilding Geth after each UI modification however is not feasible from a developer perspective. Instead, we can run `yarn dev` to watch for file system changes and refresh the browser automatically.
|
||||
|
||||
```
|
||||
$ geth --dashboard --vmodule=dashboard=5
|
||||
$ (cd dashboard/assets && ./node_modules/.bin/webpack-dev-server)
|
||||
$ (cd dashboard/assets && yarn dev)
|
||||
```
|
||||
|
||||
The configuration of `webpack-dev-server` is in `webpack.config.js`.
|
||||
|
||||
To bundle up the final UI into Geth, run `go generate`:
|
||||
|
||||
```
|
||||
$ go generate ./dashboard
|
||||
$ (cd dashboard && go generate)
|
||||
```
|
||||
|
||||
### Static type checking
|
||||
|
|
@ -43,7 +40,7 @@ For more IDE support install the `linter-eslint` package too, which finds the `.
|
|||
|
||||
[Webpack][Webpack] offers handy tools for visualizing the bundle's dependency tree and space usage.
|
||||
|
||||
* Generate the bundle's profile running `webpack --profile --json > stats.json`
|
||||
* Generate the bundle's profile running `yarn stats`
|
||||
* For the _dependency tree_ go to [Webpack Analyze][WA], and import `stats.json`
|
||||
* For the _space usage_ go to [Webpack Visualizer][WV], and import `stats.json`
|
||||
|
||||
|
|
|
|||
1421
dashboard/assets.go
1421
dashboard/assets.go
File diff suppressed because one or more lines are too long
|
|
@ -25,11 +25,6 @@ import Body from './Body';
|
|||
import {MENU} from '../common';
|
||||
import type {Content} from '../types/content';
|
||||
|
||||
// gethHost is the host of geth.
|
||||
const gethHost = 'localhost';
|
||||
// gethPort is the port of geth.
|
||||
const gethPort = 8080;
|
||||
|
||||
// deepUpdate updates an object corresponding to the given update data, which has
|
||||
// the shape of the same structure as the original object. updater also has the same
|
||||
// structure, except that it contains functions where the original data needs to be
|
||||
|
|
@ -82,15 +77,15 @@ const appender = <T>(limit: number, mapper = replacer) => (update: Array<T>, pre
|
|||
|
||||
// defaultContent is the initial value of the state content.
|
||||
const defaultContent: Content = {
|
||||
general: {
|
||||
version: null,
|
||||
commit: null,
|
||||
},
|
||||
home: {},
|
||||
chain: {},
|
||||
txpool: {},
|
||||
network: {},
|
||||
system: {},
|
||||
logs: {
|
||||
log: [],
|
||||
},
|
||||
footer: {
|
||||
system: {
|
||||
activeMemory: [],
|
||||
virtualMemory: [],
|
||||
networkIngress: [],
|
||||
|
|
@ -99,9 +94,9 @@ const defaultContent: Content = {
|
|||
systemCPU: [],
|
||||
diskRead: [],
|
||||
diskWrite: [],
|
||||
|
||||
version: null,
|
||||
commit: null,
|
||||
},
|
||||
logs: {
|
||||
log: [],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -109,15 +104,15 @@ const defaultContent: Content = {
|
|||
//
|
||||
// TODO (kurkomisi): Define a tricky type which embraces the content and the updaters.
|
||||
const updaters = {
|
||||
general: {
|
||||
version: replacer,
|
||||
commit: replacer,
|
||||
},
|
||||
home: null,
|
||||
chain: null,
|
||||
txpool: null,
|
||||
network: null,
|
||||
system: null,
|
||||
logs: {
|
||||
log: appender(200),
|
||||
},
|
||||
footer: {
|
||||
system: {
|
||||
activeMemory: appender(200),
|
||||
virtualMemory: appender(200),
|
||||
networkIngress: appender(200),
|
||||
|
|
@ -126,9 +121,9 @@ const updaters = {
|
|||
systemCPU: appender(200),
|
||||
diskRead: appender(200),
|
||||
diskWrite: appender(200),
|
||||
|
||||
version: replacer,
|
||||
commit: replacer,
|
||||
},
|
||||
logs: {
|
||||
log: appender(200),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -141,7 +136,7 @@ const styles = {
|
|||
height: '100%',
|
||||
zIndex: 1,
|
||||
overflow: 'hidden',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// themeStyles returns the styles generated from the theme for the component.
|
||||
|
|
@ -183,7 +178,8 @@ class Dashboard extends Component<Props, State> {
|
|||
// reconnect establishes a websocket connection with the server, listens for incoming messages
|
||||
// and tries to reconnect on connection loss.
|
||||
reconnect = () => {
|
||||
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${gethHost}:${gethPort}/api`);
|
||||
// PROD is defined by webpack.
|
||||
const server = new WebSocket(`${((window.location.protocol === 'https:') ? 'wss://' : 'ws://')}${PROD ? window.location.host : 'localhost:8080'}/api`);
|
||||
server.onopen = () => {
|
||||
this.setState({content: defaultContent, shouldUpdate: {}});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import {ResponsiveContainer, AreaChart, Area, Tooltip} from 'recharts';
|
|||
import ChartRow from './ChartRow';
|
||||
import CustomTooltip, {bytePlotter, bytePerSecPlotter, percentPlotter, multiplier} from './CustomTooltip';
|
||||
import {styles as commonStyles} from '../common';
|
||||
import type {Footer as FooterType} from '../types/content';
|
||||
import type {General, System} from '../types/content';
|
||||
|
||||
const FOOTER_SYNC_ID = 'footerSyncId';
|
||||
|
||||
|
|
@ -68,14 +68,15 @@ const themeStyles: Object = (theme: Object) => ({
|
|||
export type Props = {
|
||||
classes: Object, // injected by withStyles()
|
||||
theme: Object,
|
||||
content: FooterType,
|
||||
general: General,
|
||||
system: System,
|
||||
shouldUpdate: Object,
|
||||
};
|
||||
|
||||
// Footer renders the footer of the dashboard.
|
||||
class Footer extends Component<Props> {
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return typeof nextProps.shouldUpdate.footer !== 'undefined';
|
||||
return typeof nextProps.shouldUpdate.general !== 'undefined' || typeof nextProps.shouldUpdate.system !== 'undefined';
|
||||
}
|
||||
|
||||
// halfHeightChart renders an area chart with half of the height of its parent.
|
||||
|
|
@ -125,7 +126,7 @@ class Footer extends Component<Props> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const {content} = this.props;
|
||||
const {general, system} = this.props;
|
||||
|
||||
return (
|
||||
<Grid container className={this.props.classes.footer} direction='row' alignItems='center' style={styles.footer}>
|
||||
|
|
@ -134,38 +135,38 @@ class Footer extends Component<Props> {
|
|||
{this.doubleChart(
|
||||
FOOTER_SYNC_ID,
|
||||
CPU,
|
||||
{data: content.processCPU, tooltip: percentPlotter('Process load')},
|
||||
{data: content.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))},
|
||||
{data: system.processCPU, tooltip: percentPlotter('Process load')},
|
||||
{data: system.systemCPU, tooltip: percentPlotter('System load', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
FOOTER_SYNC_ID,
|
||||
MEMORY,
|
||||
{data: content.activeMemory, tooltip: bytePlotter('Active memory')},
|
||||
{data: content.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))},
|
||||
{data: system.activeMemory, tooltip: bytePlotter('Active memory')},
|
||||
{data: system.virtualMemory, tooltip: bytePlotter('Virtual memory', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
FOOTER_SYNC_ID,
|
||||
DISK,
|
||||
{data: content.diskRead, tooltip: bytePerSecPlotter('Disk read')},
|
||||
{data: content.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))},
|
||||
{data: system.diskRead, tooltip: bytePerSecPlotter('Disk read')},
|
||||
{data: system.diskWrite, tooltip: bytePerSecPlotter('Disk write', multiplier(-1))},
|
||||
)}
|
||||
{this.doubleChart(
|
||||
FOOTER_SYNC_ID,
|
||||
TRAFFIC,
|
||||
{data: content.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||
{data: content.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||
{data: system.networkIngress, tooltip: bytePerSecPlotter('Download')},
|
||||
{data: system.networkEgress, tooltip: bytePerSecPlotter('Upload', multiplier(-1))},
|
||||
)}
|
||||
</ChartRow>
|
||||
</Grid>
|
||||
<Grid item >
|
||||
<Typography type='caption' color='inherit'>
|
||||
<span style={commonStyles.light}>Geth</span> {content.version}
|
||||
<span style={commonStyles.light}>Geth</span> {general.version}
|
||||
</Typography>
|
||||
{content.commit && (
|
||||
{general.commit && (
|
||||
<Typography type='caption' color='inherit'>
|
||||
<span style={commonStyles.light}>{'Commit '}</span>
|
||||
<a href={`https://github.com/ethereum/go-ethereum/commit/${content.commit}`} target='_blank' style={{color: 'inherit', textDecoration: 'none'}} >
|
||||
{content.commit.substring(0, 8)}
|
||||
<a href={`https://github.com/ethereum/go-ethereum/commit/${general.commit}`} target='_blank' style={{color: 'inherit', textDecoration: 'none'}} >
|
||||
{general.commit.substring(0, 8)}
|
||||
</a>
|
||||
</Typography>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ class Main extends Component<Props> {
|
|||
<div style={styles.wrapper}>
|
||||
<div className={classes.content} style={styles.content}>{children}</div>
|
||||
<Footer
|
||||
content={content.footer}
|
||||
general={content.general}
|
||||
system={content.system}
|
||||
shouldUpdate={shouldUpdate}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -37,5 +37,11 @@
|
|||
"url-loader": "^0.6.2",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-dev-server": "^2.11.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production webpack",
|
||||
"stats": "webpack --profile --json > stats.json",
|
||||
"dev": "webpack-dev-server --port 8081",
|
||||
"flow": "flow-typed install"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export type Content = {
|
||||
general: General,
|
||||
home: Home,
|
||||
chain: Chain,
|
||||
txpool: TxPool,
|
||||
network: Network,
|
||||
system: System,
|
||||
logs: Logs,
|
||||
footer: Footer,
|
||||
};
|
||||
|
||||
export type ChartEntries = Array<ChartEntry>;
|
||||
|
|
@ -33,6 +33,11 @@ export type ChartEntry = {
|
|||
value: number,
|
||||
};
|
||||
|
||||
export type General = {
|
||||
version: ?string,
|
||||
commit: ?string,
|
||||
};
|
||||
|
||||
export type Home = {
|
||||
/* TODO (kurkomisi) */
|
||||
};
|
||||
|
|
@ -50,14 +55,6 @@ export type Network = {
|
|||
};
|
||||
|
||||
export type System = {
|
||||
/* TODO (kurkomisi) */
|
||||
};
|
||||
|
||||
export type Logs = {
|
||||
log: Array<string>,
|
||||
};
|
||||
|
||||
export type Footer = {
|
||||
activeMemory: ChartEntries,
|
||||
virtualMemory: ChartEntries,
|
||||
networkIngress: ChartEntries,
|
||||
|
|
@ -66,7 +63,8 @@ export type Footer = {
|
|||
systemCPU: ChartEntries,
|
||||
diskRead: ChartEntries,
|
||||
diskWrite: ChartEntries,
|
||||
|
||||
version: ?string,
|
||||
commit: ?string,
|
||||
};
|
||||
|
||||
export type Logs = {
|
||||
log: Array<string>,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ module.exports = {
|
|||
mangle: false,
|
||||
beautify: true,
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
PROD: process.env.NODE_ENV === 'production',
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
|
|
@ -71,7 +74,4 @@ module.exports = {
|
|||
},
|
||||
],
|
||||
},
|
||||
devServer: {
|
||||
port: 8081,
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package dashboard
|
||||
|
||||
//go:generate npm --prefix ./assets install
|
||||
//go:generate ./assets/node_modules/.bin/webpack --config ./assets/webpack.config.js --context ./assets
|
||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/dashboard.html assets/bundle.js
|
||||
//go:generate yarn --cwd ./assets install
|
||||
//go:generate yarn --cwd ./assets build
|
||||
//go:generate go-bindata -nometadata -o assets.go -prefix assets -nocompress -pkg dashboard assets/index.html assets/bundle.js
|
||||
//go:generate sh -c "sed 's#var _bundleJs#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||
//go:generate sh -c "sed 's#var _dashboardHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||
//go:generate sh -c "sed 's#var _indexHtml#//nolint:misspell\\\n&#' assets.go > assets.go.tmp && mv assets.go.tmp assets.go"
|
||||
//go:generate gofmt -w -s assets.go
|
||||
|
||||
import (
|
||||
|
|
@ -60,7 +60,7 @@ type Dashboard struct {
|
|||
|
||||
listener net.Listener
|
||||
conns map[uint32]*client // Currently live websocket connections
|
||||
charts *FooterMessage
|
||||
charts *SystemMessage
|
||||
commit string
|
||||
lock sync.RWMutex // Lock protecting the dashboard's internals
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ func New(config *Config, commit string) (*Dashboard, error) {
|
|||
conns: make(map[uint32]*client),
|
||||
config: config,
|
||||
quit: make(chan chan error),
|
||||
charts: &FooterMessage{
|
||||
charts: &SystemMessage{
|
||||
ActiveMemory: emptyChartEntries(now, activeMemorySampleLimit, config.Refresh),
|
||||
VirtualMemory: emptyChartEntries(now, virtualMemorySampleLimit, config.Refresh),
|
||||
NetworkIngress: emptyChartEntries(now, networkIngressSampleLimit, config.Refresh),
|
||||
|
|
@ -178,7 +178,7 @@ func (db *Dashboard) webHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
path := r.URL.String()
|
||||
if path == "/" {
|
||||
path = "/dashboard.html"
|
||||
path = "/index.html"
|
||||
}
|
||||
blob, err := Asset(path[1:])
|
||||
if err != nil {
|
||||
|
|
@ -224,7 +224,11 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
|||
}
|
||||
// Send the past data.
|
||||
client.msg <- Message{
|
||||
Footer: &FooterMessage{
|
||||
General: &GeneralMessage{
|
||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||
Commit: db.commit,
|
||||
},
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: db.charts.ActiveMemory,
|
||||
VirtualMemory: db.charts.VirtualMemory,
|
||||
NetworkIngress: db.charts.NetworkIngress,
|
||||
|
|
@ -233,9 +237,6 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
|
|||
SystemCPU: db.charts.SystemCPU,
|
||||
DiskRead: db.charts.DiskRead,
|
||||
DiskWrite: db.charts.DiskWrite,
|
||||
|
||||
Version: fmt.Sprintf("v%d.%d.%d%s", params.VersionMajor, params.VersionMinor, params.VersionPatch, versionMeta),
|
||||
Commit: db.commit,
|
||||
},
|
||||
}
|
||||
// Start tracking the connection and drop at connection loss.
|
||||
|
|
@ -350,7 +351,7 @@ func (db *Dashboard) collectData() {
|
|||
db.charts.DiskWrite = append(db.charts.DiskRead[1:], diskWrite)
|
||||
|
||||
db.sendToAll(&Message{
|
||||
Footer: &FooterMessage{
|
||||
System: &SystemMessage{
|
||||
ActiveMemory: ChartEntries{activeMemory},
|
||||
VirtualMemory: ChartEntries{virtualMemory},
|
||||
NetworkIngress: ChartEntries{networkIngress},
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ package dashboard
|
|||
import "time"
|
||||
|
||||
type Message struct {
|
||||
General *GeneralMessage `json:"general,omitempty"`
|
||||
Home *HomeMessage `json:"home,omitempty"`
|
||||
Chain *ChainMessage `json:"chain,omitempty"`
|
||||
TxPool *TxPoolMessage `json:"txpool,omitempty"`
|
||||
Network *NetworkMessage `json:"network,omitempty"`
|
||||
System *SystemMessage `json:"system,omitempty"`
|
||||
Logs *LogsMessage `json:"logs,omitempty"`
|
||||
Footer *FooterMessage `json:"footer,omitempty"`
|
||||
}
|
||||
|
||||
type ChartEntries []*ChartEntry
|
||||
|
|
@ -35,6 +35,11 @@ type ChartEntry struct {
|
|||
Value float64 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type GeneralMessage struct {
|
||||
Version string `json:"version,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
type HomeMessage struct {
|
||||
/* TODO (kurkomisi) */
|
||||
}
|
||||
|
|
@ -52,14 +57,6 @@ type NetworkMessage struct {
|
|||
}
|
||||
|
||||
type SystemMessage struct {
|
||||
/* TODO (kurkomisi) */
|
||||
}
|
||||
|
||||
type LogsMessage struct {
|
||||
Log []string `json:"log,omitempty"`
|
||||
}
|
||||
|
||||
type FooterMessage struct {
|
||||
ActiveMemory ChartEntries `json:"activeMemory,omitempty"`
|
||||
VirtualMemory ChartEntries `json:"virtualMemory,omitempty"`
|
||||
NetworkIngress ChartEntries `json:"networkIngress,omitempty"`
|
||||
|
|
@ -68,7 +65,8 @@ type FooterMessage struct {
|
|||
SystemCPU ChartEntries `json:"systemCPU,omitempty"`
|
||||
DiskRead ChartEntries `json:"diskRead,omitempty"`
|
||||
DiskWrite ChartEntries `json:"diskWrite,omitempty"`
|
||||
|
||||
Version string `json:"version,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
}
|
||||
|
||||
type LogsMessage struct {
|
||||
Log []string `json:"log,omitempty"`
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue