diff --git a/packages/core/src/layout/InfoCard/BottomLink.js b/packages/core/src/layout/InfoCard/BottomLink.js
deleted file mode 100644
index 5dafa72978..0000000000
--- a/packages/core/src/layout/InfoCard/BottomLink.js
+++ /dev/null
@@ -1,63 +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 } from 'react';
-import PropTypes from 'prop-types';
-import { Link } from '@material-ui/core';
-import { Divider, ListItemText, withStyles } from '@material-ui/core';
-import { ListItem, ListItemIcon } from '@material-ui/core';
-import ArrowIcon from '@material-ui/icons/ArrowForward';
-import grey from '@material-ui/core/colors/grey';
-import Box from '@material-ui/core/Box';
-
-const styles = theme => ({
- root: {
- maxWidth: 'fit-content',
- padding: theme.spacing(2, 2, 2, 2.5)
- },
- boxTitle: {
- margin: 0,
- color: grey[900]
- }
-})
-class BottomLink extends Component {
- static propTypes = {
- link: PropTypes.string,
- title: PropTypes.string,
- onClick: PropTypes.func,
- };
-
- render() {
- const { link, title, onClick, classes } = this.props;
- return (
-
-
-
-
-
- {title}
-
-
-
-
-
-
-
- );
- }
-}
-
-export default withStyles(styles)(BottomLink);
\ No newline at end of file
diff --git a/packages/core/src/layout/InfoCard/BottomLink.test.js b/packages/core/src/layout/InfoCard/BottomLink.test.tsx
similarity index 100%
rename from packages/core/src/layout/InfoCard/BottomLink.test.js
rename to packages/core/src/layout/InfoCard/BottomLink.test.tsx
diff --git a/packages/core/src/layout/InfoCard/BottomLink.tsx b/packages/core/src/layout/InfoCard/BottomLink.tsx
new file mode 100644
index 0000000000..bf82f6cd11
--- /dev/null
+++ b/packages/core/src/layout/InfoCard/BottomLink.tsx
@@ -0,0 +1,65 @@
+/*
+ * 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, { FC } from 'react';
+import { Link } from '@material-ui/core';
+import { Divider, ListItemText, makeStyles } from '@material-ui/core';
+import { ListItem, ListItemIcon } from '@material-ui/core';
+import ArrowIcon from '@material-ui/icons/ArrowForward';
+import grey from '@material-ui/core/colors/grey';
+import Box from '@material-ui/core/Box';
+import { BackstageTheme } from '../../theme/theme';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ maxWidth: 'fit-content',
+ padding: theme.spacing(2, 2, 2, 2.5),
+ },
+ boxTitle: {
+ margin: 0,
+ color: grey[900],
+ },
+}));
+
+export type Props = {
+ link: string;
+ title: string;
+ onClick?: (event: React.MouseEvent) => void;
+};
+
+const BottomLink: FC = ({ link, title, onClick }) => {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+ {title}
+
+
+
+
+
+
+
+
+ );
+};
+
+export default BottomLink;
diff --git a/packages/core/src/layout/InfoCard/InfoCard.js b/packages/core/src/layout/InfoCard/InfoCard.js
deleted file mode 100644
index 1005a016af..0000000000
--- a/packages/core/src/layout/InfoCard/InfoCard.js
+++ /dev/null
@@ -1,229 +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 } from 'react';
-import PropTypes from 'prop-types';
-import {
- Card,
- CardActions,
- CardContent,
- CardHeader,
- Divider,
- withStyles,
-} from '@material-ui/core';
-import ErrorBoundary from '../ErrorBoundary/ErrorBoundary';
-import BottomLink from './BottomLink';
-
-import textContent from 'react-addons-text-content';
-
-const styles = theme => ({
- header: {
- padding: theme.spacing(2, 2, 2, 2.5)
- }
-});
-
-const BoldHeader = withStyles({
- title: { fontWeight: '700' },
- subheader: { paddingTop: '2px' },
-})(CardHeader);
-
-const CardActionsTopRight = withStyles({
- root: {
- display: 'inline-block',
- paddingRight: '16px',
- paddingTop: '16px',
- float: 'right',
- },
-})(CardActions);
-
-const VARIANT_STYLES = {
- card: {
- flex: {
- display: 'flex',
- flexDirection: 'column',
- },
- widget: {
- height: 430,
- },
- fullHeight: {
- height: '100%',
- },
- height100: {
- display: 'flex',
- flexDirection: 'column',
- height: 'calc(100% - 10px)', // for pages without content header
- marginBottom: '10px',
- },
- contentheader: {
- height: 'calc(100% - 40px)', // for pages with content header
- },
- contentheadertabs: {
- height: 'calc(100% - 97px)', // for pages with content header and tabs (Tingle)
- },
- noShrink: {
- flexShrink: 0,
- },
- minheight300: {
- minHeight: 300,
- overflow: 'initial',
- },
- },
- cardContent: {
- widget: {
- overflowY: 'auto',
- height: 332,
- width: '100%',
- },
- fullHeight: {
- height: 'calc(100% - 50px)',
- },
- height100: {
- height: 'calc(100% - 50px)',
- },
- contentRow: {
- display: 'flex',
- flexDirection: 'row',
- },
- },
-};
-
-/**
- * InfoCard is used to display a paper-styled block on the screen, similar to a panel.
- *
- * You can custom style an InfoCard with the 'style' (outer container) and 'cardStyle' (inner container)
- * styles.
- *
- * The InfoCard serves as an error boundary. As a result, if you provide a 'slackChannel' property this
- * specifies the channel to display in the error component that is displayed if an error occurs
- * in any descendent components.
- *
- * By default the InfoCard has no custom layout of its children, but is treated as a block element. A
- * couple common variants are provided and can be specified via the variant property:
- *
- * Display the card full height suitable for DataGrid:
- *
- * ...
- *
- * Variants can be combined in a whitespace delimited list like so:
- *
- * ...
- */
-class InfoCard extends Component {
- static propTypes = {
- title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
- subheader: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
- divider: PropTypes.bool,
- deepLink: PropTypes.object,
- slackChannel: PropTypes.string,
- variant: PropTypes.string,
- };
-
- render() {
- const {
- title,
- subheader,
- divider,
- deepLink,
- children,
- actions,
- actionsTopRight,
- headerStyle,
- headerProps,
- classes,
- slackChannel,
- variant,
- } = this.props;
-
- if (this.props.style) {
- // eslint-disable-next-line no-console
- console.warn(
- 'InfoCard: using `style` property directly, consider migrating your style to variant in InfoCard',
- );
- }
- if (this.props.cardStyle) {
- // eslint-disable-next-line no-console
- console.warn(
- 'InfoCard: using `cardStyle` property directly, consider migrating your style to variant in InfoCard',
- );
- }
-
- /**
- * If variant is specified, we build up styles for that particular variant for both
- * the Card and the CardContent (since these need to be synced)
- */
- let calculatedStyle = {};
- let calculatedCardStyle = {};
-
- if (variant) {
- const variants = variant.split(/[\s]+/g);
- variants.forEach(name => {
- calculatedStyle = { ...calculatedStyle, ...VARIANT_STYLES.card[name] };
- calculatedCardStyle = {
- ...calculatedCardStyle,
- ...VARIANT_STYLES.cardContent[name],
- };
- });
- }
-
- // Apply the passed styles on top
- const computedStyle = { ...calculatedStyle, ...this.props.style };
- const computedCardStyle = {
- ...calculatedCardStyle,
- ...this.props.cardStyle,
- };
-
- return (
-
-
- {title && (
- <>
-
-
- >
- )}
- {actionsTopRight && (
- {actionsTopRight}
- )}
- {divider && }
-
- {children}
-
- {actions && (
-
- {actions}
-
- )}
- {deepLink && }
-
-
- );
- }
-}
-
-export default withStyles(styles)(InfoCard);
diff --git a/packages/core/src/layout/InfoCard/InfoCard.test.js b/packages/core/src/layout/InfoCard/InfoCard.test.tsx
similarity index 100%
rename from packages/core/src/layout/InfoCard/InfoCard.test.js
rename to packages/core/src/layout/InfoCard/InfoCard.test.tsx
diff --git a/packages/core/src/layout/InfoCard/InfoCard.tsx b/packages/core/src/layout/InfoCard/InfoCard.tsx
new file mode 100644
index 0000000000..5b3ab1cfd1
--- /dev/null
+++ b/packages/core/src/layout/InfoCard/InfoCard.tsx
@@ -0,0 +1,206 @@
+/*
+ * 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, { FC, ReactNode } from 'react';
+import {
+ Card,
+ CardActions,
+ CardContent,
+ CardHeader,
+ Divider,
+ withStyles,
+ makeStyles,
+} from '@material-ui/core';
+import ErrorBoundary from '../ErrorBoundary/ErrorBoundary';
+import BottomLink, { Props as BottomLinkProps } from './BottomLink';
+import { BackstageTheme } from '../../theme/theme';
+
+const useStyles = makeStyles(theme => ({
+ header: {
+ padding: theme.spacing(2, 2, 2, 2.5),
+ },
+}));
+
+const BoldHeader = withStyles(theme => ({
+ title: { fontWeight: 700 },
+ subheader: { paddingTop: theme.spacing(1) },
+}))(CardHeader);
+
+const CardActionsTopRight = withStyles(theme => ({
+ root: {
+ display: 'inline-block',
+ padding: theme.spacing(8, 8, 0, 0),
+ float: 'right',
+ },
+}))(CardActions);
+
+const VARIANT_STYLES = {
+ card: {
+ flex: {
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ widget: {
+ height: 430,
+ },
+ fullHeight: {
+ height: '100%',
+ },
+ height100: {
+ display: 'flex',
+ flexDirection: 'column',
+ height: 'calc(100% - 10px)', // for pages without content header
+ marginBottom: '10px',
+ },
+ contentheader: {
+ height: 'calc(100% - 40px)', // for pages with content header
+ },
+ contentheadertabs: {
+ height: 'calc(100% - 97px)', // for pages with content header and tabs (Tingle)
+ },
+ noShrink: {
+ flexShrink: 0,
+ },
+ minheight300: {
+ minHeight: 300,
+ overflow: 'initial',
+ },
+ },
+ cardContent: {
+ widget: {
+ overflowY: 'auto',
+ height: 332,
+ width: '100%',
+ },
+ fullHeight: {
+ height: 'calc(100% - 50px)',
+ },
+ height100: {
+ height: 'calc(100% - 50px)',
+ },
+ contentRow: {
+ display: 'flex',
+ flexDirection: 'row',
+ },
+ },
+};
+
+/**
+ * InfoCard is used to display a paper-styled block on the screen, similar to a panel.
+ *
+ * You can custom style an InfoCard with the 'style' (outer container) and 'cardStyle' (inner container)
+ * styles.
+ *
+ * The InfoCard serves as an error boundary. As a result, if you provide a 'slackChannel' property this
+ * specifies the channel to display in the error component that is displayed if an error occurs
+ * in any descendent components.
+ *
+ * By default the InfoCard has no custom layout of its children, but is treated as a block element. A
+ * couple common variants are provided and can be specified via the variant property:
+ *
+ * Display the card full height suitable for DataGrid:
+ *
+ * ...
+ *
+ * Variants can be combined in a whitespace delimited list like so:
+ *
+ * ...
+ */
+type Props = {
+ title?: ReactNode;
+ subheader?: ReactNode;
+ divider?: boolean;
+ deepLink?: BottomLinkProps;
+ slackChannel?: string;
+ variant?: string;
+ style?: object;
+ cardStyle?: object;
+ children?: ReactNode;
+ headerStyle?: object;
+ headerProps?: object;
+ actionsClassName?: string;
+ actions?: ReactNode;
+ cardClassName?: string;
+ actionsTopRight?: ReactNode;
+};
+
+const InfoCard: FC = ({
+ title,
+ subheader,
+ divider,
+ deepLink,
+ slackChannel = '#backstage',
+ variant,
+ children,
+ headerStyle,
+ headerProps,
+ actionsClassName,
+ actions,
+ cardClassName,
+ actionsTopRight,
+}) => {
+ const classes = useStyles();
+
+ /**
+ * If variant is specified, we build up styles for that particular variant for both
+ * the Card and the CardContent (since these need to be synced)
+ */
+ let calculatedStyle = {};
+ let calculatedCardStyle = {};
+
+ if (variant) {
+ const variants = variant.split(/[\s]+/g);
+ variants.forEach(name => {
+ calculatedStyle = { ...calculatedStyle, ...VARIANT_STYLES.card[name] };
+ calculatedCardStyle = {
+ ...calculatedCardStyle,
+ ...VARIANT_STYLES.cardContent[name],
+ };
+ });
+ }
+
+ return (
+
+
+ {title && (
+ <>
+
+
+ >
+ )}
+ {actionsTopRight && (
+ {actionsTopRight}
+ )}
+ {divider && }
+
+ {children}
+
+ {actions && (
+ {actions}
+ )}
+ {deepLink && }
+
+
+ );
+};
+
+export default InfoCard;
diff --git a/packages/core/src/layout/InfoCard/index.js b/packages/core/src/layout/InfoCard/index.ts
similarity index 100%
rename from packages/core/src/layout/InfoCard/index.js
rename to packages/core/src/layout/InfoCard/index.ts