Merge branch 'master' into feature/400-info-card-storybook
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
# @backstage/app
|
||||
# example-app
|
||||
|
||||
This package is an example of a Backstage application.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": false
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"plugins": ["cypress"],
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
describe('App', () => {
|
||||
it('should render the welcome page', () => {
|
||||
cy.visit('/');
|
||||
cy.contains('Welcome to Backstage');
|
||||
cy.contains('Getting Started');
|
||||
cy.contains('Quick Links');
|
||||
cy.contains('APIs');
|
||||
});
|
||||
|
||||
it('should display support info when clicking the button', () => {
|
||||
cy.visit('/');
|
||||
cy.findByTestId('support-button').click({ force: true });
|
||||
cy.contains('#backstage');
|
||||
});
|
||||
|
||||
it('should display error message when triggering it', () => {
|
||||
cy.visit('/');
|
||||
cy.findByTestId('error-button').click({ force: true });
|
||||
cy.contains('Error: Oh no!');
|
||||
cy.findByTestId('error-button-close').click({ force: true });
|
||||
});
|
||||
|
||||
it('should be able to login and logout', () => {
|
||||
const name = 'test-name';
|
||||
Cypress.on('window:before:load', win => {
|
||||
win.fetch = cy.stub().resolves({
|
||||
status: 200,
|
||||
json: () => ({ username: 'test name', token: 'token', name }),
|
||||
});
|
||||
});
|
||||
|
||||
cy.visit('/');
|
||||
cy.get('a[href="/login"]').click({ force: true });
|
||||
cy.url().should('include', '/login');
|
||||
cy.contains('Welcome, guest!');
|
||||
cy.contains('Username')
|
||||
.get('input[name=github-username-tf]')
|
||||
.type(name, { force: true });
|
||||
cy.contains('Token')
|
||||
.get('input[name=github-auth-tf]')
|
||||
.type('password', { force: true });
|
||||
cy.findByTestId('github-auth-button').click({ force: true });
|
||||
cy.contains(`Welcome, ${name}!`);
|
||||
cy.contains('Logout').click({ force: true });
|
||||
cy.contains('Welcome, guest!');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import '@testing-library/cypress/add-commands';
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@backstage/app",
|
||||
"name": "example-app",
|
||||
"version": "0.1.1-alpha.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
@@ -28,7 +28,11 @@
|
||||
"start": "backstage-cli app:serve",
|
||||
"build": "backstage-cli app:build",
|
||||
"test": "backstage-cli test",
|
||||
"lint": "backstage-cli lint"
|
||||
"test:e2e": "start-server-and-test start http://localhost:3000 cy:dev",
|
||||
"test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run",
|
||||
"lint": "backstage-cli lint",
|
||||
"cy:dev": "cypress open",
|
||||
"cy:run": "cypress run"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -42,5 +46,12 @@
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@testing-library/cypress": "^6.0.0",
|
||||
"@types/jquery": "^3.3.34",
|
||||
"cypress": "^4.2.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"start-server-and-test": "^1.10.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
import React, { FC, useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Snackbar } from '@material-ui/core';
|
||||
import { Snackbar, IconButton } from '@material-ui/core';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { ErrorApi, ErrorContext } from '@backstage/core';
|
||||
|
||||
@@ -73,7 +74,19 @@ const ErrorDisplay: FC<Props> = ({ forwarder }) => {
|
||||
message={firstError.toString()}
|
||||
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
|
||||
>
|
||||
<Alert onClose={handleClose} severity="error">
|
||||
<Alert
|
||||
action={
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
onClick={handleClose}
|
||||
data-testid="error-button-close"
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
}
|
||||
severity="error"
|
||||
>
|
||||
{firstError.toString()}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
TextField,
|
||||
List,
|
||||
ListItem,
|
||||
Link
|
||||
Link,
|
||||
} from '@material-ui/core';
|
||||
import InfoCard from '../../../layout/InfoCard/InfoCard';
|
||||
|
||||
@@ -37,7 +37,9 @@ enum AuthType {
|
||||
|
||||
const LoginPage: FC<{}> = () => {
|
||||
const [githubUsername, setGithubUsername] = useState(String);
|
||||
const [githubPersonalAuthToken, setGithubPersonalAuthToken] = useState(String);
|
||||
const [githubPersonalAuthToken, setGithubPersonalAuthToken] = useState(
|
||||
String,
|
||||
);
|
||||
const [loginDetails, setLoginDetails] = useState(Object);
|
||||
|
||||
const saveGithubInfo = (info: {}) => {
|
||||
@@ -70,11 +72,11 @@ const LoginPage: FC<{}> = () => {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
}),
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
if (response.status === 200) return response.json();
|
||||
throw Error(`${response.status} ${response.statusText}`);
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
const info = {
|
||||
username: username,
|
||||
token: token,
|
||||
@@ -158,6 +160,7 @@ const LoginPage: FC<{}> = () => {
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Button
|
||||
data-testid="github-auth-button"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => authenticate(AuthType.GitHub)}
|
||||
@@ -174,4 +177,4 @@ const LoginPage: FC<{}> = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginPage;
|
||||
export default LoginPage;
|
||||
|
||||
@@ -78,7 +78,11 @@ const SupportButton: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Button color="primary" onClick={onClickHandler}>
|
||||
<Button
|
||||
data-testid="support-button"
|
||||
color="primary"
|
||||
onClick={onClickHandler}
|
||||
>
|
||||
<HelpIcon className={classes.leftIcon} />
|
||||
Support
|
||||
</Button>
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Typography, withStyles, Tooltip } from '@material-ui/core';
|
||||
import { Theme } from '../Page/Page';
|
||||
// import { Link } from 'shared/components';
|
||||
import Waves from './Waves';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
class Header extends Component {
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
typeLink: PropTypes.string,
|
||||
title: PropTypes.node.isRequired,
|
||||
tooltip: PropTypes.string,
|
||||
subtitle: PropTypes.node,
|
||||
pageTitleOverride: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
component: PropTypes.object,
|
||||
};
|
||||
|
||||
typeFragment() {
|
||||
const { type, typeLink, classes } = this.props;
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return typeLink ? (
|
||||
// <Link to={typeLink}>
|
||||
<Typography className={classes.type}>{type}</Typography>
|
||||
) : (
|
||||
// </Link>
|
||||
<Typography className={classes.type}>{type}</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
titleFragment() {
|
||||
const { title, pageTitleOverride, classes, tooltip } = this.props;
|
||||
const FinalTitle = (
|
||||
<Typography className={classes.title} variant="h4">
|
||||
{title || pageTitleOverride}
|
||||
</Typography>
|
||||
);
|
||||
if (tooltip) {
|
||||
return (
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
{FinalTitle}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return FinalTitle;
|
||||
}
|
||||
|
||||
subtitleFragment() {
|
||||
const { subtitle, classes } = this.props;
|
||||
if (!subtitle) {
|
||||
return null;
|
||||
} else if (typeof subtitle !== 'string') {
|
||||
return subtitle;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography className={classes.subtitle} variant="subtitle1">
|
||||
{subtitle}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title, pageTitleOverride, children, style, classes } = this.props;
|
||||
const pageTitle = pageTitleOverride || title;
|
||||
return (
|
||||
<Fragment>
|
||||
<Helmet
|
||||
titleTemplate={`${pageTitle} | %s | Backstage`}
|
||||
defaultTitle={`${pageTitle} | Backstage`}
|
||||
/>
|
||||
<Theme.Consumer>
|
||||
{theme => (
|
||||
<header style={style} className={classes.header}>
|
||||
<Waves theme={theme} />
|
||||
<div className={classes.leftItemsBox}>
|
||||
{this.typeFragment()}
|
||||
{this.titleFragment()}
|
||||
{this.subtitleFragment()}
|
||||
</div>
|
||||
<div className={classes.rightItemsBox}>{children}</div>
|
||||
</header>
|
||||
)}
|
||||
</Theme.Consumer>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
header: {
|
||||
gridArea: 'pageHeader',
|
||||
padding: theme.spacing(3),
|
||||
minHeight: 118,
|
||||
width: '100%',
|
||||
boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
|
||||
position: 'relative',
|
||||
zIndex: 100,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
},
|
||||
leftItemsBox: {
|
||||
flex: '1 1 auto',
|
||||
},
|
||||
rightItemsBox: {
|
||||
flex: '0 1 auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center',
|
||||
marginRight: theme.spacing(6),
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.bursts.fontColor,
|
||||
lineHeight: '1.0em',
|
||||
wordBreak: 'break-all',
|
||||
fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))',
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
subtitle: {
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
lineHeight: '1.0em',
|
||||
},
|
||||
type: {
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 9,
|
||||
opacity: 0.8,
|
||||
marginBottom: 10,
|
||||
color: theme.palette.bursts.fontColor,
|
||||
},
|
||||
});
|
||||
|
||||
export default withStyles(styles)(Header);
|
||||
+9
-3
@@ -36,18 +36,24 @@ describe('<Header/>', () => {
|
||||
});
|
||||
|
||||
it('should override document title', () => {
|
||||
const rendered = render(wrapInThemedTestApp(<Header title="Title1" pageTitleOverride="Title2" />));
|
||||
const rendered = render(
|
||||
wrapInThemedTestApp(<Header title="Title1" pageTitleOverride="Title2" />),
|
||||
);
|
||||
rendered.getByText('Title1');
|
||||
rendered.getByText('defaultTitle: Title2 | Backstage');
|
||||
});
|
||||
|
||||
it('should have subtitle', () => {
|
||||
const rendered = render(wrapInThemedTestApp(<Header title="Title" subtitle="Subtitle" />));
|
||||
const rendered = render(
|
||||
wrapInThemedTestApp(<Header title="Title" subtitle="Subtitle" />),
|
||||
);
|
||||
rendered.getByText('Subtitle');
|
||||
});
|
||||
|
||||
it('should have type rendered', () => {
|
||||
const rendered = render(wrapInThemedTestApp(<Header title="Title" type="tool" />));
|
||||
const rendered = render(
|
||||
wrapInThemedTestApp(<Header title="Title" type="tool" />),
|
||||
);
|
||||
rendered.getByText('tool');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { Fragment, ReactNode, CSSProperties, FC } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Typography, Tooltip, makeStyles } from '@material-ui/core';
|
||||
import { Theme } from '../Page/Page';
|
||||
// import { Link } from 'shared/components';
|
||||
import { BackstageTheme } from '../../theme/theme';
|
||||
import Waves from './Waves';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(theme => ({
|
||||
header: {
|
||||
gridArea: 'pageHeader',
|
||||
padding: theme.spacing(3),
|
||||
minHeight: 118,
|
||||
width: '100%',
|
||||
boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
|
||||
position: 'relative',
|
||||
zIndex: 100,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
},
|
||||
leftItemsBox: {
|
||||
flex: '1 1 auto',
|
||||
},
|
||||
rightItemsBox: {
|
||||
flex: '0 1 auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
alignItems: 'center',
|
||||
marginRight: theme.spacing(6),
|
||||
},
|
||||
title: {
|
||||
color: theme.palette.bursts.fontColor,
|
||||
lineHeight: '1.0em',
|
||||
wordBreak: 'break-all',
|
||||
fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))',
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
subtitle: {
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
lineHeight: '1.0em',
|
||||
},
|
||||
type: {
|
||||
textTransform: 'uppercase',
|
||||
fontSize: 9,
|
||||
opacity: 0.8,
|
||||
marginBottom: 10,
|
||||
color: theme.palette.bursts.fontColor,
|
||||
},
|
||||
}));
|
||||
|
||||
type HeaderStyles = ReturnType<typeof useStyles>;
|
||||
|
||||
type Props = {
|
||||
component?: ReactNode;
|
||||
pageTitleOverride?: string;
|
||||
style?: CSSProperties;
|
||||
subtitle?: ReactNode;
|
||||
title: ReactNode;
|
||||
tooltip?: string;
|
||||
type?: string;
|
||||
typeLink?: string;
|
||||
};
|
||||
|
||||
type TypeFragmentProps = {
|
||||
classes: HeaderStyles;
|
||||
type?: Props['title'];
|
||||
typeLink?: Props['typeLink'];
|
||||
};
|
||||
|
||||
type TitleFragmentProps = {
|
||||
classes: HeaderStyles;
|
||||
pageTitle: string | ReactNode;
|
||||
tooltip?: Props['tooltip'];
|
||||
};
|
||||
|
||||
type SubtitleFragmentProps = {
|
||||
classes: HeaderStyles;
|
||||
subtitle?: Props['subtitle'];
|
||||
};
|
||||
|
||||
const TypeFragment: FC<TypeFragmentProps> = ({ type, typeLink, classes }) => {
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!typeLink) {
|
||||
return (
|
||||
// </Link>
|
||||
<Typography className={classes.type}>{type}</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
// <Link to={typeLink}>
|
||||
<Typography className={classes.type}>{type}</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
const TitleFragment: FC<TitleFragmentProps> = ({
|
||||
pageTitle,
|
||||
classes,
|
||||
tooltip,
|
||||
}) => {
|
||||
const FinalTitle = (
|
||||
<Typography className={classes.title} variant="h4">
|
||||
{pageTitle}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
if (!tooltip) {
|
||||
return FinalTitle;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={tooltip} placement="top-start">
|
||||
{FinalTitle}
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const SubtitleFragment: FC<SubtitleFragmentProps> = ({ classes, subtitle }) => {
|
||||
if (!subtitle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof subtitle !== 'string') {
|
||||
return <>{subtitle}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography className={classes.subtitle} variant="subtitle1">
|
||||
{subtitle}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header: FC<Props> = ({
|
||||
children,
|
||||
pageTitleOverride,
|
||||
style,
|
||||
subtitle,
|
||||
title,
|
||||
tooltip,
|
||||
type,
|
||||
typeLink,
|
||||
}) => {
|
||||
const classes = useStyles();
|
||||
const documentTitle = pageTitleOverride || title;
|
||||
const pageTitle = title || pageTitleOverride;
|
||||
const titleTemplate = `${documentTitle} | %s | Backstage`;
|
||||
const defaultTitle = `${documentTitle} | Backstage`;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Helmet titleTemplate={titleTemplate} defaultTitle={defaultTitle} />
|
||||
<Theme.Consumer>
|
||||
{theme => (
|
||||
<header style={style} className={classes.header}>
|
||||
<Waves theme={theme} />
|
||||
<div className={classes.leftItemsBox}>
|
||||
<TypeFragment classes={classes} type={type} typeLink={typeLink} />
|
||||
<TitleFragment
|
||||
classes={classes}
|
||||
pageTitle={pageTitle}
|
||||
tooltip={tooltip}
|
||||
/>
|
||||
<SubtitleFragment classes={classes} subtitle={subtitle} />
|
||||
</div>
|
||||
<div className={classes.rightItemsBox}>{children}</div>
|
||||
</header>
|
||||
)}
|
||||
</Theme.Consumer>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -84,7 +84,6 @@ const Waves = ({ theme }) => {
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor={color1} />
|
||||
<stop offset="1" stopColor={color2} />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear"
|
||||
|
||||
@@ -75,7 +75,7 @@ export const gradients: Record<string, Gradient> = {
|
||||
colors: ['#69B9FF', '#ACCEEC'],
|
||||
},
|
||||
teal: {
|
||||
colors: ['#1F8A77', 'rgba(155, 240, 225, 1.0)'],
|
||||
colors: ['#005E4D', '#9BF0E1'],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ export const SidebarItem: FC<SidebarItemProps> = ({
|
||||
onClick={onClick}
|
||||
underline="none"
|
||||
>
|
||||
<div className={classes.iconContainer}>
|
||||
<div data-testid="login-button" className={classes.iconContainer}>
|
||||
<Icon fontSize="small" />
|
||||
</div>
|
||||
<Typography variant="subtitle1" className={classes.label}>
|
||||
|
||||
Vendored
+7
@@ -39,5 +39,12 @@ export type BackstageTheme = Theme & {
|
||||
linkHover: string;
|
||||
link: string;
|
||||
gold: string;
|
||||
bursts: {
|
||||
fontColor: string;
|
||||
slackChannelText: string;
|
||||
backgroundColor: {
|
||||
default: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user