Merge pull request #14671 from luchillo17/feat/BCKSTG-73-core-components-theme-sync
Sync @backstage/core-components with Backstage's Component Design Guidelines
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
'@backstage/test-utils': patch
|
||||
---
|
||||
|
||||
Sync components in @backstage/core-components with the Component Design Guidelines
|
||||
@@ -52,10 +52,10 @@ import { Theme } from '@material-ui/core/styles';
|
||||
import { TooltipProps } from '@material-ui/core/Tooltip';
|
||||
import { WithStyles } from '@material-ui/core/styles';
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export function AlertDisplay(props: AlertDisplayProps): JSX.Element | null;
|
||||
|
||||
// @public
|
||||
// @public (undocumented)
|
||||
export type AlertDisplayProps = {
|
||||
anchorOrigin?: {
|
||||
vertical: 'top' | 'bottom';
|
||||
|
||||
@@ -13,14 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import { alertApiRef, AlertMessage, useApi } from '@backstage/core-plugin-api';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Snackbar from '@material-ui/core/Snackbar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import { AlertMessage, useApi, alertApiRef } from '@backstage/core-plugin-api';
|
||||
import pluralize from 'pluralize';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
// TODO: improve on this and promote to a shared component for use by all apps.
|
||||
|
||||
/** @public */
|
||||
export type AlertDisplayProps = {
|
||||
anchorOrigin?: {
|
||||
vertical: 'top' | 'bottom';
|
||||
horizontal: 'left' | 'center' | 'right';
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays alerts from {@link @backstage/core-plugin-api#AlertApi}
|
||||
@@ -30,17 +40,6 @@ import pluralize from 'pluralize';
|
||||
*
|
||||
* Shown as SnackBar at the center top of the page by default. Configurable with props.
|
||||
*/
|
||||
|
||||
// TODO: improve on this and promote to a shared component for use by all apps.
|
||||
|
||||
export type AlertDisplayProps = {
|
||||
anchorOrigin?: {
|
||||
vertical: 'top' | 'bottom';
|
||||
horizontal: 'left' | 'center' | 'right';
|
||||
};
|
||||
};
|
||||
|
||||
/** @public */
|
||||
export function AlertDisplay(props: AlertDisplayProps) {
|
||||
const [messages, setMessages] = useState<Array<AlertMessage>>([]);
|
||||
const alertApi = useApi(alertApiRef);
|
||||
@@ -82,7 +81,7 @@ export function AlertDisplay(props: AlertDisplayProps) {
|
||||
}
|
||||
severity={firstMessage.severity}
|
||||
>
|
||||
<span>
|
||||
<Typography component="span">
|
||||
{String(firstMessage.message)}
|
||||
{messages.length > 1 && (
|
||||
<em>{` (${messages.length - 1} older ${pluralize(
|
||||
@@ -90,7 +89,7 @@ export function AlertDisplay(props: AlertDisplayProps) {
|
||||
messages.length - 1,
|
||||
)})`}</em>
|
||||
)}
|
||||
</span>
|
||||
</Typography>
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
);
|
||||
|
||||
@@ -29,7 +29,9 @@ describe('<Avatar />', () => {
|
||||
it('generates a background color', async () => {
|
||||
const bgcolor = stringToColor('John Doe');
|
||||
const { getByText } = render(<Avatar displayName="John Doe" />);
|
||||
expect(getByText('JD')).toHaveStyle(`background-color: ${bgcolor}`);
|
||||
expect(getByText('JD').parentElement).toHaveStyle(
|
||||
`background-color: ${bgcolor}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not generate a background color when a picture is given', async () => {
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { CSSProperties } from 'react';
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
|
||||
import MaterialAvatar from '@material-ui/core/Avatar';
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { CSSProperties } from 'react';
|
||||
|
||||
import { extractInitials, stringToColor } from './utils';
|
||||
|
||||
/** @public */
|
||||
@@ -28,6 +30,8 @@ const useStyles = makeStyles(
|
||||
width: '4rem',
|
||||
height: '4rem',
|
||||
color: '#fff',
|
||||
},
|
||||
avatarText: {
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
letterSpacing: '1px',
|
||||
textTransform: 'uppercase',
|
||||
@@ -68,6 +72,11 @@ export function Avatar(props: AvatarProps) {
|
||||
const { displayName, picture, customStyles } = props;
|
||||
const classes = useStyles();
|
||||
let styles = { ...customStyles };
|
||||
const fontStyles = {
|
||||
fontFamily: styles.fontFamily,
|
||||
fontSize: styles.fontSize,
|
||||
fontWeight: styles.fontWeight,
|
||||
};
|
||||
// We only calculate the background color if there's not an avatar
|
||||
// picture. If there is a picture, it might have a transparent
|
||||
// background and we don't know whether the calculated background
|
||||
@@ -85,7 +94,16 @@ export function Avatar(props: AvatarProps) {
|
||||
className={classes.avatar}
|
||||
style={styles}
|
||||
>
|
||||
{displayName && extractInitials(displayName)}
|
||||
{displayName && (
|
||||
<Typography
|
||||
variant="h6"
|
||||
component="span"
|
||||
className={classes.avatarText}
|
||||
style={fontStyles}
|
||||
>
|
||||
{extractInitials(displayName)}
|
||||
</Typography>
|
||||
)}
|
||||
</MaterialAvatar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { CopyTextButton } from '../CopyTextButton';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
import type {} from 'react-syntax-highlighter';
|
||||
import { default as LightAsync } from 'react-syntax-highlighter/dist/esm/light-async';
|
||||
import LightAsync from 'react-syntax-highlighter/dist/esm/light-async';
|
||||
import dark from 'react-syntax-highlighter/dist/esm/styles/hljs/dark';
|
||||
import docco from 'react-syntax-highlighter/dist/esm/styles/hljs/docco';
|
||||
|
||||
import { CopyTextButton } from '../CopyTextButton';
|
||||
|
||||
/**
|
||||
* Properties for {@link CodeSnippet}
|
||||
*
|
||||
@@ -87,7 +88,7 @@ export function CodeSnippet(props: CodeSnippetProps) {
|
||||
const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';
|
||||
|
||||
return (
|
||||
<div style={{ position: 'relative' }}>
|
||||
<Box position="relative">
|
||||
<LightAsync
|
||||
customStyle={customStyle}
|
||||
language={language}
|
||||
@@ -108,10 +109,10 @@ export function CodeSnippet(props: CodeSnippetProps) {
|
||||
{text}
|
||||
</LightAsync>
|
||||
{showCopyCodeButton && (
|
||||
<div style={{ position: 'absolute', top: 0, right: 0 }}>
|
||||
<Box position="absolute" top={0} right={0}>
|
||||
<CopyTextButton text={text} />
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ const useStyles = makeStyles(
|
||||
zIndex: 'unset',
|
||||
},
|
||||
icon: {
|
||||
fontSize: 20,
|
||||
fontSize: theme.typography.h6.fontSize,
|
||||
},
|
||||
content: {
|
||||
width: '100%',
|
||||
|
||||
@@ -13,15 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
|
||||
import { CodeSnippet } from '../CodeSnippet';
|
||||
import { Link } from '../Link';
|
||||
import { EmptyState } from './EmptyState';
|
||||
import { CodeSnippet } from '../CodeSnippet';
|
||||
|
||||
const COMPONENT_YAML_TEMPLATE = `apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
@@ -109,7 +110,7 @@ export function MissingAnnotationEmptyState(props: Props) {
|
||||
Add the annotation to your component YAML as shown in the
|
||||
highlighted example below:
|
||||
</Typography>
|
||||
<div className={classes.code}>
|
||||
<Box className={classes.code}>
|
||||
<CodeSnippet
|
||||
text={generateComponentYaml(annotations)}
|
||||
language="yaml"
|
||||
@@ -117,7 +118,7 @@ export function MissingAnnotationEmptyState(props: Props) {
|
||||
highlightedNumbers={generateLineNumbers(annotations.length)}
|
||||
customStyle={{ background: 'inherit', fontSize: '115%' }}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
<Button color="primary" component={Link} to={url}>
|
||||
Read more
|
||||
</Button>
|
||||
|
||||
+11
-10
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
@@ -26,6 +26,7 @@ import React, {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { usePortal } from './lib/usePortal';
|
||||
import { useShowCallout } from './lib/useShowCallout';
|
||||
|
||||
@@ -168,14 +169,14 @@ export function FeatureCalloutCircular(props: PropsWithChildren<Props>) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.featureWrapper} ref={wrapperRef}>
|
||||
<Box className={classes.featureWrapper} {...{ ref: wrapperRef }}>
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
{createPortal(
|
||||
<div className={classes.backdrop}>
|
||||
<Box className={classes.backdrop}>
|
||||
<ClickAwayListener onClickAway={hide}>
|
||||
<>
|
||||
<div
|
||||
<Box
|
||||
className={classes.dot}
|
||||
data-testid="dot"
|
||||
style={{
|
||||
@@ -190,9 +191,9 @@ export function FeatureCalloutCircular(props: PropsWithChildren<Props>) {
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className={classes.pulseCircle} />
|
||||
</div>
|
||||
<div
|
||||
<Box className={classes.pulseCircle} />
|
||||
</Box>
|
||||
<Box
|
||||
className={classes.text}
|
||||
data-testid="text"
|
||||
style={{
|
||||
@@ -205,10 +206,10 @@ export function FeatureCalloutCircular(props: PropsWithChildren<Props>) {
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography>{description}</Typography>
|
||||
</div>
|
||||
</Box>
|
||||
</>
|
||||
</ClickAwayListener>
|
||||
</div>,
|
||||
</Box>,
|
||||
portalElement,
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -18,6 +18,8 @@ import classnames from 'classnames';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import LinkIcon from '@material-ui/icons/Link';
|
||||
import { Link } from '../Link';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
export type IconLinkVerticalProps = {
|
||||
color?: 'primary' | 'secondary';
|
||||
@@ -56,9 +58,8 @@ const useIconStyles = makeStyles(
|
||||
color: theme.palette.secondary.main,
|
||||
},
|
||||
label: {
|
||||
fontSize: '0.7rem',
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 600,
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
letterSpacing: 1.2,
|
||||
},
|
||||
}),
|
||||
@@ -79,10 +80,16 @@ export function IconLinkVertical({
|
||||
|
||||
if (disabled) {
|
||||
return (
|
||||
<div title={title} className={classnames(classes.link, classes.disabled)}>
|
||||
<Box title={title} className={classnames(classes.link, classes.disabled)}>
|
||||
{icon}
|
||||
<span className={classes.label}>{label}</span>
|
||||
</div>
|
||||
<Typography
|
||||
variant="caption"
|
||||
component="span"
|
||||
className={classes.label}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,7 +101,9 @@ export function IconLinkVertical({
|
||||
onClick={onClick}
|
||||
>
|
||||
{icon}
|
||||
<span className={classes.label}>{label}</span>
|
||||
<Typography variant="caption" component="span" className={classes.label}>
|
||||
{label}
|
||||
</Typography>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
+5
-5
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles, Theme } from '@material-ui/core/styles';
|
||||
@@ -227,7 +227,7 @@ export function HorizontalScrollGrid(props: PropsWithChildren<Props>) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div {...otherProps} className={classes.root}>
|
||||
<Box {...otherProps} className={classes.root}>
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
@@ -237,12 +237,12 @@ export function HorizontalScrollGrid(props: PropsWithChildren<Props>) {
|
||||
>
|
||||
{children}
|
||||
</Grid>
|
||||
<div
|
||||
<Box
|
||||
className={classNames(classes.fade, classes.fadeLeft, {
|
||||
[classes.fadeHidden]: scrollLeft === 0,
|
||||
})}
|
||||
/>
|
||||
<div
|
||||
<Box
|
||||
className={classNames(classes.fade, classes.fadeRight, {
|
||||
[classes.fadeHidden]: scrollRight === 0,
|
||||
})}
|
||||
@@ -265,6 +265,6 @@ export function HorizontalScrollGrid(props: PropsWithChildren<Props>) {
|
||||
<ChevronRightIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import CSS from 'csstype';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CSS from 'csstype';
|
||||
import React from 'react';
|
||||
|
||||
type Props = CSS.Properties & {
|
||||
shorthand?: boolean;
|
||||
@@ -47,15 +47,16 @@ export function Lifecycle(props: Props) {
|
||||
const classes = useStyles(props);
|
||||
const { shorthand, alpha } = props;
|
||||
return shorthand ? (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classes[alpha ? 'alpha' : 'beta']}
|
||||
style={{ fontSize: '120%' }}
|
||||
>
|
||||
{alpha ? <>α</> : <>β</>}
|
||||
</span>
|
||||
</Typography>
|
||||
) : (
|
||||
<span className={classes[alpha ? 'alpha' : 'beta']}>
|
||||
<Typography component="span" className={classes[alpha ? 'alpha' : 'beta']}>
|
||||
{alpha ? 'Alpha' : 'Beta'}
|
||||
</span>
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,21 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { configApiRef, useAnalytics, useApi } from '@backstage/core-plugin-api';
|
||||
import classnames from 'classnames';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import MaterialLink, {
|
||||
LinkProps as MaterialLinkProps,
|
||||
} from '@material-ui/core/Link';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import classnames from 'classnames';
|
||||
import { trimEnd } from 'lodash';
|
||||
import React, { ElementType } from 'react';
|
||||
import {
|
||||
createRoutesFromChildren,
|
||||
Link as RouterLink,
|
||||
LinkProps as RouterLinkProps,
|
||||
Route,
|
||||
} from 'react-router-dom';
|
||||
import { trimEnd } from 'lodash';
|
||||
import { createRoutesFromChildren, Route } from 'react-router-dom';
|
||||
|
||||
export function isReactRouterBeta(): boolean {
|
||||
const [obj] = createRoutesFromChildren(<Route index element={<div />} />);
|
||||
@@ -161,7 +162,9 @@ export const Link = React.forwardRef<any, LinkProps>(
|
||||
className={classnames(classes.externalLink, props.className)}
|
||||
>
|
||||
{props.children}
|
||||
<span className={classes.visuallyHidden}>, Opens in a new window</span>
|
||||
<Typography component="span" className={classes.visuallyHidden}>
|
||||
, Opens in a new window
|
||||
</Typography>
|
||||
</MaterialLink>
|
||||
) : (
|
||||
// Interact with React Router for internal links
|
||||
|
||||
@@ -13,18 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import CopyIcon from '@material-ui/icons/FileCopy';
|
||||
import classnames from 'classnames';
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
|
||||
import { AnsiProcessor } from './AnsiProcessor';
|
||||
import { HEADER_SIZE, useStyles } from './styles';
|
||||
import classnames from 'classnames';
|
||||
import { LogLine } from './LogLine';
|
||||
import { LogViewerControls } from './LogViewerControls';
|
||||
import { HEADER_SIZE, useStyles } from './styles';
|
||||
import { useLogViewerSearch } from './useLogViewerSearch';
|
||||
import { useLogViewerSelection } from './useLogViewerSelection';
|
||||
|
||||
@@ -69,10 +70,10 @@ export function RealLogViewer(props: RealLogViewerProps) {
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<div style={{ width, height }} className={classes.root}>
|
||||
<div className={classes.header}>
|
||||
<Box style={{ width, height }} className={classes.root}>
|
||||
<Box className={classes.header}>
|
||||
<LogViewerControls {...search} />
|
||||
</div>
|
||||
</Box>
|
||||
<FixedSizeList
|
||||
ref={listRef}
|
||||
className={classes.log}
|
||||
@@ -86,7 +87,7 @@ export function RealLogViewer(props: RealLogViewerProps) {
|
||||
const line = data[index];
|
||||
const { lineNumber } = line;
|
||||
return (
|
||||
<div
|
||||
<Box
|
||||
style={{ ...style }}
|
||||
className={classnames(classes.line, {
|
||||
[classes.lineSelected]: selection.isSelected(lineNumber),
|
||||
@@ -122,11 +123,11 @@ export function RealLogViewer(props: RealLogViewerProps) {
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}}
|
||||
</FixedSizeList>
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
|
||||
@@ -13,23 +13,29 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect, PropsWithChildren } from 'react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import LinearProgress, {
|
||||
LinearProgressProps,
|
||||
} from '@material-ui/core/LinearProgress';
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
import React, { PropsWithChildren, useEffect, useState } from 'react';
|
||||
|
||||
export function Progress(props: PropsWithChildren<LinearProgressProps>) {
|
||||
const theme = useTheme<BackstageTheme>();
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handle = setTimeout(() => setIsVisible(true), 250);
|
||||
const handle = setTimeout(
|
||||
() => setIsVisible(true),
|
||||
theme.transitions.duration.short,
|
||||
);
|
||||
return () => clearTimeout(handle);
|
||||
}, []);
|
||||
}, [theme.transitions.duration.short]);
|
||||
|
||||
return isVisible ? (
|
||||
<LinearProgress {...props} data-testid="progress" />
|
||||
) : (
|
||||
<div style={{ display: 'none' }} />
|
||||
<Box display="none" />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { BackstagePalette, BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles, useTheme } from '@material-ui/core/styles';
|
||||
import { Circle } from 'rc-progress';
|
||||
import React, { ReactNode, useEffect, useState } from 'react';
|
||||
import Box from '@material-ui/core/Box';
|
||||
|
||||
/** @public */
|
||||
export type GaugeClassKey =
|
||||
@@ -38,8 +39,8 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -60%)',
|
||||
fontSize: 45,
|
||||
fontWeight: 'bold',
|
||||
fontSize: theme.typography.pxToRem(45),
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
color: theme.palette.textContrast,
|
||||
},
|
||||
description: {
|
||||
@@ -152,7 +153,7 @@ export function Gauge(props: GaugeProps) {
|
||||
}, [description, hoverRef]);
|
||||
|
||||
return (
|
||||
<div ref={setHoverRef} className={classes.root}>
|
||||
<Box {...{ ref: setHoverRef }} className={classes.root}>
|
||||
<Circle
|
||||
strokeLinecap="butt"
|
||||
percent={asPercentage}
|
||||
@@ -162,12 +163,12 @@ export function Gauge(props: GaugeProps) {
|
||||
className={classes.circle}
|
||||
/>
|
||||
{description && isHovering ? (
|
||||
<div className={classes.description}>{description}</div>
|
||||
<Box className={classes.description}>{description}</Box>
|
||||
) : (
|
||||
<div className={classes.overlay}>
|
||||
<Box className={classes.overlay}>
|
||||
{isNaN(value) ? 'N/A' : `${asActual}${unit}`}
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
import { BottomLinkProps } from '../../layout/BottomLink';
|
||||
import { InfoCard, InfoCardVariants } from '../../layout/InfoCard';
|
||||
import { Gauge, GaugePropsGetColor } from './Gauge';
|
||||
@@ -74,7 +75,7 @@ export function GaugeCard(props: Props) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Box className={classes.root}>
|
||||
<InfoCard
|
||||
title={title}
|
||||
subheader={subheader}
|
||||
@@ -84,6 +85,6 @@ export function GaugeCard(props: Props) {
|
||||
>
|
||||
<Gauge {...gaugeProps} />
|
||||
</InfoCard>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Line } from 'rc-progress';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { getProgressColor, GaugePropsGetColor } from './Gauge';
|
||||
import React from 'react';
|
||||
|
||||
import { GaugePropsGetColor, getProgressColor } from './Gauge';
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
@@ -47,14 +48,14 @@ export function LinearGauge(props: Props) {
|
||||
});
|
||||
return (
|
||||
<Tooltip title={`${percent}%`}>
|
||||
<span>
|
||||
<Typography component="span">
|
||||
<Line
|
||||
percent={percent}
|
||||
strokeWidth={4}
|
||||
trailWidth={4}
|
||||
strokeColor={strokeColor}
|
||||
/>
|
||||
</span>
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Checkbox from '@material-ui/core/Checkbox';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
} from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import ClosedDropdown from './static/ClosedDropdown';
|
||||
import OpenedDropdown from './static/OpenedDropdown';
|
||||
|
||||
@@ -45,17 +46,17 @@ const BootstrapInput = withStyles(
|
||||
},
|
||||
},
|
||||
input: {
|
||||
borderRadius: 4,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
position: 'relative',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: '1px solid #ced4da',
|
||||
fontSize: 16,
|
||||
padding: '10px 26px 10px 12px',
|
||||
fontSize: theme.typography.body1.fontSize,
|
||||
padding: theme.spacing(1.25, 3.25, 1.25, 1.5),
|
||||
transition: theme.transitions.create(['border-color', 'box-shadow']),
|
||||
fontFamily: 'Helvetica Neue',
|
||||
'&:focus': {
|
||||
background: theme.palette.background.paper,
|
||||
borderRadius: 4,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -81,7 +82,7 @@ const useStyles = makeStyles(
|
||||
label: {
|
||||
transform: 'initial',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 14,
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
color: theme.palette.text.primary,
|
||||
'&.Mui-focused': {
|
||||
@@ -91,7 +92,7 @@ const useStyles = makeStyles(
|
||||
formLabel: {
|
||||
transform: 'initial',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 14,
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
color: theme.palette.text.primary,
|
||||
'&.Mui-focused': {
|
||||
@@ -196,7 +197,7 @@ export function SelectComponent(props: SelectProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Box className={classes.root}>
|
||||
<ClickAwayListener onClickAway={handleClickAway}>
|
||||
<FormControl className={classes.formControl}>
|
||||
<InputLabel className={classes.formLabel}>{label}</InputLabel>
|
||||
@@ -217,7 +218,7 @@ export function SelectComponent(props: SelectProps) {
|
||||
tabIndex={0}
|
||||
renderValue={s =>
|
||||
multiple && (value as any[]).length !== 0 ? (
|
||||
<div className={classes.chips}>
|
||||
<Box className={classes.chips}>
|
||||
{(s as string[]).map(selectedValue => (
|
||||
<Chip
|
||||
key={items.find(el => el.value === selectedValue)?.value}
|
||||
@@ -229,7 +230,7 @@ export function SelectComponent(props: SelectProps) {
|
||||
className={classes.chip}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Box>
|
||||
) : (
|
||||
<Typography>
|
||||
{(value as any[]).length === 0
|
||||
@@ -279,6 +280,6 @@ export function SelectComponent(props: SelectProps) {
|
||||
</Select>
|
||||
</FormControl>
|
||||
</ClickAwayListener>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import SvgIcon from '@material-ui/core/SvgIcon';
|
||||
export type ClosedDropdownClassKey = 'icon';
|
||||
|
||||
const useStyles = makeStyles(
|
||||
() =>
|
||||
theme =>
|
||||
createStyles({
|
||||
icon: {
|
||||
position: 'absolute',
|
||||
right: '4px',
|
||||
right: theme.spacing(0.5),
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -20,11 +20,11 @@ import SvgIcon from '@material-ui/core/SvgIcon';
|
||||
export type OpenedDropdownClassKey = 'icon';
|
||||
|
||||
const useStyles = makeStyles(
|
||||
() =>
|
||||
theme =>
|
||||
createStyles({
|
||||
icon: {
|
||||
position: 'absolute',
|
||||
right: '4px',
|
||||
right: theme.spacing(0.5),
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { useContext, ReactNode, PropsWithChildren } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { StepActions } from './types';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { PropsWithChildren, ReactNode, useContext } from 'react';
|
||||
|
||||
import { VerticalStepperContext } from './SimpleStepper';
|
||||
import { StepActions } from './types';
|
||||
|
||||
export type SimpleStepperFooterClassKey = 'root';
|
||||
|
||||
@@ -145,7 +147,7 @@ export const SimpleStepperFooter = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Box className={classes.root}>
|
||||
{[undefined, true].includes(actions.showBack) && stepIndex !== 0 && (
|
||||
<BackBtn
|
||||
text={actions.backText}
|
||||
@@ -184,6 +186,6 @@ export const SimpleStepperFooter = ({
|
||||
/>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import MuiStep from '@material-ui/core/Step';
|
||||
import StepContent from '@material-ui/core/StepContent';
|
||||
import StepLabel from '@material-ui/core/StepLabel';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import { SimpleStepperFooter } from './SimpleStepperFooter';
|
||||
import { StepProps } from './types';
|
||||
|
||||
@@ -40,11 +42,11 @@ export function SimpleStepperStep(props: PropsWithChildren<StepProps>) {
|
||||
// The end step is not a part of the stepper
|
||||
// It simply is the final screen with an option to have buttons such as reset or back
|
||||
return end ? (
|
||||
<div className={classes.end}>
|
||||
<Box className={classes.end}>
|
||||
<Typography variant="h6">{title}</Typography>
|
||||
{children}
|
||||
<SimpleStepperFooter actions={{ ...(actions || {}), showNext: false }} />
|
||||
</div>
|
||||
</Box>
|
||||
) : (
|
||||
<MuiStep {...muiProps}>
|
||||
<StepLabel>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import classNames from 'classnames';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
@@ -31,12 +31,12 @@ export type StatusClassKey =
|
||||
const useStyles = makeStyles<BackstageTheme>(
|
||||
theme => ({
|
||||
status: {
|
||||
fontWeight: 500,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
'&::before': {
|
||||
width: '0.7em',
|
||||
height: '0.7em',
|
||||
display: 'inline-block',
|
||||
marginRight: 8,
|
||||
marginRight: theme.spacing(1),
|
||||
borderRadius: '50%',
|
||||
content: '""',
|
||||
},
|
||||
@@ -78,7 +78,8 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
export function StatusOK(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.ok)}
|
||||
aria-label="Status ok"
|
||||
aria-hidden="true"
|
||||
@@ -90,7 +91,8 @@ export function StatusOK(props: PropsWithChildren<{}>) {
|
||||
export function StatusWarning(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.warning)}
|
||||
aria-label="Status warning"
|
||||
aria-hidden="true"
|
||||
@@ -102,7 +104,8 @@ export function StatusWarning(props: PropsWithChildren<{}>) {
|
||||
export function StatusError(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.error)}
|
||||
aria-label="Status error"
|
||||
aria-hidden="true"
|
||||
@@ -114,7 +117,8 @@ export function StatusError(props: PropsWithChildren<{}>) {
|
||||
export function StatusPending(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.pending)}
|
||||
aria-label="Status pending"
|
||||
aria-hidden="true"
|
||||
@@ -126,7 +130,8 @@ export function StatusPending(props: PropsWithChildren<{}>) {
|
||||
export function StatusRunning(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.running)}
|
||||
aria-label="Status running"
|
||||
aria-hidden="true"
|
||||
@@ -138,7 +143,8 @@ export function StatusRunning(props: PropsWithChildren<{}>) {
|
||||
export function StatusAborted(props: PropsWithChildren<{}>) {
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<span
|
||||
<Typography
|
||||
component="span"
|
||||
className={classNames(classes.status, classes.aborted)}
|
||||
aria-label="Status aborted"
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -13,25 +13,26 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import {
|
||||
withStyles,
|
||||
createStyles,
|
||||
WithStyles,
|
||||
Theme,
|
||||
WithStyles,
|
||||
withStyles,
|
||||
} from '@material-ui/core/styles';
|
||||
import Table from '@material-ui/core/Table';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableCell from '@material-ui/core/TableCell';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import React from 'react';
|
||||
|
||||
export type MetadataTableTitleCellClassKey = 'root';
|
||||
|
||||
const tableTitleCellStyles = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
fontWeight: 'bolder',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
whiteSpace: 'nowrap',
|
||||
paddingRight: theme.spacing(4),
|
||||
border: '0',
|
||||
@@ -53,9 +54,7 @@ export type MetadataTableListClassKey = 'root';
|
||||
const listStyles = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
listStyle: 'none',
|
||||
margin: theme.spacing(0, 0, -1, 0),
|
||||
padding: '0',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -111,11 +110,13 @@ interface StyleProps extends WithStyles {
|
||||
export const MetadataList = withStyles(listStyles, {
|
||||
name: 'BackstageMetadataTableList',
|
||||
})(({ classes, children }: StyleProps) => (
|
||||
<ul className={classes.root}>{children}</ul>
|
||||
<List disablePadding className={classes.root}>
|
||||
{children}
|
||||
</List>
|
||||
));
|
||||
|
||||
export const MetadataListItem = withStyles(listItemStyles, {
|
||||
name: 'BackstageMetadataTableListItem',
|
||||
})(({ classes, children }: StyleProps) => (
|
||||
<li className={classes.root}>{children}</li>
|
||||
<ListItem className={classes.root}>{children}</ListItem>
|
||||
));
|
||||
|
||||
+9
-2
@@ -22,6 +22,7 @@ import {
|
||||
Theme,
|
||||
} from '@material-ui/core/styles';
|
||||
import startCase from 'lodash/startCase';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import {
|
||||
MetadataTable,
|
||||
@@ -88,7 +89,9 @@ function renderMap(
|
||||
: startCase(key);
|
||||
return (
|
||||
<MetadataListItem key={key}>
|
||||
{`${fmtKey}: `}
|
||||
<Typography variant="body2" component="span">
|
||||
{`${fmtKey}: `}
|
||||
</Typography>
|
||||
{value}
|
||||
</MetadataListItem>
|
||||
);
|
||||
@@ -122,7 +125,11 @@ function toValue(
|
||||
return <Fragment>{value ? '✅' : '❌'}</Fragment>;
|
||||
}
|
||||
|
||||
return <Fragment>{value}</Fragment>;
|
||||
return (
|
||||
<Typography variant="body2" component="span">
|
||||
{value}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
const ItemValue = ({ value, options }: { value: any; options: any }) => (
|
||||
<Fragment>{toValue(value, options)}</Fragment>
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { Select } from '../Select';
|
||||
import { SelectProps } from '../Select/Select';
|
||||
|
||||
@@ -39,7 +40,7 @@ const useFilterStyles = makeStyles<BackstageTheme>(
|
||||
header: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
height: '60px',
|
||||
height: theme.spacing(7.5),
|
||||
justifyContent: 'space-between',
|
||||
borderBottom: `1px solid ${theme.palette.grey[500]}`,
|
||||
},
|
||||
@@ -93,14 +94,14 @@ export const Filters = (props: Props) => {
|
||||
|
||||
// As material table doesn't provide a way to add a column filter tab we will make our own filter logic
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.value}>Filters</div>
|
||||
<Box className={classes.root}>
|
||||
<Box className={classes.header}>
|
||||
<Box className={classes.value}>Filters</Box>
|
||||
<Button color="primary" onClick={handleClick}>
|
||||
Clear all
|
||||
</Button>
|
||||
</div>
|
||||
<div className={classes.filters}>
|
||||
</Box>
|
||||
<Box className={classes.filters}>
|
||||
{props.filters?.length &&
|
||||
props.filters.map(filter => (
|
||||
<Select
|
||||
@@ -116,7 +117,7 @@ export const Filters = (props: Props) => {
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
|
||||
export type SubvalueCellClassKey = 'value' | 'subvalue';
|
||||
|
||||
const useSubvalueCellStyles = makeStyles<BackstageTheme>(
|
||||
theme => ({
|
||||
value: {
|
||||
marginBottom: '6px',
|
||||
marginBottom: theme.spacing(0.75),
|
||||
},
|
||||
subvalue: {
|
||||
color: theme.palette.textSubtle,
|
||||
@@ -44,8 +44,8 @@ export function SubvalueCell(props: SubvalueCellProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.value}>{value}</div>
|
||||
<div className={classes.subvalue}>{subvalue}</div>
|
||||
<Box className={classes.value}>{value}</Box>
|
||||
<Box className={classes.subvalue}>{subvalue}</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles, useTheme, withStyles } from '@material-ui/core/styles';
|
||||
import MTable, {
|
||||
Column,
|
||||
Icons,
|
||||
MaterialTableProps,
|
||||
MTableBody,
|
||||
MTableHeader,
|
||||
MTableToolbar,
|
||||
Options,
|
||||
} from '@material-table/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles, useTheme, withStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
// Material-table is not using the standard icons available in in material-ui. https://github.com/mbrn/material-table/issues/51
|
||||
import AddBox from '@material-ui/icons/AddBox';
|
||||
import ArrowUpward from '@material-ui/icons/ArrowUpward';
|
||||
import Check from '@material-ui/icons/Check';
|
||||
@@ -34,15 +42,6 @@ import Remove from '@material-ui/icons/Remove';
|
||||
import SaveAlt from '@material-ui/icons/SaveAlt';
|
||||
import ViewColumn from '@material-ui/icons/ViewColumn';
|
||||
import { isEqual, transform } from 'lodash';
|
||||
import MTable, {
|
||||
Column,
|
||||
Icons,
|
||||
MaterialTableProps,
|
||||
MTableBody,
|
||||
MTableHeader,
|
||||
MTableToolbar,
|
||||
Options,
|
||||
} from '@material-table/core';
|
||||
import React, {
|
||||
forwardRef,
|
||||
MutableRefObject,
|
||||
@@ -51,9 +50,11 @@ import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { SelectProps } from '../Select/Select';
|
||||
import { Filter, Filters, SelectedFilters, Without } from './Filters';
|
||||
|
||||
// Material-table is not using the standard icons available in in material-ui. https://github.com/mbrn/material-table/issues/51
|
||||
const tableIcons: Icons = {
|
||||
Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
|
||||
Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
|
||||
@@ -122,7 +123,7 @@ const StyledMTableToolbar = withStyles(
|
||||
},
|
||||
title: {
|
||||
'& > h6': {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
},
|
||||
},
|
||||
searchField: {
|
||||
@@ -136,14 +137,14 @@ const StyledMTableToolbar = withStyles(
|
||||
export type FiltersContainerClassKey = 'root' | 'title';
|
||||
|
||||
const useFilterStyles = makeStyles<BackstageTheme>(
|
||||
() => ({
|
||||
theme => ({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
title: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
fontSize: 18,
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
@@ -265,21 +266,21 @@ export function TableToolbar(toolbarProps: {
|
||||
|
||||
if (hasFilters) {
|
||||
return (
|
||||
<div className={filtersClasses.root}>
|
||||
<div className={filtersClasses.root}>
|
||||
<Box className={filtersClasses.root}>
|
||||
<Box className={filtersClasses.root}>
|
||||
<IconButton onClick={toggleFilters} aria-label="filter list">
|
||||
<FilterList />
|
||||
</IconButton>
|
||||
<Typography className={filtersClasses.title}>
|
||||
Filters ({selectedFiltersLength})
|
||||
</Typography>
|
||||
</div>
|
||||
</Box>
|
||||
<StyledMTableToolbar
|
||||
{...toolbarProps}
|
||||
ref={toolbarRef}
|
||||
onSearchChanged={onSearchChanged}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -484,7 +485,7 @@ export function Table<T extends object = {}>(props: TableProps<T>) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={tableClasses.root}>
|
||||
<Box className={tableClasses.root}>
|
||||
{filtersOpen && data && typeof data !== 'function' && filters?.length && (
|
||||
<Filters
|
||||
filters={constructFilters(filters, data as any[])}
|
||||
@@ -521,7 +522,7 @@ export function Table<T extends object = {}>(props: TableProps<T>) {
|
||||
}}
|
||||
{...restProps}
|
||||
/>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: theme.palette.tabbar.indicator,
|
||||
height: '4px',
|
||||
height: theme.spacing(0.5),
|
||||
},
|
||||
flexContainer: {
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -29,16 +29,16 @@ interface StyledIconProps {
|
||||
export type TabIconClassKey = 'root';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme, StyledIconProps>(
|
||||
() => ({
|
||||
theme => ({
|
||||
root: {
|
||||
color: '#6E6E6E',
|
||||
overflow: 'visible',
|
||||
fontSize: '1.5rem',
|
||||
fontSize: theme.typography.h5.fontSize,
|
||||
textAlign: 'center',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: '#E6E6E6',
|
||||
marginLeft: props => (props.isNext ? 'auto' : '0'),
|
||||
marginRight: props => (props.isNext ? '0' : '10px'),
|
||||
marginRight: props => (props.isNext ? '0' : theme.spacing(1.25)),
|
||||
'&:hover': {
|
||||
backgroundColor: '#E6E6E6',
|
||||
opacity: '1',
|
||||
|
||||
@@ -13,9 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
export interface TabPanelProps {
|
||||
value?: any;
|
||||
@@ -26,13 +25,13 @@ export const TabPanel = (props: PropsWithChildren<TabPanelProps>) => {
|
||||
const { children, value, index, ...other } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
<Box
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
aria-labelledby={`scrollable-auto-tab-${index}`}
|
||||
{...other}
|
||||
>
|
||||
{value === index && <Box p={3}>{children}</Box>}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@ import { TabPanel } from './TabPanel';
|
||||
import { StyledIcon } from './TabIcon';
|
||||
import { StyledTab } from './Tab';
|
||||
import { StyledTabs } from './TabBar';
|
||||
import Box from '@material-ui/core/Box';
|
||||
|
||||
/* Props Types */
|
||||
|
||||
@@ -56,8 +57,8 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
appbar: {
|
||||
boxShadow: 'none',
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
paddingLeft: '10px',
|
||||
paddingRight: '10px',
|
||||
paddingLeft: theme.spacing(1.25),
|
||||
paddingRight: theme.spacing(1.25),
|
||||
},
|
||||
}),
|
||||
{ name: 'BackstageTabs' },
|
||||
@@ -110,9 +111,9 @@ export function Tabs(props: TabsProps) {
|
||||
const currentIndex = navIndex === value[0] ? value[1] : false;
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Box className={classes.root}>
|
||||
<AppBar ref={wrapper} className={classes.appbar} position="static">
|
||||
<div>
|
||||
<Box>
|
||||
<StyledTabs
|
||||
value={currentIndex}
|
||||
onChange={handleChange}
|
||||
@@ -146,7 +147,7 @@ export function Tabs(props: TabsProps) {
|
||||
</StyledIcon>
|
||||
)}
|
||||
</StyledTabs>
|
||||
</div>
|
||||
</Box>
|
||||
</AppBar>
|
||||
{currentIndex !== false ? (
|
||||
chunkedTabs[navIndex].map((tab, index) => (
|
||||
@@ -164,6 +165,6 @@ export function Tabs(props: TabsProps) {
|
||||
{chunkedTabs[value[0]][value[1]].content}
|
||||
</TabPanel>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
severity as NonNullable<WarningProps['severity']>,
|
||||
theme,
|
||||
),
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
},
|
||||
message: {
|
||||
width: '100%',
|
||||
|
||||
@@ -61,7 +61,7 @@ export function BottomLink(props: BottomLinkProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Box>
|
||||
<Divider />
|
||||
<Link to={link} onClick={onClick} underline="none">
|
||||
<Box display="flex" alignItems="center" className={classes.root}>
|
||||
@@ -73,6 +73,6 @@ export function BottomLink(props: BottomLinkProps) {
|
||||
<ArrowIcon className={classes.arrow} />
|
||||
</Box>
|
||||
</Link>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO favoriteable capability
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { PropsWithChildren, ReactNode } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
|
||||
/**
|
||||
* TODO: favoriteable capability
|
||||
*/
|
||||
|
||||
/** @public */
|
||||
export type ContentHeaderClassKey =
|
||||
| 'container'
|
||||
@@ -120,17 +120,17 @@ export function ContentHeader(props: PropsWithChildren<ContentHeaderProps>) {
|
||||
return (
|
||||
<>
|
||||
<Helmet title={title} />
|
||||
<div className={classes.container}>
|
||||
<div className={classes.leftItemsBox}>
|
||||
<Box className={classes.container}>
|
||||
<Box className={classes.leftItemsBox}>
|
||||
{renderedTitle}
|
||||
{description && (
|
||||
<Typography className={classes.description} variant="body2">
|
||||
{description}
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
<div className={classes.rightItemsBox}>{children}</div>
|
||||
</div>
|
||||
</Box>
|
||||
<Box className={classes.rightItemsBox}>{children}</Box>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React, { ComponentClass, Component, ErrorInfo } from 'react';
|
||||
import { Button } from '../../components/Button';
|
||||
import { ErrorPanel } from '../../components/ErrorPanel';
|
||||
@@ -40,9 +41,11 @@ const SlackLink = (props: { slackChannel?: string | SlackChannel }) => {
|
||||
if (!slackChannel) {
|
||||
return null;
|
||||
} else if (typeof slackChannel === 'string') {
|
||||
return <>Please contact {slackChannel} for help.</>;
|
||||
return <Typography>Please contact {slackChannel} for help.</Typography>;
|
||||
} else if (!slackChannel.href) {
|
||||
return <>Please contact {slackChannel.name} for help.</>;
|
||||
return (
|
||||
<Typography>Please contact {slackChannel.name} for help.</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -46,7 +46,7 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
paddingBottom: theme.spacing(5),
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
paddingBottom: theme.spacing(4),
|
||||
fontSize: 32,
|
||||
fontSize: theme.typography.h3.fontSize,
|
||||
},
|
||||
},
|
||||
subtitle: {
|
||||
|
||||
@@ -44,7 +44,7 @@ const ActionItem = ({
|
||||
onClick,
|
||||
}: HeaderActionMenuItem) => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Fragment>
|
||||
<ListItem
|
||||
data-testid="header-action-item"
|
||||
disabled={disabled}
|
||||
@@ -58,7 +58,7 @@ const ActionItem = ({
|
||||
{icon && <ListItemIcon>{icon}</ListItemIcon>}
|
||||
<ListItemText primary={label} secondary={secondaryLabel} />
|
||||
</ListItem>
|
||||
</React.Fragment>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ const useStyles = makeStyles(
|
||||
},
|
||||
label: {
|
||||
color: theme.palette.common.white,
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
letterSpacing: 0,
|
||||
fontSize: theme.typography.fontSize,
|
||||
marginBottom: theme.spacing(1) / 2,
|
||||
@@ -77,10 +77,10 @@ export function HeaderLabel(props: HeaderLabelProps) {
|
||||
);
|
||||
return (
|
||||
<Grid item>
|
||||
<span className={classes.root}>
|
||||
<Typography component="span" className={classes.root}>
|
||||
<Typography className={classes.label}>{label}</Typography>
|
||||
{url ? <Link to={url}>{content}</Link> : content}
|
||||
</span>
|
||||
</Typography>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO(blam): Remove this implementation when the Tabs are ready
|
||||
// This is just a temporary solution to implementing tabs for now
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import TabUI, { TabProps } from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
// TODO(blam): Remove this implementation when the Tabs are ready
|
||||
// This is just a temporary solution to implementing tabs for now
|
||||
|
||||
/** @public */
|
||||
export type HeaderTabsClassKey =
|
||||
| 'tabsWrapper'
|
||||
@@ -38,10 +38,10 @@ const useStyles = makeStyles(
|
||||
minWidth: 0,
|
||||
},
|
||||
defaultTab: {
|
||||
padding: theme.spacing(3, 3),
|
||||
...theme.typography.caption,
|
||||
padding: theme.spacing(3, 3),
|
||||
textTransform: 'uppercase',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
selected: {
|
||||
@@ -97,7 +97,7 @@ export function HeaderTabs(props: HeaderTabsProps) {
|
||||
}, [selectedIndex]);
|
||||
|
||||
return (
|
||||
<div className={styles.tabsWrapper}>
|
||||
<Box className={styles.tabsWrapper}>
|
||||
<Tabs
|
||||
selectionFollowsFocus
|
||||
indicatorColor="primary"
|
||||
@@ -120,6 +120,6 @@ export function HeaderTabs(props: HeaderTabsProps) {
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ const useStyles = makeStyles(
|
||||
padding: theme.spacing(2, 2, 2, 2.5),
|
||||
},
|
||||
headerTitle: {
|
||||
fontWeight: 700,
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
},
|
||||
headerSubheader: {
|
||||
paddingTop: theme.spacing(1),
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import {
|
||||
createStyles,
|
||||
makeStyles,
|
||||
@@ -65,8 +65,8 @@ export function ItemCardGrid(props: ItemCardGridProps) {
|
||||
const { children, ...otherProps } = props;
|
||||
const classes = useStyles(otherProps);
|
||||
return (
|
||||
<div className={classes.root} {...otherProps}>
|
||||
<Box className={classes.root} {...otherProps}>
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { createStyles, makeStyles, WithStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import React from 'react';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
/** @public */
|
||||
export type ItemCardHeaderClassKey = 'root';
|
||||
@@ -77,7 +77,7 @@ export function ItemCardHeader(props: ItemCardHeaderProps) {
|
||||
const { title, subtitle, children } = props;
|
||||
const classes = useStyles(props);
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Box className={classes.root}>
|
||||
{subtitle && (
|
||||
<Typography variant="subtitle2" component="h3">
|
||||
{subtitle}
|
||||
@@ -89,6 +89,6 @@ export function ItemCardHeader(props: ItemCardHeaderProps) {
|
||||
</Typography>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,28 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import React, { useState, useContext, useRef } from 'react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import React, { useContext, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
makeSidebarConfig,
|
||||
makeSidebarSubmenuConfig,
|
||||
SidebarConfig,
|
||||
SidebarConfigContext,
|
||||
SubmenuConfig,
|
||||
SidebarOptions,
|
||||
SubmenuConfig,
|
||||
SubmenuOptions,
|
||||
} from './config';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { MobileSidebar } from './MobileSidebar';
|
||||
import { useContent } from './Page';
|
||||
import { SidebarOpenStateProvider } from './SidebarOpenStateContext';
|
||||
import { useSidebarPinState } from './SidebarPinStateContext';
|
||||
import { MobileSidebar } from './MobileSidebar';
|
||||
|
||||
/** @public */
|
||||
export type SidebarClassKey = 'drawer' | 'drawerOpen';
|
||||
@@ -191,7 +190,7 @@ const DesktopSidebar = (props: DesktopSidebarProps) => {
|
||||
<nav style={{}} aria-label="sidebar nav">
|
||||
<A11ySkipSidebar />
|
||||
<SidebarOpenStateProvider value={{ isOpen, setOpen }}>
|
||||
<div
|
||||
<Box
|
||||
className={classes.root}
|
||||
data-testid="sidebar-root"
|
||||
onMouseEnter={disableExpandOnHover ? () => {} : handleOpen}
|
||||
@@ -199,14 +198,14 @@ const DesktopSidebar = (props: DesktopSidebarProps) => {
|
||||
onMouseLeave={disableExpandOnHover ? () => {} : handleClose}
|
||||
onBlur={disableExpandOnHover ? () => {} : handleClose}
|
||||
>
|
||||
<div
|
||||
<Box
|
||||
className={classnames(classes.drawer, {
|
||||
[classes.drawerOpen]: isOpen,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
</SidebarOpenStateProvider>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@@ -13,19 +13,20 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Collapse from '@material-ui/core/Collapse';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import CloseIcon from '@material-ui/icons/Close';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useLocalStorageValue } from '@react-hookz/web';
|
||||
import React, { useContext, useState } from 'react';
|
||||
|
||||
import {
|
||||
SidebarConfigContext,
|
||||
SidebarConfig,
|
||||
SIDEBAR_INTRO_LOCAL_STORAGE,
|
||||
SidebarConfig,
|
||||
SidebarConfigContext,
|
||||
} from './config';
|
||||
import { SidebarDivider } from './Items';
|
||||
import { useSidebarOpenState } from './SidebarOpenStateContext';
|
||||
@@ -45,8 +46,8 @@ const useStyles = makeStyles<BackstageTheme, { sidebarConfig: SidebarConfig }>(
|
||||
// XXX (@koroeskohr): should I be using a Mui theme variable?
|
||||
fontSize: 12,
|
||||
width: props.sidebarConfig.drawerWidthOpen,
|
||||
marginTop: 18,
|
||||
marginBottom: 12,
|
||||
marginTop: theme.spacing(2.25),
|
||||
marginBottom: theme.spacing(1.5),
|
||||
paddingLeft: props.sidebarConfig.iconPadding,
|
||||
paddingRight: props.sidebarConfig.iconPadding,
|
||||
}),
|
||||
@@ -54,13 +55,13 @@ const useStyles = makeStyles<BackstageTheme, { sidebarConfig: SidebarConfig }>(
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
marginTop: 12,
|
||||
marginTop: theme.spacing(1.5),
|
||||
},
|
||||
introDismissLink: {
|
||||
color: '#dddddd',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginBottom: 4,
|
||||
marginBottom: theme.spacing(0.5),
|
||||
'&:hover': {
|
||||
color: theme.palette.linkHover,
|
||||
transition: theme.transitions.create('color', {
|
||||
@@ -78,7 +79,7 @@ const useStyles = makeStyles<BackstageTheme, { sidebarConfig: SidebarConfig }>(
|
||||
introDismissIcon: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
marginRight: 12,
|
||||
marginRight: theme.spacing(1.5),
|
||||
},
|
||||
}),
|
||||
{ name: 'BackstageSidebarIntro' },
|
||||
@@ -103,17 +104,17 @@ export function IntroCard(props: IntroCardProps) {
|
||||
const handleClose = () => onClose();
|
||||
|
||||
return (
|
||||
<div className={classes.introCard}>
|
||||
<Box className={classes.introCard}>
|
||||
<Typography variant="subtitle2">{text}</Typography>
|
||||
<div className={classes.introDismiss}>
|
||||
<Box className={classes.introDismiss}>
|
||||
<IconButton onClick={handleClose} className={classes.introDismissLink}>
|
||||
<CloseIcon className={classes.introDismissIcon} />
|
||||
<Typography component="span" className={classes.introDismissText}>
|
||||
Dismiss
|
||||
</Typography>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,23 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { IconComponent, useElementFilter } from '@backstage/core-plugin-api';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import { makeStyles, styled, Theme } from '@material-ui/core/styles';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import Badge from '@material-ui/core/Badge';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles, styled, Theme } from '@material-ui/core/styles';
|
||||
import {
|
||||
CreateCSSProperties,
|
||||
StyledComponentProps,
|
||||
} from '@material-ui/core/styles/withStyles';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
|
||||
import ArrowDropUp from '@material-ui/icons/ArrowDropUp';
|
||||
import ArrowRightIcon from '@material-ui/icons/ArrowRight';
|
||||
import SearchIcon from '@material-ui/icons/Search';
|
||||
import ArrowDropUp from '@material-ui/icons/ArrowDropUp';
|
||||
import ArrowDropDown from '@material-ui/icons/ArrowDropDown';
|
||||
import classnames from 'classnames';
|
||||
import { Location } from 'history';
|
||||
import React, {
|
||||
ComponentProps,
|
||||
ComponentType,
|
||||
@@ -48,18 +49,18 @@ import {
|
||||
useLocation,
|
||||
useResolvedPath,
|
||||
} from 'react-router-dom';
|
||||
|
||||
import {
|
||||
SidebarConfig,
|
||||
SidebarConfigContext,
|
||||
SidebarItemWithSubmenuContext,
|
||||
SidebarConfig,
|
||||
} from './config';
|
||||
import { SidebarSubmenuProps, SidebarSubmenu } from './SidebarSubmenu';
|
||||
import DoubleArrowLeft from './icons/DoubleArrowLeft';
|
||||
import DoubleArrowRight from './icons/DoubleArrowRight';
|
||||
import { isLocationMatch } from './utils';
|
||||
import { Location } from 'history';
|
||||
import { useSidebarOpenState } from './SidebarOpenStateContext';
|
||||
import { SidebarSubmenu, SidebarSubmenuProps } from './SidebarSubmenu';
|
||||
import { SidebarSubmenuItemProps } from './SidebarSubmenuItem';
|
||||
import { isLocationMatch } from './utils';
|
||||
|
||||
/** @public */
|
||||
export type SidebarItemClassKey =
|
||||
@@ -145,7 +146,7 @@ const makeSidebarStyles = (sidebarConfig: SidebarConfig) =>
|
||||
},
|
||||
searchField: {
|
||||
color: '#b5b5b5',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
fontSize: theme.typography.fontSize,
|
||||
},
|
||||
searchFieldHTMLInput: {
|
||||
@@ -373,10 +374,10 @@ const SidebarItemBase = forwardRef<any, SidebarItemProps>((props, ref) => {
|
||||
!isOpen && hasSubmenu ? { display: 'flex', marginLeft: '24px' } : {};
|
||||
|
||||
const displayItemIcon = (
|
||||
<div style={divStyle}>
|
||||
<Box style={divStyle}>
|
||||
<Icon fontSize="small" />
|
||||
{!isOpen && hasSubmenu ? <ArrowRightIcon /> : <></>}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const itemIcon = (
|
||||
@@ -393,9 +394,9 @@ const SidebarItemBase = forwardRef<any, SidebarItemProps>((props, ref) => {
|
||||
|
||||
const openContent = (
|
||||
<>
|
||||
<div data-testid="login-button" className={classes.iconContainer}>
|
||||
<Box data-testid="login-button" className={classes.iconContainer}>
|
||||
{itemIcon}
|
||||
</div>
|
||||
</Box>
|
||||
{text && (
|
||||
<Typography variant="subtitle2" className={classes.label}>
|
||||
{text}
|
||||
@@ -572,7 +573,7 @@ export function SidebarSearchField(props: SidebarSearchFieldProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.searchRoot}>
|
||||
<Box className={classes.searchRoot}>
|
||||
<SidebarItem
|
||||
icon={Icon}
|
||||
to={props.to}
|
||||
@@ -595,7 +596,7 @@ export function SidebarSearchField(props: SidebarSearchFieldProps) {
|
||||
}}
|
||||
/>
|
||||
</SidebarItem>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -620,13 +621,13 @@ export const SidebarSpacer = styled('div')(
|
||||
export type SidebarDividerClassKey = 'root';
|
||||
|
||||
export const SidebarDivider = styled('hr')(
|
||||
{
|
||||
({ theme }) => ({
|
||||
height: 1,
|
||||
width: '100%',
|
||||
background: '#383838',
|
||||
border: 'none',
|
||||
margin: '12px 0px',
|
||||
},
|
||||
margin: theme.spacing(1.2, 0),
|
||||
}),
|
||||
{ name: 'BackstageSidebarDivider' },
|
||||
) as ComponentType<ComponentProps<'hr'> & StyledComponentProps<'root'>>;
|
||||
|
||||
@@ -693,9 +694,9 @@ export const SidebarExpandButton = () => {
|
||||
aria-label="Expand Sidebar"
|
||||
data-testid="sidebar-expand-button"
|
||||
>
|
||||
<div className={classes.arrows}>
|
||||
<Box className={classes.arrows}>
|
||||
{isOpen ? <DoubleArrowLeft /> : <DoubleArrowRight />}
|
||||
</div>
|
||||
</Box>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
@@ -25,10 +26,9 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { SidebarConfigContext, SidebarConfig } from './config';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
import { SidebarConfig, SidebarConfigContext } from './config';
|
||||
import { LocalStorage } from './localStorage';
|
||||
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
||||
import { SidebarPinStateProvider } from './SidebarPinStateContext';
|
||||
|
||||
export type SidebarPageClassKey = 'root';
|
||||
@@ -122,7 +122,7 @@ export function SidebarPage(props: SidebarPageProps) {
|
||||
}}
|
||||
>
|
||||
<PageContext.Provider value={pageContext}>
|
||||
<div className={classes.root}>{props.children}</div>
|
||||
<Box className={classes.root}>{props.children}</Box>
|
||||
</PageContext.Provider>
|
||||
</SidebarPinStateProvider>
|
||||
);
|
||||
|
||||
@@ -13,17 +13,19 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import classnames from 'classnames';
|
||||
import React, { ReactNode, useContext, useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
SidebarItemWithSubmenuContext,
|
||||
SidebarConfigContext,
|
||||
SidebarItemWithSubmenuContext,
|
||||
SubmenuConfig,
|
||||
} from './config';
|
||||
import { useSidebarOpenState } from './SidebarOpenStateContext';
|
||||
import { BackstageTheme } from '@backstage/theme';
|
||||
|
||||
const useStyles = makeStyles<
|
||||
BackstageTheme,
|
||||
@@ -76,10 +78,10 @@ const useStyles = makeStyles<
|
||||
},
|
||||
}),
|
||||
title: {
|
||||
fontSize: 24,
|
||||
fontWeight: 500,
|
||||
fontSize: theme.typography.h5.fontSize,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
color: '#FFF',
|
||||
padding: 20,
|
||||
padding: theme.spacing(2.5),
|
||||
[theme.breakpoints.down('xs')]: {
|
||||
display: 'none',
|
||||
},
|
||||
@@ -120,7 +122,7 @@ export const SidebarSubmenu = (props: SidebarSubmenuProps) => {
|
||||
}, [isHoveredOn]);
|
||||
|
||||
return (
|
||||
<div
|
||||
<Box
|
||||
className={classnames(classes.drawer, {
|
||||
[classes.drawerOpen]: isSubmenuOpen,
|
||||
})}
|
||||
@@ -129,6 +131,6 @@ export const SidebarSubmenu = (props: SidebarSubmenuProps) => {
|
||||
{props.title}
|
||||
</Typography>
|
||||
{props.children}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@ import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
|
||||
import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp';
|
||||
import { SidebarItemWithSubmenuContext } from './config';
|
||||
import { isLocationMatch } from './utils';
|
||||
import Box from '@material-ui/core/Box';
|
||||
|
||||
const useStyles = makeStyles<BackstageTheme>(
|
||||
theme => ({
|
||||
@@ -39,7 +40,7 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
color: theme.palette.navigation.color,
|
||||
padding: 20,
|
||||
padding: theme.spacing(2.5),
|
||||
cursor: 'pointer',
|
||||
position: 'relative',
|
||||
background: 'none',
|
||||
@@ -53,9 +54,9 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
color: '#FFF',
|
||||
},
|
||||
label: {
|
||||
margin: 14,
|
||||
marginLeft: 7,
|
||||
fontSize: 14,
|
||||
margin: theme.spacing(1.75),
|
||||
marginLeft: theme.spacing(1),
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis',
|
||||
@@ -88,7 +89,7 @@ const useStyles = makeStyles<BackstageTheme>(
|
||||
color: theme.palette.navigation.color,
|
||||
paddingLeft: theme.spacing(4),
|
||||
paddingRight: theme.spacing(1),
|
||||
fontSize: '14px',
|
||||
fontSize: theme.typography.body2.fontSize,
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis',
|
||||
@@ -155,7 +156,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
return isActive;
|
||||
});
|
||||
return (
|
||||
<div className={classes.itemContainer}>
|
||||
<Box className={classes.itemContainer}>
|
||||
<Tooltip title={title} enterDelay={500} enterNextDelay={500}>
|
||||
<button
|
||||
onClick={handleClickDropdown}
|
||||
@@ -183,7 +184,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
</button>
|
||||
</Tooltip>
|
||||
{dropdownItems && showDropDown && (
|
||||
<div className={classes.dropdown}>
|
||||
<Box className={classes.dropdown}>
|
||||
{dropdownItems.map((object, key) => (
|
||||
<Tooltip
|
||||
key={key}
|
||||
@@ -204,14 +205,14 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
</Link>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.itemContainer}>
|
||||
<Box className={classes.itemContainer}>
|
||||
<Tooltip title={title} enterDelay={500} enterNextDelay={500}>
|
||||
<Link
|
||||
to={to!}
|
||||
@@ -235,6 +236,6 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
</Typography>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos';
|
||||
import React from 'react';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
iconContainer: {
|
||||
@@ -34,14 +34,14 @@ const DoubleArrowLeft = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.iconContainer}>
|
||||
<div className={classes.arrow1}>
|
||||
<Box className={classes.iconContainer}>
|
||||
<Box className={classes.arrow1}>
|
||||
<ArrowBackIosIcon style={{ fontSize: '12px' }} />
|
||||
</div>
|
||||
<div>
|
||||
</Box>
|
||||
<Box>
|
||||
<ArrowBackIosIcon style={{ fontSize: '12px' }} />
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
|
||||
import React from 'react';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
iconContainer: {
|
||||
@@ -34,14 +34,14 @@ const DoubleArrowRight = () => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div className={classes.iconContainer}>
|
||||
<div className={classes.arrow1}>
|
||||
<Box className={classes.iconContainer}>
|
||||
<Box className={classes.arrow1}>
|
||||
<ArrowForwardIosIcon style={{ fontSize: '12px' }} />
|
||||
</div>
|
||||
<div>
|
||||
</Box>
|
||||
<Box>
|
||||
<ArrowForwardIosIcon style={{ fontSize: '12px' }} />
|
||||
</div>
|
||||
</div>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ export function TabbedCard(props: PropsWithChildren<Props>) {
|
||||
} else {
|
||||
React.Children.map(children, child => {
|
||||
if (React.isValidElement(child) && child?.props.value === value) {
|
||||
selectedTabContent = child?.props.children;
|
||||
selectedTabContent = child?.props?.children;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -142,7 +142,7 @@ const useCardTabStyles = makeStyles(
|
||||
},
|
||||
},
|
||||
selected: {
|
||||
fontWeight: 'bold',
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
},
|
||||
}),
|
||||
{ name: 'BackstageCardTab' },
|
||||
|
||||
@@ -23,6 +23,7 @@ import { FetchApi } from '@backstage/core-plugin-api';
|
||||
import { IdentityApi } from '@backstage/core-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { MatcherFunction } from '@testing-library/react';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { PermissionApi } from '@backstage/plugin-permission-react';
|
||||
import { PropsWithChildren } from 'react';
|
||||
@@ -241,6 +242,9 @@ export type TestAppOptions = {
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export const textContentMatcher: (text: string) => MatcherFunction;
|
||||
|
||||
// @public
|
||||
export function withLogCollector(
|
||||
callback: AsyncLogCollector,
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
attachComponentData,
|
||||
createRouteRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { RenderResult } from '@testing-library/react';
|
||||
import { MatcherFunction, RenderResult } from '@testing-library/react';
|
||||
import { renderWithEffects } from './testingLibrary';
|
||||
import { defaultApis } from './defaultApis';
|
||||
import { mockApis } from './mockApis';
|
||||
@@ -242,3 +242,24 @@ export async function renderInTestApp(
|
||||
wrapper: createTestAppWrapper(options),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a `@testing-library/react` valid MatcherFunction for supplied text
|
||||
*
|
||||
* @param string - text Text to match by element's textContent
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const textContentMatcher =
|
||||
(text: string): MatcherFunction =>
|
||||
(_, node) => {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasText = (textNode: Element) => textNode?.textContent === text;
|
||||
const childrenDontHaveText = (containerNode: Element) =>
|
||||
Array.from(containerNode?.children).every(child => !hasText(child));
|
||||
|
||||
return hasText(node) && childrenDontHaveText(node);
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ export { default as mockBreakpoint } from './mockBreakpoint';
|
||||
export {
|
||||
wrapInTestApp,
|
||||
renderInTestApp,
|
||||
textContentMatcher,
|
||||
createTestAppWrapper,
|
||||
} from './appWrappers';
|
||||
export type { TestAppOptions } from './appWrappers';
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('Features', () => {
|
||||
|
||||
expect(getByTestId(TEST_IDS.info.info)).toMatchInlineSnapshot(`
|
||||
<div
|
||||
class="MuiBox-root MuiBox-root-10"
|
||||
class="MuiBox-root MuiBox-root-11"
|
||||
data-testid="grm--info"
|
||||
>
|
||||
<h6
|
||||
@@ -72,7 +72,7 @@ describe('Features', () => {
|
||||
: The source control system where releases reside in a practical sense. Read more about
|
||||
|
||||
<a
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover Link-externalLink-12 MuiTypography-colorPrimary"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover Link-externalLink-13 MuiTypography-colorPrimary"
|
||||
href="https://docs.github.com/en/github/administering-a-repository/managing-releases-in-a-repository"
|
||||
rel="noopener"
|
||||
target="_blank"
|
||||
@@ -80,7 +80,7 @@ describe('Features', () => {
|
||||
>
|
||||
Git releases
|
||||
<span
|
||||
class="Link-visuallyHidden-11"
|
||||
class="MuiTypography-root Link-visuallyHidden-12 MuiTypography-body1"
|
||||
>
|
||||
, Opens in a new window
|
||||
</span>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import * as deployments from '../../__fixtures__/2-deployments.json';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { renderInTestApp, textContentMatcher } from '@backstage/test-utils';
|
||||
import { DeploymentDrawer } from './DeploymentDrawer';
|
||||
|
||||
describe('DeploymentDrawer', () => {
|
||||
@@ -33,9 +33,13 @@ describe('DeploymentDrawer', () => {
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(getByText('Strategy')).toBeInTheDocument();
|
||||
expect(getByText('Rolling Update:')).toBeInTheDocument();
|
||||
expect(getByText('Max Surge: 25%')).toBeInTheDocument();
|
||||
expect(getByText('Max Unavailable: 25%')).toBeInTheDocument();
|
||||
expect(getByText('Type: RollingUpdate')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('Max Surge: 25%'))).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Max Unavailable: 25%')),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Type: RollingUpdate')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Min Ready Seconds')).toBeInTheDocument();
|
||||
expect(getByText('???')).toBeInTheDocument();
|
||||
expect(getByText('Progress Deadline Seconds')).toBeInTheDocument();
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import * as ingresses from './__fixtures__/2-ingresses.json';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { textContentMatcher, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { IngressDrawer } from './IngressDrawer';
|
||||
|
||||
describe('IngressDrawer', () => {
|
||||
@@ -28,11 +28,17 @@ describe('IngressDrawer', () => {
|
||||
),
|
||||
);
|
||||
|
||||
expect(getAllByText('awesome-service')).toHaveLength(2);
|
||||
expect(getAllByText('awesome-service')).toHaveLength(4);
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(getByText('Rules')).toBeInTheDocument();
|
||||
expect(getByText('Host: api.awesome-host.io')).toBeInTheDocument();
|
||||
expect(getAllByText('Service Port: 80')).toHaveLength(2);
|
||||
expect(getAllByText('Service Name: awesome-service')).toHaveLength(2);
|
||||
expect(
|
||||
getByText(textContentMatcher('Host: api.awesome-host.io')),
|
||||
).toBeInTheDocument();
|
||||
expect(getAllByText(textContentMatcher('Service Port: 80'))).toHaveLength(
|
||||
2,
|
||||
);
|
||||
expect(
|
||||
getAllByText(textContentMatcher('Service Name: awesome-service')),
|
||||
).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
+15
-7
@@ -18,7 +18,7 @@ import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import * as pod from './__fixtures__/pod.json';
|
||||
import * as crashingPod from './__fixtures__/crashing-pod.json';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { textContentMatcher, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { PodDrawer } from './PodDrawer';
|
||||
|
||||
describe('PodDrawer', () => {
|
||||
@@ -46,8 +46,10 @@ describe('PodDrawer', () => {
|
||||
expect(getAllByText('True')).toHaveLength(4);
|
||||
expect(getByText('Exposed Ports')).toBeInTheDocument();
|
||||
expect(getByText('Nginx:')).toBeInTheDocument();
|
||||
expect(getByText('Container Port: 80')).toBeInTheDocument();
|
||||
expect(getByText('Protocol: TCP')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Container Port: 80')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('Protocol: TCP'))).toBeInTheDocument();
|
||||
});
|
||||
it('should render crashing pod', async () => {
|
||||
const { getByText, getAllByText } = render(
|
||||
@@ -80,12 +82,18 @@ describe('PodDrawer', () => {
|
||||
getAllByText('containers with unready status: [side-car other-side-car]'),
|
||||
).toHaveLength(2);
|
||||
expect(getByText('Exposed Ports')).toBeInTheDocument();
|
||||
expect(getAllByText('Protocol: TCP')).toHaveLength(3);
|
||||
expect(getAllByText(textContentMatcher('Protocol: TCP'))).toHaveLength(3);
|
||||
expect(getByText('Nginx:')).toBeInTheDocument();
|
||||
expect(getByText('Container Port: 80')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Container Port: 80')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Side Car:')).toBeInTheDocument();
|
||||
expect(getByText('Container Port: 81')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Container Port: 81')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Other Side Car:')).toBeInTheDocument();
|
||||
expect(getByText('Container Port: 82')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Container Port: 82')),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import * as services from './__fixtures__/2-services.json';
|
||||
import { wrapInTestApp } from '@backstage/test-utils';
|
||||
import { textContentMatcher, wrapInTestApp } from '@backstage/test-utils';
|
||||
import { ServiceDrawer } from './ServiceDrawer';
|
||||
|
||||
describe('ServiceDrawer', () => {
|
||||
@@ -33,7 +33,11 @@ describe('ServiceDrawer', () => {
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(getByText('Cluster IP')).toBeInTheDocument();
|
||||
expect(getByText('Ports')).toBeInTheDocument();
|
||||
expect(getByText('Target Port: 1997')).toBeInTheDocument();
|
||||
expect(getByText('App: awesome-service')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Target Port: 1997')),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('App: awesome-service')),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
+12
-6
@@ -16,7 +16,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import * as statefulsets from '../../__fixtures__/2-statefulsets.json';
|
||||
import { renderInTestApp } from '@backstage/test-utils';
|
||||
import { renderInTestApp, textContentMatcher } from '@backstage/test-utils';
|
||||
import { StatefulSetDrawer } from './StatefulSetDrawer';
|
||||
|
||||
describe('StatefulSetDrawer', () => {
|
||||
@@ -28,19 +28,25 @@ describe('StatefulSetDrawer', () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(getAllByText('dice-roller')).toHaveLength(3);
|
||||
expect(getAllByText('dice-roller')).toHaveLength(4);
|
||||
expect(getByText('StatefulSet')).toBeInTheDocument();
|
||||
expect(getByText('YAML')).toBeInTheDocument();
|
||||
expect(getByText('Type: RollingUpdate')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Type: RollingUpdate')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Rolling Update:')).toBeInTheDocument();
|
||||
expect(getByText('Max Surge: 25%')).toBeInTheDocument();
|
||||
expect(getByText('Max Unavailable: 25%')).toBeInTheDocument();
|
||||
expect(getByText(textContentMatcher('Max Surge: 25%'))).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('Max Unavailable: 25%')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Pod Management Policy')).toBeInTheDocument();
|
||||
expect(getByText('Parallel')).toBeInTheDocument();
|
||||
expect(getByText('Service Name')).toBeInTheDocument();
|
||||
expect(getByText('Selector')).toBeInTheDocument();
|
||||
expect(getByText('Match Labels:')).toBeInTheDocument();
|
||||
expect(getByText('App: dice-roller')).toBeInTheDocument();
|
||||
expect(
|
||||
getByText(textContentMatcher('App: dice-roller')),
|
||||
).toBeInTheDocument();
|
||||
expect(getByText('Revision History Limit')).toBeInTheDocument();
|
||||
expect(getByText('10')).toBeInTheDocument();
|
||||
expect(getByText('namespace: default')).toBeInTheDocument();
|
||||
|
||||
Reference in New Issue
Block a user