;
@@ -37,6 +38,12 @@ export const withTheme = (Component: Rea
export function useTheme() {
return useContext(ThemeContextMock || ThemeContext);
}
+/** Hook for using memoized styles with access to the theme. */
+export const useStyles = (getStyles: (theme?: GrafanaTheme) => any) => {
+ const currentTheme = useTheme();
+ const callback = stylesFactory(stylesTheme => getStyles(stylesTheme));
+ return callback(currentTheme);
+};
/**
* Enables theme context mocking
diff --git a/packages/grafana-ui/src/themes/index.ts b/packages/grafana-ui/src/themes/index.ts
index d1e0ea0295f..77f86a763fe 100644
--- a/packages/grafana-ui/src/themes/index.ts
+++ b/packages/grafana-ui/src/themes/index.ts
@@ -1,8 +1,8 @@
-import { ThemeContext, withTheme, useTheme, mockThemeContext } from './ThemeContext';
+import { ThemeContext, withTheme, useTheme, useStyles, mockThemeContext } from './ThemeContext';
import { getTheme, mockTheme } from './getTheme';
import { selectThemeVariant } from './selectThemeVariant';
export { stylesFactory } from './stylesFactory';
-export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext };
+export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext, useStyles };
import * as styleMixins from './mixins';
export { styleMixins };
diff --git a/public/app/core/components/Branding/Branding.tsx b/public/app/core/components/Branding/Branding.tsx
index aa41fbc5025..deb119b2398 100644
--- a/public/app/core/components/Branding/Branding.tsx
+++ b/public/app/core/components/Branding/Branding.tsx
@@ -1,42 +1,53 @@
import React, { FC } from 'react';
import { css, cx } from 'emotion';
+import { useTheme } from '@grafana/ui';
export interface BrandComponentProps {
className?: string;
children?: JSX.Element | JSX.Element[];
}
-export const LoginLogo: FC = ({ className }) => {
- const maxSize = css`
- max-width: 150px;
- `;
-
- return (
- <>
-
-
- >
- );
+const LoginLogo: FC = ({ className }) => {
+ return
;
};
-export const LoginBackground: FC = ({ className, children }) => {
+const LoginBackground: FC = ({ className, children }) => {
+ const theme = useTheme();
const background = css`
- background: url(public/img/heatmap_bg_test.svg);
+ background: url(public/img/login_background_${theme.isDark ? 'dark' : 'light'}.svg);
background-size: cover;
`;
return {children}
;
};
-export const MenuLogo: FC = ({ className }) => {
+const MenuLogo: FC = ({ className }) => {
return
;
};
-export const AppTitle = 'Grafana';
+const LoginBoxBackground = () => {
+ const theme = useTheme();
+ return css`
+ background: ${theme.isLight ? 'rgba(6, 30, 200, 0.1 )' : 'rgba(18, 28, 41, 0.65)'};
+ background-size: cover;
+ `;
+};
export class Branding {
static LoginLogo = LoginLogo;
static LoginBackground = LoginBackground;
static MenuLogo = MenuLogo;
- static AppTitle = AppTitle;
+ static LoginBoxBackground = LoginBoxBackground;
+ static AppTitle = 'Grafana';
+ static LoginTitle = 'Welcome to Grafana';
+ static GetLoginSubTitle = () => {
+ const slogans = [
+ "Don't get in the way of the data",
+ 'Your single pane of glass',
+ 'Built better together',
+ 'Democratising data',
+ ];
+ const count = slogans.length;
+ return slogans[Math.floor(Math.random() * count)];
+ };
}
diff --git a/public/app/core/components/Login/ChangePassword.tsx b/public/app/core/components/Login/ChangePassword.tsx
index d1d5acd5589..47cac53f63a 100644
--- a/public/app/core/components/Login/ChangePassword.tsx
+++ b/public/app/core/components/Login/ChangePassword.tsx
@@ -1,138 +1,60 @@
-import React, { ChangeEvent, PureComponent, SyntheticEvent } from 'react';
-import { Tooltip } from '@grafana/ui';
-import { AppEvents } from '@grafana/data';
-
-import appEvents from 'app/core/app_events';
+import React, { FC, SyntheticEvent } from 'react';
+import { Tooltip, Form, Field, Input, VerticalGroup, Button, LinkButton } from '@grafana/ui';
import { selectors } from '@grafana/e2e-selectors';
-
+import { submitButton } from './LoginForm';
interface Props {
onSubmit: (pw: string) => void;
- onSkip: Function;
- focus?: boolean;
+ onSkip: (event?: SyntheticEvent) => void;
}
-interface State {
+interface PasswordDTO {
newPassword: string;
confirmNew: string;
- valid: boolean;
}
-export class ChangePassword extends PureComponent {
- private userInput: HTMLInputElement;
- constructor(props: Props) {
- super(props);
- this.state = {
- newPassword: '',
- confirmNew: '',
- valid: false,
- };
- }
-
- componentDidUpdate(prevProps: Props) {
- if (!prevProps.focus && this.props.focus) {
- this.focus();
- }
- }
-
- focus() {
- this.userInput.focus();
- }
-
- onSubmit = (e: SyntheticEvent) => {
- e.preventDefault();
-
- const { newPassword, valid } = this.state;
- if (valid) {
- this.props.onSubmit(newPassword);
- } else {
- appEvents.emit(AppEvents.alertWarning, ['New passwords do not match']);
- }
+export const ChangePassword: FC = ({ onSubmit, onSkip }) => {
+ const submit = (passwords: PasswordDTO) => {
+ onSubmit(passwords.newPassword);
};
-
- onNewPasswordChange = (e: ChangeEvent) => {
- this.setState({
- newPassword: e.target.value,
- valid: this.validate('newPassword', e.target.value),
- });
- };
-
- onConfirmPasswordChange = (e: ChangeEvent) => {
- this.setState({
- confirmNew: e.target.value,
- valid: this.validate('confirmNew', e.target.value),
- });
- };
-
- onSkip = (e: SyntheticEvent) => {
- this.props.onSkip();
- };
-
- validate(changed: string, pw: string) {
- if (changed === 'newPassword') {
- return this.state.confirmNew === pw;
- } else if (changed === 'confirmNew') {
- return this.state.newPassword === pw;
- }
- return false;
- }
-
- render() {
- return (
-
-
-
Change Password
- Before you can get started with awesome dashboards we need you to make your account more secure by changing
- your password.
-
- You can change your password again later.
-
-
-
- );
- }
-}
+
+ >
+ )}
+