Skip to content

Commit

Permalink
ui: adapted the React UI to Thanos
Browse files Browse the repository at this point in the history
Signed-off-by: Prem Kumar <[email protected]>
  • Loading branch information
onprem committed May 5, 2020
1 parent 7f13996 commit a0e2355
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 141 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ We use *breaking* word for marking changes that are not backward compatible (rel

- [#2502](https://github.com/thanos-io/thanos/pull/2502) Added `hints` field to `SeriesResponse`. Hints in an opaque data structure that can be used to carry additional information from the store and its content is implementation specific.
- [#2521](https://github.com/thanos-io/thanos/pull/2521) Sidecar: add `thanos_sidecar_reloader_reloads_failed_total`, `thanos_sidecar_reloader_reloads_total`, `thanos_sidecar_reloader_watch_errors_total`, `thanos_sidecar_reloader_watch_events_total` and `thanos_sidecar_reloader_watches` metrics.
- [#2412](https://github.com/thanos-io/thanos/pull/2412) ui: add React UI from Prometheus upstream. Currently only accessible from Query component as only `/graph` endpoint is migrated.

### Changed

Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ REACT_APP_PATH = pkg/ui/react-app
REACT_APP_SOURCE_FILES = $(wildcard $(REACT_APP_PATH)/public/* $(REACT_APP_PATH)/src/* $(REACT_APP_PATH)/tsconfig.json)
REACT_APP_OUTPUT_DIR = pkg/ui/static/react
REACT_APP_NODE_MODULES_PATH = $(REACT_APP_PATH)/node_modules
REACT_APP_NPM_LICENSES_TARBALL = "npm_licenses.tar.bz2"

# fetch_go_bin_version downloads (go gets) the binary from specific version and installs it in $(GOBIN)/<bin>-<version>
# arguments:
Expand Down Expand Up @@ -155,7 +154,7 @@ assets: $(GOBINDATA) $(REACT_APP_OUTPUT_DIR)
@go fmt ./pkg/ui

.PHONY: react-app-lint
react-app-lint:
react-app-lint: $(REACT_APP_NODE_MODULES_PATH)
@echo ">> running React app linting"
cd $(REACT_APP_PATH) && yarn lint:ci

Expand All @@ -167,7 +166,7 @@ react-app-lint-fix:
.PHONY: react-app-test
react-app-test: | $(REACT_APP_NODE_MODULES_PATH) react-app-lint
@echo ">> running React app tests"
cd $(REACT_APP_PATH) && yarn test --no-watch --coverage
cd $(REACT_APP_PATH) && export CI=true && yarn test --no-watch --coverage

.PHONY: react-app-start
react-app-start: $(REACT_APP_NODE_MODULES_PATH)
Expand Down
10 changes: 4 additions & 6 deletions pkg/query/api/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ type API struct {
enablePartialResponse bool
replicaLabels []string
reg prometheus.Registerer
storeSet *query.StoreSet
storeSet *query.StoreSet
defaultInstantQueryMaxSourceResolution time.Duration

now func() time.Time
Expand All @@ -133,7 +133,7 @@ func NewAPI(
enablePartialResponse: enablePartialResponse,
replicaLabels: replicaLabels,
reg: reg,
storeSet: storeSet,
storeSet: storeSet,
defaultInstantQueryMaxSourceResolution: defaultInstantQueryMaxSourceResolution,

now: time.Now,
Expand Down Expand Up @@ -183,8 +183,6 @@ type queryData struct {
Warnings []error `json:"warnings,omitempty"`
}

type storesData map[string][]query.StoreStatus

func (api *API) parseEnableDedupParam(r *http.Request) (enableDeduplication bool, _ *ApiError) {
const dedupParam = "dedup"
enableDeduplication = true
Expand Down Expand Up @@ -635,9 +633,9 @@ func (api *API) labelNames(r *http.Request) (interface{}, []error, *ApiError) {
}

func (api *API) stores(r *http.Request) (interface{}, []error, *ApiError) {
statuses := make(storesData)
statuses := make(map[string][]query.StoreStatus)
for _, status := range api.storeSet.GetStoreStatus() {
statuses[status.StoreType.String()] = append(statuses[status.StoreType.String()], status)
}
return statuses, nil, nil
}
}
10 changes: 5 additions & 5 deletions pkg/query/storeset.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ type StoreSpec interface {
}

type StoreStatus struct {
Name string `json:"name"`
LastCheck time.Time `json:"last_check"`
LastError error `json:"last_error"`
Name string `json:"name"`
LastCheck time.Time `json:"last_check"`
LastError error `json:"last_error"`
LabelSets []storepb.LabelSet `json:"label_sets"`
StoreType component.StoreAPI `json:"store_type"`
MinTime int64 `json:"min_time"`
MaxTime int64 `json:"max_time"`
MinTime int64 `json:"min_time"`
MaxTime int64 `json:"max_time"`
}

type grpcStoreSpec struct {
Expand Down
104 changes: 52 additions & 52 deletions pkg/ui/bindata.go

Large diffs are not rendered by default.

24 changes: 13 additions & 11 deletions pkg/ui/react-app/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Working with the React UI

This file explains how to work with the React-based Prometheus UI.
This file explains how to work with the React-based Thanos UI.

## Introduction

The [React-based](https://reactjs.org/) Prometheus UI was was bootstrapped using [Create React App](https://github.com/facebook/create-react-app), a popular toolkit for generating React application setups. You can find general information about Create React App on [their documentation site](https://create-react-app.dev/).
The [React-based](https://reactjs.org/) Thanos UI was was bootstrapped using [Create React App](https://github.com/facebook/create-react-app), a popular toolkit for generating React application setups. You can find general information about Create React App on [their documentation site](https://create-react-app.dev/).

Instead of plain JavaScript, we use [TypeScript](https://www.typescriptlang.org/) to ensure typed code.

Expand All @@ -16,7 +16,7 @@ To work with the React UI code, you will need to have the following tools instal
* The [Yarn](https://yarnpkg.com/) package manager.
* *Recommended:* An editor with TypeScript, React, and [ESLint](https://eslint.org/) linting support. See e.g. [Create React App's editor setup instructions](https://create-react-app.dev/docs/setting-up-your-editor/). If you are not sure which editor to use, we recommend using [Visual Studio Code](https://code.visualstudio.com/docs/languages/typescript). Make sure that [the editor uses the project's TypeScript version rather than its own](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-the-workspace-version-of-typescript).

**NOTE**: When using Visual Studio Code, be sure to open the `web/ui/react-app` directory in the editor instead of the root of the repository. This way, the right ESLint and TypeScript configuration will be picked up from the React workspace.
**NOTE**: When using Visual Studio Code, be sure to open the `pkg/ui/react-app` directory in the editor instead of the root of the repository. This way, the right ESLint and TypeScript configuration will be picked up from the React workspace.

## Installing npm dependencies

Expand All @@ -28,15 +28,15 @@ Yarn consults the `package.json` and `yarn.lock` files for dependencies to insta

## Running a local development server

You can start a development server for the React UI outside of a running Prometheus server by running:
You can start a development server for the React UI outside of a running Thanos server by running:

yarn start

This will open a browser window with the React app running on http://localhost:3000/. The page will reload if you make edits to the source code. You will also see any lint errors in the console.

Due to a `"proxy": "http://localhost:9090"` setting in the `package.json` file, any API requests from the React UI are proxied to `localhost` on port `9090` by the development server. This allows you to run a normal Prometheus server to handle API requests, while iterating separately on the UI.
Due to a `"proxy": "http://localhost:10902"` setting in the `package.json` file, any API requests from the React UI are proxied to `localhost` on port `10902` by the development server. This allows you to run a normal Thanos Query server to handle API requests, while iterating separately on the UI.

[browser] ----> [localhost:3000 (dev server)] --(proxy API requests)--> [localhost:9090 (Prometheus)]
[browser] ----> [localhost:3000 (dev server)] --(proxy API requests)--> [localhost:10902 (Thanos)]

## Running tests

Expand All @@ -62,20 +62,22 @@ To detect and automatically fix lint errors, run:

yarn lint

This is also available via the `react-app-lint-fix` target in the main Prometheus `Makefile`.
This is also available via the `react-app-lint-fix` target in the main Thanos `Makefile`.

## Building the app for production

To build a production-optimized version of the React app to a `build` subdirectory, run:

yarn build

**NOTE:** You will likely not need to do this directly. Instead, this is taken care of by the `build` target in the main Prometheus `Makefile` when building the full binary.
**NOTE:** You will likely not need to do this directly. Instead, this is taken care of by the `assets` target in the main Thanos `Makefile` when building the full binary.

## Integration into Prometheus
## Integration into Thanos

To build a Prometheus binary that includes a compiled-in version of the production build of the React app, change to the root of the repository and run:
To build a Thanos binary that includes a compiled-in version of the production build of the React app, change to the root of the repository and run:

make build

This installs npm dependencies via Yarn, builds a production build of the React app, and then finally compiles in all web assets into the Prometheus binary.
This compiles in all web assets into the Thanos binary.

Note that `make build` only compiles static assets using `bindata.go`, if you are working on React UI, make sure you run `make assets` to update `pkg/ui/bindata.go`
Binary file modified pkg/ui/react-app/public/favicon.ico
100755 → 100644
Binary file not shown.
8 changes: 4 additions & 4 deletions pkg/ui/react-app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
<meta name="theme-color" content="#000000" />

<!--
This constant's placeholder magic value is replaced during serving by Prometheus
and set to Prometheus's external URL path. It gets prepended to all links back
to Prometheus, both for asset loading as well as API accesses.
This constant's placeholder magic value is replaced during serving by Thanos
and set to Thanos's external URL path. It gets prepended to all links back
to Thanos, both for asset loading as well as API accesses.
-->
<script>const GLOBAL_PATH_PREFIX='';</script>
<script>const THANOS_COMPONENT='query';</script>
Expand All @@ -31,7 +31,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Prometheus Expression Browser</title>
<title>Thanos Expression Browser</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
4 changes: 2 additions & 2 deletions pkg/ui/react-app/public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"short_name": "Prometheus UI",
"name": "Prometheus Server Web Interface",
"short_name": "Thanos",
"name": "Thanos web interface",
"icons": [
{
"src": "favicon.ico",
Expand Down
7 changes: 4 additions & 3 deletions pkg/ui/react-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { FC } from 'react';
import Navigation from './thanos/Navbar';
import { Container } from 'reactstrap';

import './App.css';
import { Router, Redirect } from '@reach/router';

import { Alerts, Config, Flags, Rules, ServiceDiscovery, Status, Targets, TSDBStatus, PanelList } from './pages';
import PathPrefixProps from './types/PathPrefixProps';
import ThanosComponentProps from './thanos/types/ThanosComponentProps';
import Navigation from './thanos/Navbar';

import './App.css';

const App: FC<PathPrefixProps & ThanosComponentProps> = ({ pathPrefix, thanosComponent }) => {
return (
Expand Down
63 changes: 33 additions & 30 deletions pkg/ui/react-app/src/pages/graph/ExpressionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,36 +77,39 @@ class ExpressionInput extends Component<ExpressionInputProps, ExpressionInputSta
const { autocompleteSections } = this.props;
let index = 0;
const sections = inputValue!.length
? Object.entries(autocompleteSections).reduce((acc, [title, items]) => {
const matches = this.getSearchMatches(inputValue!, items);
return !matches.length
? acc
: [
...acc,
<ul className="autosuggest-dropdown-list" key={title}>
<li className="autosuggest-dropdown-header">{title}</li>
{matches
.slice(0, 100) // Limit DOM rendering to 100 results, as DOM rendering is sloooow.
.map(({ original, string: text }) => {
const itemProps = downshift.getItemProps({
key: original,
index,
item: original,
style: {
backgroundColor: highlightedIndex === index++ ? 'lightgray' : 'white',
},
});
return (
<li
key={title}
{...itemProps}
dangerouslySetInnerHTML={{ __html: sanitizeHTML(text, { allowedTags: ['strong'] }) }}
/>
);
})}
</ul>,
];
}, [] as JSX.Element[])
? Object.entries(autocompleteSections).reduce(
(acc, [title, items]) => {
const matches = this.getSearchMatches(inputValue!, items);
return !matches.length
? acc
: [
...acc,
<ul className="autosuggest-dropdown-list" key={title}>
<li className="autosuggest-dropdown-header">{title}</li>
{matches
.slice(0, 100) // Limit DOM rendering to 100 results, as DOM rendering is sloooow.
.map(({ original, string: text }) => {
const itemProps = downshift.getItemProps({
key: original,
index,
item: original,
style: {
backgroundColor: highlightedIndex === index++ ? 'lightgray' : 'white',
},
});
return (
<li
key={title}
{...itemProps}
dangerouslySetInnerHTML={{ __html: sanitizeHTML(text, { allowedTags: ['strong'] }) }}
/>
);
})}
</ul>,
];
},
[] as JSX.Element[]
)
: [];

if (!sections.length) {
Expand Down
10 changes: 2 additions & 8 deletions pkg/ui/react-app/src/pages/graph/Graph.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,7 @@ describe('Graph', () => {
resolution: 28,
},
data: {
result: [
{ values: [], metric: {} },
{ values: [], metric: {} },
],
result: [{ values: [], metric: {} }, { values: [], metric: {} }],
},
} as any)}
/>
Expand Down Expand Up @@ -257,10 +254,7 @@ describe('Graph', () => {
resolution: 28,
},
data: {
result: [
{ values: [], metric: {} },
{ values: [], metric: {} },
],
result: [{ values: [], metric: {} }, { values: [], metric: {} }],
},
} as any)}
/>
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/src/pages/graph/PanelList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ const PanelList: FC<RouteComponentProps & PathPrefixProps> = ({ pathPrefix = ''
<strong>Warning: </strong>
{timeErr && `Unexpected response status when fetching server time: ${timeErr.message}`}
{delta >= 30 &&
`Error fetching server time: Detected ${delta} seconds time difference between your browser and the server. Prometheus relies on accurate time and time drift might cause unexpected query results.`}
`Error fetching server time: Detected ${delta} seconds time difference between your browser and the server. Thanos relies on accurate time and time drift might cause unexpected query results.`}
</Alert>
)}
{metricsErr && (
Expand Down
13 changes: 1 addition & 12 deletions pkg/ui/react-app/src/thanos/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
import React, { FC, useState } from 'react';
import { Link } from '@reach/router';
import {
Collapse,
Navbar,
NavbarToggler,
Nav,
NavItem,
NavLink,
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem,
} from 'reactstrap';
import { Collapse, Navbar, NavbarToggler, Nav, NavItem, NavLink } from 'reactstrap';
import PathPrefixProps from '../types/PathPrefixProps';
import ThanosComponentProps from './types/ThanosComponentProps';

Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/src/vendor/flot/jquery.flot.crosshair.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* THIS FILE WAS COPIED INTO PROMETHEUS FROM GRAFANA'S VENDORED FORK OF FLOT
* THIS FILE WAS COPIED INTO THANOS FROM GRAFANA'S VENDORED FORK OF FLOT
* (LIVING AT https://github.com/grafana/grafana/tree/master/public/vendor/flot),
* WHICH CONTAINS FIXES FOR DISPLAYING NULL VALUES IN STACKED GRAPHS. THE ORIGINAL
* FLOT CODE WAS LICENSED UNDER THE MIT LICENSE AS STATED BELOW. ADDITIONAL
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/src/vendor/flot/jquery.flot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* THIS FILE WAS COPIED INTO PROMETHEUS FROM GRAFANA'S VENDORED FORK OF FLOT
* THIS FILE WAS COPIED INTO THANOS FROM GRAFANA'S VENDORED FORK OF FLOT
* (LIVING AT https://github.com/grafana/grafana/tree/master/public/vendor/flot),
* WHICH CONTAINS FIXES FOR DISPLAYING NULL VALUES IN STACKED GRAPHS. THE ORIGINAL
* FLOT CODE WAS LICENSED UNDER THE MIT LICENSE AS STATED BELOW. ADDITIONAL
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/src/vendor/flot/jquery.flot.stack.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* THIS FILE WAS COPIED INTO PROMETHEUS FROM GRAFANA'S VENDORED FORK OF FLOT
* THIS FILE WAS COPIED INTO THANOS FROM GRAFANA'S VENDORED FORK OF FLOT
* (LIVING AT https://github.com/grafana/grafana/tree/master/public/vendor/flot),
* WHICH CONTAINS FIXES FOR DISPLAYING NULL VALUES IN STACKED GRAPHS. THE ORIGINAL
* FLOT CODE WAS LICENSED UNDER THE MIT LICENSE AS STATED BELOW. ADDITIONAL
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/src/vendor/flot/jquery.flot.time.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* THIS FILE WAS COPIED INTO PROMETHEUS FROM GRAFANA'S VENDORED FORK OF FLOT
* THIS FILE WAS COPIED INTO THANOS FROM GRAFANA'S VENDORED FORK OF FLOT
* (LIVING AT https://github.com/grafana/grafana/tree/master/public/vendor/flot),
* WHICH CONTAINS FIXES FOR DISPLAYING NULL VALUES IN STACKED GRAPHS. THE ORIGINAL
* FLOT CODE WAS LICENSED UNDER THE MIT LICENSE AS STATED BELOW. ADDITIONAL
Expand Down

0 comments on commit a0e2355

Please sign in to comment.