grafana/public/app/core/components/Login/LoginServiceButtons.tsx
Alex Khomenko cad9e23e54
Login page: Fix button width (#86680)
* Fix login buttons width

* Login page: Fix button width

* Add todo
2024-04-22 15:31:11 +03:00

178 lines
5.1 KiB
TypeScript

import { css, cx } from '@emotion/css';
import { pickBy } from 'lodash';
import React from 'react';
import { GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data';
import { Icon, IconName, LinkButton, Stack, useStyles2, useTheme2 } from '@grafana/ui';
import config from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export interface LoginService {
bgColor: string;
enabled: boolean;
name: string;
hrefName?: string;
icon: IconName;
}
export interface LoginServices {
[key: string]: LoginService;
}
const loginServices: () => LoginServices = () => {
const oauthEnabled = !!config.oauth;
return {
saml: {
bgColor: '#464646',
enabled: config.samlEnabled,
name: config.samlName || DEFAULT_SAML_NAME,
icon: 'key-skeleton-alt',
},
google: {
bgColor: '#e84d3c',
enabled: oauthEnabled && Boolean(config.oauth.google),
name: config.oauth?.google?.name || 'Google',
icon: config.oauth?.google?.icon || ('google' as const),
},
azuread: {
bgColor: '#2f2f2f',
enabled: oauthEnabled && Boolean(config.oauth.azuread),
name: config.oauth?.azuread?.name || 'Microsoft',
icon: config.oauth?.azuread?.icon || ('microsoft' as const),
},
github: {
bgColor: '#464646',
enabled: oauthEnabled && Boolean(config.oauth.github),
name: config.oauth?.github?.name || 'GitHub',
icon: config.oauth?.github?.icon || ('github' as const),
},
gitlab: {
bgColor: '#fc6d26',
enabled: oauthEnabled && Boolean(config.oauth.gitlab),
name: config.oauth?.gitlab?.name || 'GitLab',
icon: config.oauth?.gitlab?.icon || ('gitlab' as const),
},
grafanacom: {
bgColor: '#262628',
enabled: oauthEnabled && Boolean(config.oauth.grafana_com),
name: config.oauth?.grafana_com?.name || 'Grafana.com',
icon: config.oauth?.grafana_com?.icon || ('grafana' as const),
hrefName: 'grafana_com',
},
okta: {
bgColor: '#2f2f2f',
enabled: oauthEnabled && Boolean(config.oauth.okta),
name: config.oauth?.okta?.name || 'Okta',
icon: config.oauth?.okta?.icon || ('okta' as const),
},
oauth: {
bgColor: '#262628',
enabled: oauthEnabled && Boolean(config.oauth.generic_oauth),
name: config.oauth?.generic_oauth?.name || 'OAuth',
icon: config.oauth?.generic_oauth?.icon || ('signin' as const),
hrefName: 'generic_oauth',
},
};
};
const getServiceStyles = (theme: GrafanaTheme2) => {
return {
button: css({
color: '#d8d9da',
position: 'relative',
}),
buttonIcon: css({
position: 'absolute',
left: theme.spacing(1),
top: '50%',
transform: 'translateY(-50%)',
}),
divider: {
base: css({
color: theme.colors.text.primary,
display: 'flex',
marginBottom: theme.spacing(1),
justifyContent: 'space-between',
textAlign: 'center',
width: '100%',
}),
line: css({
width: 100,
height: 10,
borderBottom: `1px solid ${theme.colors.text}`,
}),
},
};
};
const LoginDivider = () => {
const styles = useStyles2(getServiceStyles);
return (
<>
<div className={styles.divider.base}>
<div>
<div className={styles.divider.line} />
</div>
<div>
<span>{!config.disableLoginForm && <span>or</span>}</span>
</div>
<div>
<div className={styles.divider.line} />
</div>
</div>
<div className="clearfix" />
</>
);
};
function getButtonStyleFor(service: LoginService, styles: ReturnType<typeof getServiceStyles>, theme: GrafanaTheme2) {
return cx(
styles.button,
css({
backgroundColor: service.bgColor,
color: theme.colors.getContrastText(service.bgColor),
['&:hover']: {
backgroundColor: theme.colors.emphasize(service.bgColor, 0.15),
boxShadow: theme.shadows.z1,
},
})
);
}
export const LoginServiceButtons = () => {
const enabledServices = pickBy(loginServices(), (service) => service.enabled);
const hasServices = Object.keys(enabledServices).length > 0;
const theme = useTheme2();
const styles = useStyles2(getServiceStyles);
if (hasServices) {
return (
// TODO: Remove extra div when Stack supports width
<div style={{ width: '100%' }}>
<Stack direction={'column'}>
<LoginDivider />
{Object.entries(enabledServices).map(([key, service]) => {
const serviceName = service.name;
return (
<LinkButton
key={key}
className={getButtonStyleFor(service, styles, theme)}
href={`login/${service.hrefName ? service.hrefName : key}`}
target="_self"
fullWidth
>
<Icon className={styles.buttonIcon} name={service.icon} />
<Trans i18nKey="login.services.sing-in-with-prefix">Sign in with {{ serviceName }}</Trans>
</LinkButton>
);
})}
</Stack>
</div>
);
}
return null;
};