From d2506f1c34d0a2f057c1917a561ee17c0cf92d63 Mon Sep 17 00:00:00 2001 From: Breezewish Date: Fri, 14 Feb 2020 22:14:54 +0800 Subject: [PATCH 1/3] Support dev mode Signed-off-by: Breezewish --- README.md | 5 +++++ go.mod | 2 +- go.sum | 5 ++--- pkg/apiserver/apiserver.go | 5 +++-- pkg/apiserver/info/info.go | 9 +++++---- ui/.github_release_version | 2 +- ui/src/apps/demo/index.js | 1 - ui/src/apps/keyvis/RootComponent.less | 4 ++++ ui/src/apps/keyvis/ToolBar.tsx | 10 +++++----- ui/src/apps/keyvis/index.js | 1 + ui/src/index.css | 0 ui/src/index.js | 1 - ui/src/layout/RootComponent.js | 5 ++++- 13 files changed, 31 insertions(+), 19 deletions(-) delete mode 100644 ui/src/index.css diff --git a/README.md b/README.md index 4b574904c0..371f7452e8 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ A standalone TiDB Dashboard Server contains the following components: To build a dashboard server that only serves Dashboard API: ```sh +# under Dashboard directory: make server # make run ``` @@ -83,6 +84,7 @@ make server To build a dashboard server that serves both API and the Swagger API UI: ```sh +# under Dashboard directory: make # or more verbose: SWAGGER=1 make server # make run ``` @@ -97,6 +99,7 @@ Note: You need Node.js and yarn installed in order to build a full-featured dash Requirements section for details. ```sh +# under Dashboard directory: make ui # Build UI from source SWAGGER=1 UI=1 make server # make run @@ -120,6 +123,7 @@ If you want to develop Dashboard UI, the recommended workflow is as follows: first time (or backend interface has been changed), you need to build or rebuild the API client: ```bash + # under Dashboard directory: make swagger_client ``` @@ -134,6 +138,7 @@ If you want to develop Dashboard UI, the recommended workflow is as follows: 3. Start React Development Server ```sh + # under Dashboard directory: cd ui npm start ``` diff --git a/go.mod b/go.mod index c242648b39..e102cc1278 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.13 require ( github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/elazarl/go-bindata-assetfs v1.0.0 - github.com/gin-contrib/cors v1.3.0 github.com/gin-contrib/gzip v0.0.1 github.com/gin-gonic/gin v1.5.0 github.com/go-bindata/go-bindata v3.1.2+incompatible @@ -13,6 +12,7 @@ require ( github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12 github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd github.com/pkg/errors v0.9.1 + github.com/rs/cors v1.7.0 github.com/swaggo/http-swagger v0.0.0-20200103000832-0e9263c4b516 github.com/swaggo/swag v1.6.5 go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 diff --git a/go.sum b/go.sum index 806cfea037..70e5f8b2ee 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,6 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.3.0 h1:PolezCc89peu+NgkIWt9OB01Kbzt6IP0J/JvkG6xxlg= -github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc= github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc= github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= @@ -203,6 +201,8 @@ github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNG github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -309,7 +309,6 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 3ee4932beb..cc114bc8cc 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -17,9 +17,9 @@ import ( "net/http" "sync" - "github.com/gin-contrib/cors" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" + cors "github.com/rs/cors/wrapper/gin" "github.com/pingcap-incubator/tidb-dashboard/pkg/apiserver/foo" "github.com/pingcap-incubator/tidb-dashboard/pkg/apiserver/info" @@ -42,9 +42,10 @@ func Handler(apiPrefix string, config *config.Config, services *Services) http.H }) r := gin.New() - r.Use(cors.Default()) + r.Use(cors.AllowAll()) r.Use(gin.Recovery()) r.Use(gzip.Gzip(gzip.BestSpeed)) + endpoint := r.Group(apiPrefix) foo.NewService(config).Register(endpoint) diff --git a/pkg/apiserver/info/info.go b/pkg/apiserver/info/info.go index 21fd0a034c..89a867cca8 100644 --- a/pkg/apiserver/info/info.go +++ b/pkg/apiserver/info/info.go @@ -38,17 +38,18 @@ func NewService(config *config.Config, db *dbstore.DB) *Service { func (s *Service) Register(r *gin.RouterGroup) { endpoint := r.Group("/info") - endpoint.GET("/", s.infoHandler) + endpoint.GET("/info", s.infoHandler) } // @Summary Dashboard info // @Description Get information about the dashboard service. // @Produce json // @Success 200 {object} Info -// @Router /info [get] +// @Router /info/info [get] func (s *Service) infoHandler(c *gin.Context) { - c.JSON(http.StatusOK, Info{ + info := Info{ Version: s.config.Version, PDEndPoint: s.config.PDEndPoint, - }) + } + c.JSON(http.StatusOK, info) } diff --git a/ui/.github_release_version b/ui/.github_release_version index 6b328c1880..b2b58c2105 100644 --- a/ui/.github_release_version +++ b/ui/.github_release_version @@ -1,3 +1,3 @@ # This file contains a version number which will be used to release assets to # GitHub. To trigger a new asset release, simply increase this version number. -20200210_1 +20200214_1 diff --git a/ui/src/apps/demo/index.js b/ui/src/apps/demo/index.js index 40f4dae9e3..9b0fc8fd85 100644 --- a/ui/src/apps/demo/index.js +++ b/ui/src/apps/demo/index.js @@ -4,5 +4,4 @@ module.exports = { routerPrefix: '/demo', icon: 'pie-chart', menuTitle: 'Demo 2', // TODO: I18N - isDefaultRouter: true, } diff --git a/ui/src/apps/keyvis/RootComponent.less b/ui/src/apps/keyvis/RootComponent.less index 7cde43d3d1..afe86d76f0 100644 --- a/ui/src/apps/keyvis/RootComponent.less +++ b/ui/src/apps/keyvis/RootComponent.less @@ -47,6 +47,10 @@ .space { width: 12px; } + + .ant-select .anticon { + margin-right: 5px; + } } svg, diff --git a/ui/src/apps/keyvis/ToolBar.tsx b/ui/src/apps/keyvis/ToolBar.tsx index b461f843ee..a46b7d6989 100644 --- a/ui/src/apps/keyvis/ToolBar.tsx +++ b/ui/src/apps/keyvis/ToolBar.tsx @@ -1,4 +1,4 @@ -import { Slider, Spin, Icon, Select, Dropdown, Button, Input } from 'antd' +import { Slider, Spin, Icon, Select, Dropdown, Button } from 'antd' import React, { Component } from 'react' export interface IKeyVisToolBarProps { @@ -27,8 +27,8 @@ const DateRangeOptions = [ const MetricOptions = [ { text: '读取字节量', value: 'read_bytes' }, { text: '写入字节量', value: 'written_bytes' }, - { text: '读取 keys', value: 'read_keys' }, - { text: '写入 keys', value: 'written_keys' }, + { text: '读取次数', value: 'read_keys' }, + { text: '写入次数', value: 'written_keys' }, { text: '所有', value: 'integration' } ] @@ -114,7 +114,7 @@ export default class KeyVisToolBar extends Component {
- {DateRangeOptions.map(option => ( {
- {MetricOptions.map(option => ( @@ -61,7 +62,8 @@ class App extends React.PureComponent { defaultOpenKeys={['sub1']} > {this.props.registry.renderAppMenuItem('keyvis')} - {this.props.registry.renderAppMenuItem('statement')} + {isDev ? this.props.registry.renderAppMenuItem('statement') : null} + {isDev ? + : null } From 7032065f1ccc86f5b372f1c04fce93e8044fda97 Mon Sep 17 00:00:00 2001 From: Breezewish Date: Fri, 14 Feb 2020 22:39:50 +0800 Subject: [PATCH 2/3] Fix some trivial issues Signed-off-by: Breezewish --- ui/src/apps/keyvis/RootComponent.tsx | 15 +---- ui/src/apps/keyvis/ToolBar.tsx | 4 +- ui/src/apps/keyvis/api.ts | 9 --- ui/src/apps/keyvis/heatmap/chart.ts | 93 ++++++++++++---------------- 4 files changed, 47 insertions(+), 74 deletions(-) diff --git a/ui/src/apps/keyvis/RootComponent.tsx b/ui/src/apps/keyvis/RootComponent.tsx index 9232287cd8..317dbdc268 100644 --- a/ui/src/apps/keyvis/RootComponent.tsx +++ b/ui/src/apps/keyvis/RootComponent.tsx @@ -70,7 +70,6 @@ let cache = new HeatmapCache() const KeyVis = props => { const [chartState, setChartState] = useState() - const [selection, setSelection] = useState(null) const [isLoading, setLoading] = useState(false) const [isAutoFetch, setAutoFetch] = useState(false) @@ -79,11 +78,7 @@ const KeyVis = props => { const [brightLevel, setBrightLevel] = useState(1) const [metricType, setMetricType] = useState('written_bytes') - console.log('Keyvis Init') - useEffect(() => { - console.log('side effect in keyvis') - const timerId = isAutoFetch && setInterval(() => { @@ -91,7 +86,6 @@ const KeyVis = props => { }, DEFAULT_INTERVAL) return () => { - console.log('side effect in keyvis cleanup') // _chart = null timerId && clearInterval(timerId) } @@ -106,17 +100,13 @@ const KeyVis = props => { setOnBrush(false) const data = await cache.fetch(selection || dateRange, metricType) setChartState({ heatmapData: data!, metricType: metricType }) + setLoading(false) } const onChangeBrightLevel = val => { if (!_chart) return setBrightLevel(val) - const update = async () => { - await _chart.brightness(val) - setLoading(false) - } - setLoading(true) - update() + _chart.brightness(val) } const onToggleAutoFetch = (enable: Boolean | undefined) => { @@ -140,6 +130,7 @@ const KeyVis = props => { _chart = chart setLoading(false) setBrightLevel(1) + _chart.brightness(1) }, [props] ) diff --git a/ui/src/apps/keyvis/ToolBar.tsx b/ui/src/apps/keyvis/ToolBar.tsx index a46b7d6989..c5901db0b9 100644 --- a/ui/src/apps/keyvis/ToolBar.tsx +++ b/ui/src/apps/keyvis/ToolBar.tsx @@ -57,7 +57,9 @@ export default class KeyVisToolBar extends Component { handleBrightnessDropdown = (visible: boolean) => { this.setState({ brightnessDropdownVisible: visible }) - this.props.onChangeBrightLevel(1 * Math.pow(2, this.state.exp)) + setTimeout(() => { + this.handleBrightLevel(this.state.exp); + }, 0) } render() { diff --git a/ui/src/apps/keyvis/api.ts b/ui/src/apps/keyvis/api.ts index b84849ce9d..1048e56e8e 100644 --- a/ui/src/apps/keyvis/api.ts +++ b/ui/src/apps/keyvis/api.ts @@ -11,12 +11,3 @@ export async function fetchHeatmap(selection?: HeatmapRange, type: DataTag = 'wr ) return resp.data } - -/* -// Dummy Data -const dummyData: HeatmapData = require('./dummydata.json') - -export async function fetchDummyHeatmap() { - return dummyData -} -*/ diff --git a/ui/src/apps/keyvis/heatmap/chart.ts b/ui/src/apps/keyvis/heatmap/chart.ts index 9ac62e3321..3a3d4e6e8a 100644 --- a/ui/src/apps/keyvis/heatmap/chart.ts +++ b/ui/src/apps/keyvis/heatmap/chart.ts @@ -64,18 +64,7 @@ export async function heatmapChart( onZoom: () => void ) { const maxValue = d3.max(data.data[dataTag].map(array => d3.max(array)!)) || 0 - // const normalizedData = data.data[dataTag].map(row => { - // const r2 = new Float32Array(row.length); - // let l = row.length; - // for (let i = 0; i < l; i++) { - // r2[i] = row[i] / maxValue; - // } - // return r2; - // }); - // Normalize data to [0, 255] - console.time('normalize') const normalizedData = normalizeData(data.data[dataTag], maxValue) - console.timeEnd('normalize') let colorScheme: ColorScheme let brightness = 1 @@ -89,9 +78,9 @@ export async function heatmapChart( let canvasWidth = 0 let canvasHeight = 0 - heatmapChart.brightness = async function(val: number) { + heatmapChart.brightness = function(val: number) { brightness = val - await updateBuffer() + updateBuffer() heatmapChart() } @@ -126,7 +115,7 @@ export async function heatmapChart( heatmapChart() } - async function updateBuffer() { + function updateBuffer() { const d = data.data[dataTag] const height = d.length > 0 ? d[0].length : 0 const width = d.length @@ -140,7 +129,7 @@ export async function heatmapChart( colorScheme = newColorScheme } - await updateBuffer() + updateBuffer() heatmapChart() function heatmapChart() { @@ -412,7 +401,7 @@ export async function heatmapChart( function render() { renderHeatmap() // renderHighlight() - rednerAxis() + renderAxis() renderBrush() renderTooltip() renderCross() @@ -434,42 +423,42 @@ export async function heatmapChart( ) } - function renderHighlight() { - const selectedData = data.data[dataTag] - const xLen = selectedData.length - const yLen = selectedData[0].length - const xRescale = zoomTransform.rescaleX(xScale) - const yRescale = zoomTransform.rescaleY(yScale) - const xStartIdx = Math.max(0, Math.floor(xScale.invert(0))) - const xEndIdx = Math.min(xLen - 1, Math.ceil(xScale.invert(canvasWidth))) - const yStartIdx = Math.max(0, Math.floor(yScale.invert(0))) - const yEndIdx = Math.min(yLen - 1, Math.ceil(yScale.invert(canvasHeight))) - - ctx.shadowColor = '#fff' - ctx.shadowBlur = 9 + zoomTransform.k // 10 + 1 * (zoomTransform.k - 1) - ctx.fillStyle = 'blue' - for (let x = xStartIdx; x < xEndIdx; x++) { - for (let y = yStartIdx; y < yEndIdx; y++) { - if (selectedData[x][y] > maxValue / 2) { - const left = xRescale(x) - const top = yRescale(y) - const right = xRescale(x + 1) - const bottom = yRescale(y + 1) - const width = right - left - const height = bottom - top - const xPadding = ((0.8 + 0.5 * (1 - 1 / zoomTransform.k)) * width) / height - const yPadding = ((0.8 + 0.5 * (1 - 1 / zoomTransform.k)) * height) / width - ctx.beginPath() - ctx.shadowOffsetX = (left + 1000) * heatmapCanvasPixelRatio - ctx.shadowOffsetY = (top + 1000) * heatmapCanvasPixelRatio - ctx.fillRect(-1000 - xPadding, -1000 - yPadding, right - left + xPadding * 2, bottom - top + yPadding * 2) - ctx.closePath() - } - } - } - } - - function rednerAxis() { + // function renderHighlight() { + // const selectedData = data.data[dataTag] + // const xLen = selectedData.length + // const yLen = selectedData[0].length + // const xRescale = zoomTransform.rescaleX(xScale) + // const yRescale = zoomTransform.rescaleY(yScale) + // const xStartIdx = Math.max(0, Math.floor(xScale.invert(0))) + // const xEndIdx = Math.min(xLen - 1, Math.ceil(xScale.invert(canvasWidth))) + // const yStartIdx = Math.max(0, Math.floor(yScale.invert(0))) + // const yEndIdx = Math.min(yLen - 1, Math.ceil(yScale.invert(canvasHeight))) + + // ctx.shadowColor = '#fff' + // ctx.shadowBlur = 9 + zoomTransform.k // 10 + 1 * (zoomTransform.k - 1) + // ctx.fillStyle = 'blue' + // for (let x = xStartIdx; x < xEndIdx; x++) { + // for (let y = yStartIdx; y < yEndIdx; y++) { + // if (selectedData[x][y] > maxValue / 2) { + // const left = xRescale(x) + // const top = yRescale(y) + // const right = xRescale(x + 1) + // const bottom = yRescale(y + 1) + // const width = right - left + // const height = bottom - top + // const xPadding = ((0.8 + 0.5 * (1 - 1 / zoomTransform.k)) * width) / height + // const yPadding = ((0.8 + 0.5 * (1 - 1 / zoomTransform.k)) * height) / width + // ctx.beginPath() + // ctx.shadowOffsetX = (left + 1000) * heatmapCanvasPixelRatio + // ctx.shadowOffsetY = (top + 1000) * heatmapCanvasPixelRatio + // ctx.fillRect(-1000 - xPadding, -1000 - yPadding, right - left + xPadding * 2, bottom - top + yPadding * 2) + // ctx.closePath() + // } + // } + // } + // } + + function renderAxis() { const xRescale = zoomTransform.rescaleX(xScale) const yRescale = zoomTransform.rescaleY(yScale) histogramAxis( From d8c41eafa49b40355ce0be9c5131c5b94da592f2 Mon Sep 17 00:00:00 2001 From: Breezewish Date: Fri, 14 Feb 2020 23:34:16 +0800 Subject: [PATCH 3/3] Fix default routing Signed-off-by: Breezewish --- ui/src/index.js | 6 ++++++ ui/src/layout/RootComponent.js | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/index.js b/ui/src/index.js index 8cc72a7b15..4e5ab62840 100644 --- a/ui/src/index.js +++ b/ui/src/index.js @@ -97,6 +97,12 @@ registry .register(AppDemo) .register(AppStatement) ; + singleSpa.start(); +const hash = window.location.hash; +if (hash === '' || hash === '#' || hash === '#/') { + singleSpa.navigateToUrl('#' + registry.getDefaultRouter()); +} + document.getElementById('dashboard_page_spinner').remove(); diff --git a/ui/src/layout/RootComponent.js b/ui/src/layout/RootComponent.js index 3197c249b4..c05f244d9e 100644 --- a/ui/src/layout/RootComponent.js +++ b/ui/src/layout/RootComponent.js @@ -54,7 +54,6 @@ class App extends React.PureComponent { collapsible collapsed={this.state.collapsed} > -