Skip to content
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

UI: add dark theme #4249

Merged
merged 2 commits into from
May 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 :warning:_ to mark changes that are not backward compatible (re
- [#4176](https://github.com/thanos-io/thanos/pull/4176) Query API: Adds optional `Stats param` to return stats for query APIs
- [#4125](https://github.com/thanos-io/thanos/pull/4125) Rule: Add `--alert.relabel-config` / `--alert.relabel-config-file` allowing to specify alert relabel configurations like [Prometheus](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config)
- [#4211](https://github.com/thanos-io/thanos/pull/4211) Add TLS and basic authentication to Thanos APIs
- [#4249](https://github.com/thanos-io/thanos/pull/4249) UI: add dark theme

### Fixed
-
Expand Down
142 changes: 71 additions & 71 deletions pkg/ui/bindata.go

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pkg/ui/react-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@codemirror/search": "^0.18.2",
"@codemirror/state": "^0.18.2",
"@codemirror/view": "^0.18.3",
"@forevolve/bootstrap-dark": "^1.0.0",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"@fortawesome/react-fontawesome": "^0.1.14",
Expand Down Expand Up @@ -44,9 +45,11 @@
"react-test-renderer": "^16.14.0",
"reactstrap": "^8.9.0",
"sanitize-html": "^2.3.2",
"sass": "^1.32.13",
"tempusdominus-bootstrap-4": "^5.39.0",
"tempusdominus-core": "^5.19.0",
"typescript": "3.9.9",
"use-media": "^1.4.0",
"use-query-params": "^1.1.9"
},
"scripts": {
Expand Down Expand Up @@ -79,12 +82,12 @@
"@types/moment-timezone": "^0.5.30",
"@types/node": "^14.14.30",
"@types/reach__router": "^1.3.7",
"@types/reactstrap": "^8.7.2",
"@types/react": "^17.0.2",
"@types/react-copy-to-clipboard": "^5.0.0",
"@types/react-dom": "^17.0.1",
"@types/react-resize-detector": "^4.0.2",
"@types/react-select": "^4.0.13",
"@types/reactstrap": "^8.7.2",
"@types/sanitize-html": "^1.27.1",
"@types/sinon": "^9.0.10",
"@typescript-eslint/eslint-plugin": "^4.15.1",
Expand Down
2 changes: 1 addition & 1 deletion pkg/ui/react-app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
-->
<title>Thanos | Highly available Prometheus setup</title>
</head>
<body>
<body class="bootstrap">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
Expand Down
76 changes: 47 additions & 29 deletions pkg/ui/react-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import React, { FC } from 'react';
import { Container } from 'reactstrap';
import { Router, Redirect, globalHistory } from '@reach/router';
import { QueryParamProvider } from 'use-query-params';
import useMedia from 'use-media';

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

import './App.css';
import { ThemeContext, themeName, themeSetting } from './contexts/ThemeContext';
import { Theme, themeLocalStorageKey } from './Theme';
import { useLocalStorage } from './hooks/useLocalStorage';

const defaultRouteConfig: { [component: string]: string } = {
query: '/graph',
Expand All @@ -20,35 +22,51 @@ const defaultRouteConfig: { [component: string]: string } = {
};

const App: FC<PathPrefixProps & ThanosComponentProps> = ({ pathPrefix, thanosComponent }) => {
const [userTheme, setUserTheme] = useLocalStorage<themeSetting>(themeLocalStorageKey, 'auto');
const browserHasThemes = useMedia('(prefers-color-scheme)');
const browserWantsDarkTheme = useMedia('(prefers-color-scheme: dark)');

let theme: themeName;
if (userTheme !== 'auto') {
theme = userTheme;
} else {
theme = browserHasThemes ? (browserWantsDarkTheme ? 'dark' : 'light') : 'light';
}

return (
<ErrorBoundary>
<Navigation
pathPrefix={pathPrefix}
thanosComponent={thanosComponent}
defaultRoute={defaultRouteConfig[thanosComponent]}
/>
<Container fluid style={{ paddingTop: 70 }}>
<QueryParamProvider reachHistory={globalHistory}>
<Router basepath={`${pathPrefix}`}>
<Redirect from="/" to={`${pathPrefix}${defaultRouteConfig[thanosComponent]}`} />
<ThemeContext.Provider
value={{ theme: theme, userPreference: userTheme, setTheme: (t: themeSetting) => setUserTheme(t) }}
>
<Theme />
<ErrorBoundary>
<Navigation
pathPrefix={pathPrefix}
thanosComponent={thanosComponent}
defaultRoute={defaultRouteConfig[thanosComponent]}
/>
<Container fluid style={{ paddingTop: 70 }}>
<QueryParamProvider reachHistory={globalHistory}>
<Router basepath={`${pathPrefix}`}>
<Redirect from="/" to={`${pathPrefix}${defaultRouteConfig[thanosComponent]}`} />

<PanelList path="/graph" pathPrefix={pathPrefix} />
<Alerts path="/alerts" pathPrefix={pathPrefix} />
<Config path="/config" pathPrefix={pathPrefix} />
<Flags path="/flags" pathPrefix={pathPrefix} />
<Rules path="/rules" pathPrefix={pathPrefix} />
<ServiceDiscovery path="/service-discovery" pathPrefix={pathPrefix} />
<Status path="/status" pathPrefix={pathPrefix} />
<TSDBStatus path="/tsdb-status" pathPrefix={pathPrefix} />
<Targets path="/targets" pathPrefix={pathPrefix} />
<Stores path="/stores" pathPrefix={pathPrefix} />
<Blocks path="/blocks" pathPrefix={pathPrefix} />
<Blocks path="/loaded" pathPrefix={pathPrefix} view="loaded" />
<NotFound pathPrefix={pathPrefix} default defaultRoute={defaultRouteConfig[thanosComponent]} />
</Router>
</QueryParamProvider>
</Container>
</ErrorBoundary>
<PanelList path="/graph" pathPrefix={pathPrefix} />
<Alerts path="/alerts" pathPrefix={pathPrefix} />
<Config path="/config" pathPrefix={pathPrefix} />
<Flags path="/flags" pathPrefix={pathPrefix} />
<Rules path="/rules" pathPrefix={pathPrefix} />
<ServiceDiscovery path="/service-discovery" pathPrefix={pathPrefix} />
<Status path="/status" pathPrefix={pathPrefix} />
<TSDBStatus path="/tsdb-status" pathPrefix={pathPrefix} />
<Targets path="/targets" pathPrefix={pathPrefix} />
<Stores path="/stores" pathPrefix={pathPrefix} />
<Blocks path="/blocks" pathPrefix={pathPrefix} />
<Blocks path="/loaded" pathPrefix={pathPrefix} view="loaded" />
<NotFound pathPrefix={pathPrefix} default defaultRoute={defaultRouteConfig[thanosComponent]} />
</Router>
</QueryParamProvider>
</Container>
</ErrorBoundary>
</ThemeContext.Provider>
);
};

Expand Down
4 changes: 3 additions & 1 deletion pkg/ui/react-app/src/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
DropdownItem,
} from 'reactstrap';
import PathPrefixProps from './types/PathPrefixProps';
import { ThemeToggle } from './Theme';

interface NavbarProps {
consolesLink: string | null;
Expand All @@ -23,7 +24,7 @@ const Navigation: FC<PathPrefixProps & NavbarProps> = ({ pathPrefix, consolesLin
const toggle = () => setIsOpen(!isOpen);
return (
<Navbar className="mb-3" dark color="dark" expand="md" fixed="top">
<NavbarToggler onClick={toggle} />
<NavbarToggler onClick={toggle} className="mr-2" />
<Link className="pt-0 navbar-brand" to={`${pathPrefix}/graph`}>
Prometheus
</Link>
Expand Down Expand Up @@ -80,6 +81,7 @@ const Navigation: FC<PathPrefixProps & NavbarProps> = ({ pathPrefix, consolesLin
</NavItem>
</Nav>
</Collapse>
<ThemeToggle />
</Navbar>
);
};
Expand Down
57 changes: 57 additions & 0 deletions pkg/ui/react-app/src/Theme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
*
* THIS FILE WAS COPIED INTO THANOS FROM PROMETHEUS
* (LIVING AT https://github.com/prometheus/prometheus/blob/main/web/ui/react-app/src/Theme.tsx),
* THE ORIGINAL CODE WAS LICENSED UNDER AN APACHE 2.0 LICENSE, SEE
* https://github.com/prometheus/prometheus/blob/main/LICENSE.
*
*/

import React, { FC, useEffect } from 'react';
import { Form, Button, ButtonGroup } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faMoon, faSun, faAdjust } from '@fortawesome/free-solid-svg-icons';
import { useTheme } from './contexts/ThemeContext';

export const themeLocalStorageKey = 'user-prefers-color-scheme';

export const Theme: FC = () => {
const { theme } = useTheme();

useEffect(() => {
document.body.classList.toggle('bootstrap-dark', theme === 'dark');
document.body.classList.toggle('bootstrap', theme === 'light');
}, [theme]);

return null;
};

export const ThemeToggle: FC = () => {
const { userPreference, setTheme } = useTheme();

return (
<Form className="ml-auto" inline>
<ButtonGroup size="sm">
<Button
color="secondary"
title="Use light theme"
active={userPreference === 'light'}
onClick={() => setTheme('light')}
>
<FontAwesomeIcon icon={faSun} className={userPreference === 'light' ? 'text-white' : 'text-dark'} />
</Button>
<Button color="secondary" title="Use dark theme" active={userPreference === 'dark'} onClick={() => setTheme('dark')}>
<FontAwesomeIcon icon={faMoon} className={userPreference === 'dark' ? 'text-white' : 'text-dark'} />
</Button>
<Button
color="secondary"
title="Use browser-preferred theme"
active={userPreference === 'auto'}
onClick={() => setTheme('auto')}
>
<FontAwesomeIcon icon={faAdjust} className={userPreference === 'auto' ? 'text-white' : 'text-dark'} />
</Button>
</ButtonGroup>
</Form>
);
};
31 changes: 31 additions & 0 deletions pkg/ui/react-app/src/contexts/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
*
* THIS FILE WAS COPIED INTO THANOS FROM PROMETHEUS
* (LIVING AT https://github.com/prometheus/prometheus/blob/main/web/ui/react-app/src/contexts/ThemeContext.tsx),
* THE ORIGINAL CODE WAS LICENSED UNDER AN APACHE 2.0 LICENSE, SEE
* https://github.com/prometheus/prometheus/blob/main/LICENSE.
*
*/

import React from 'react';

export type themeName = 'light' | 'dark';
export type themeSetting = themeName | 'auto';

export interface ThemeCtx {
theme: themeName;
userPreference: themeSetting;
setTheme: (t: themeSetting) => void;
}

// defaults, will be overriden in App.tsx
export const ThemeContext = React.createContext<ThemeCtx>({
theme: 'light',
userPreference: 'auto',
// eslint-disable-next-line @typescript-eslint/no-empty-function
setTheme: (s: themeSetting) => {},
});

export const useTheme = () => {
return React.useContext(ThemeContext);
};
4 changes: 3 additions & 1 deletion pkg/ui/react-app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import './globals';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';
import './themes/app.scss';
import './themes/light.scss';
import './themes/dark.scss';
import './fonts/codicon.ttf';
import { isPresent } from './utils';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const CollapsibleAlertPanel: FC<CollapsibleAlertPanelProps> = ({ rule, showAnnot
<strong>{rule.name}</strong> ({`${rule.alerts.length} active`})
</Alert>
<Collapse isOpen={open} className="mb-2">
<pre style={{ background: '#f5f5f5', padding: 15 }}>
<pre className="alert-cell">
<code>
<div>
name: <a href={createExternalExpressionLink(`ALERTS{alertname="${rule.name}"}`)}>{rule.name}</a>
Expand Down
10 changes: 0 additions & 10 deletions pkg/ui/react-app/src/pages/config/Config.css

This file was deleted.

1 change: 0 additions & 1 deletion pkg/ui/react-app/src/pages/config/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Button } from 'reactstrap';
import CopyToClipboard from 'react-copy-to-clipboard';
import PathPrefixProps from '../../types/PathPrefixProps';

import './Config.css';
import { withStatusIndicator } from '../../components/withStatusIndicator';
import { useFetch } from '../../hooks/useFetch';

Expand Down
14 changes: 10 additions & 4 deletions pkg/ui/react-app/src/pages/graph/CMExpressionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import { commentKeymap } from '@codemirror/comment';
import { lintKeymap } from '@codemirror/lint';
import { PromQLExtension, CompleteStrategy } from 'codemirror-promql';
import { autocompletion, completionKeymap, CompletionContext, CompletionResult } from '@codemirror/autocomplete';
import { theme, promqlHighlighter } from './CMTheme';
import { baseTheme, lightTheme, darkTheme, promqlHighlighter } from './CMTheme';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSearch, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { newCompleteStrategy } from 'codemirror-promql/cjs/complete';
import PathPrefixProps from '../../types/PathPrefixProps';
import { useTheme } from '../../contexts/ThemeContext';

const promqlExtension = new PromQLExtension();

Expand Down Expand Up @@ -88,6 +89,7 @@ const CMExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const viewRef = useRef<EditorView | null>(null);
const { theme } = useTheme();

// (Re)initialize editor based on settings / setting changes.
useEffect(() => {
Expand All @@ -103,7 +105,11 @@ const CMExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
queryHistory
),
});
const dynamicConfig = [enableHighlighting ? promqlHighlighter : [], promqlExtension.asExtension()];
const dynamicConfig = [
enableHighlighting ? promqlHighlighter : [],
promqlExtension.asExtension(),
theme === 'dark' ? darkTheme : lightTheme,
];

// Create or reconfigure the editor.
const view = viewRef.current;
Expand All @@ -116,7 +122,7 @@ const CMExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
const startState = EditorState.create({
doc: value,
extensions: [
theme,
baseTheme,
highlightSpecialChars(),
history(),
EditorState.allowMultipleSelections.of(true),
Expand Down Expand Up @@ -189,7 +195,7 @@ const CMExpressionInput: FC<PathPrefixProps & CMExpressionInputProps> = ({
// re-run this effect every time that "value" changes.
//
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [enableAutocomplete, enableHighlighting, enableLinter, executeQuery, onExpressionChange, queryHistory]);
}, [enableAutocomplete, enableHighlighting, enableLinter, executeQuery, onExpressionChange, queryHistory, theme]);

return (
<>
Expand Down
Loading