diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index 0c7dfd926e..c2483b40ee 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -47,8 +47,8 @@ import { useEntity, } from '@backstage/plugin-catalog'; import { Entity } from '@backstage/catalog-model'; -import { Grid } from '@material-ui/core'; -import { WarningPanel } from '@backstage/core'; +import { Button, Grid } from '@material-ui/core'; +import { EmptyState } from '@backstage/core'; const CICDSwitcher = ({ entity }: { entity: Entity }) => { // This component is just an example of how you can implement your company's logic in entity page. @@ -66,10 +66,20 @@ const CICDSwitcher = ({ entity }: { entity: Entity }) => { return ; default: return ( - - No CI/CD is available for this entity. Check corresponding - annotations! - + + Read more + + } + /> ); } }; diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx index b6d9b3a5aa..2b76c908e4 100644 --- a/packages/core/src/components/CodeSnippet/CodeSnippet.tsx +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx @@ -14,8 +14,7 @@ * limitations under the License. */ -import React, { FC } from 'react'; -import PropTypes from 'prop-types'; +import React from 'react'; import SyntaxHighlighter from 'react-syntax-highlighter'; import { docco, dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; import { useTheme } from '@material-ui/core'; @@ -27,19 +26,16 @@ type Props = { language: string; showLineNumbers?: boolean; showCopyCodeButton?: boolean; + highlightedNumbers?: number[]; }; -const defaultProps = { - showLineNumbers: false, - showCopyCodeButton: false, -}; - -export const CodeSnippet: FC = props => { - const { text, language, showLineNumbers, showCopyCodeButton } = { - ...defaultProps, - ...props, - }; - +export const CodeSnippet = ({ + text, + language, + showLineNumbers = false, + showCopyCodeButton = false, + highlightedNumbers, +}: Props) => { const theme = useTheme(); const mode = theme.palette.type === 'dark' ? dark : docco; @@ -49,6 +45,12 @@ export const CodeSnippet: FC = props => { language={language} style={mode} showLineNumbers={showLineNumbers} + wrapLines + lineProps={(lineNumber: number) => + highlightedNumbers?.includes(lineNumber) + ? { style: { backgroundColor: '#e6ffed' } } + : {} + } > {text} @@ -60,11 +62,3 @@ export const CodeSnippet: FC = props => { ); }; - -// Type check for the JS files using this core component -CodeSnippet.propTypes = { - text: PropTypes.string.isRequired, - language: PropTypes.string.isRequired, - showLineNumbers: PropTypes.bool, - showCopyCodeButton: PropTypes.bool, -}; diff --git a/packages/core/src/components/EmptyState/EmptyState.stories.tsx b/packages/core/src/components/EmptyState/EmptyState.stories.tsx index f3e40bd31c..15d61f14c0 100644 --- a/packages/core/src/components/EmptyState/EmptyState.stories.tsx +++ b/packages/core/src/components/EmptyState/EmptyState.stories.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { EmptyState } from './EmptyState'; import { Button } from '@material-ui/core'; +import { MissingAnnotationEmptyState } from './MissingAnnotationEmptyState'; export default { title: 'EmptyState', @@ -25,7 +26,7 @@ export default { const containerStyle = { width: '100%', height: '100vh' }; -export const MissingAnnotation = () => ( +export const Field = () => (
(
); -export const NoInformation = () => ( +export const Info = () => (
(
); -export const CreateComponent = () => ( +export const Content = () => (
(
); -export const NoBuild = () => ( +export const Data = () => (
( />
); + +export const MissingAnnotation = () => ( +
+ +
+); diff --git a/packages/core/src/components/EmptyState/EmptyState.tsx b/packages/core/src/components/EmptyState/EmptyState.tsx index 88becc7c90..4469c3ce86 100644 --- a/packages/core/src/components/EmptyState/EmptyState.tsx +++ b/packages/core/src/components/EmptyState/EmptyState.tsx @@ -22,7 +22,7 @@ import Background from './assets/Background.svg'; const useStyles = makeStyles(theme => ({ root: { backgroundColor: theme.palette.background.default, - padding: theme.spacing(10, 0, 0, 0), + padding: theme.spacing(2, 0, 0, 0), }, action: { marginTop: theme.spacing(2), @@ -56,7 +56,7 @@ export const EmptyState = ({ title, description, missing, action }: Props) => { > - {title} + {title} {description} diff --git a/packages/core/src/components/EmptyState/MissingAnnotationEmptyState.tsx b/packages/core/src/components/EmptyState/MissingAnnotationEmptyState.tsx new file mode 100644 index 0000000000..6ac15851e6 --- /dev/null +++ b/packages/core/src/components/EmptyState/MissingAnnotationEmptyState.tsx @@ -0,0 +1,69 @@ +/* + * 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 from 'react'; +import { Button, Typography } from '@material-ui/core'; +import { EmptyState } from './EmptyState'; +import { CodeSnippet } from '../CodeSnippet'; + +const COMPONENT_YAML = `# Example +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage + description: backstage.io + annotations: + ANNOTATION: value +spec: + type: website + lifecycle: production + owner: guest +`; + +type Props = { + annotation: string; +}; + +export const MissingAnnotationEmptyState = ({ annotation }: Props) => { + return ( + + + Add the annotation to your component YAML as per the highlighted + example below: + + + + + } + /> + ); +}; diff --git a/packages/core/src/components/EmptyState/index.ts b/packages/core/src/components/EmptyState/index.ts index 3774010467..2e2a88be94 100644 --- a/packages/core/src/components/EmptyState/index.ts +++ b/packages/core/src/components/EmptyState/index.ts @@ -15,3 +15,4 @@ */ export { EmptyState } from './EmptyState'; +export { MissingAnnotationEmptyState } from './MissingAnnotationEmptyState'; diff --git a/plugins/github-actions/README.md b/plugins/github-actions/README.md index 24bc96937f..07a69cdfad 100644 --- a/plugins/github-actions/README.md +++ b/plugins/github-actions/README.md @@ -11,7 +11,7 @@ TBD ### Generic Requirements 1. Provide OAuth credentials: - 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) with callback URL set to `https://localhost:3000/auth/github`. + 1. [Create an OAuth App](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) with callback URL set to `http://localhost:7000/api/auth/github`. 2. Take Client ID and Client Secret from the newly created app's settings page and put them into `AUTH_GITHUB_CLIENT_ID` and `AUTH_GITHUB_CLIENT_SECRET` env variables. 2. Annotate your component with a correct GitHub Actions repository and owner: diff --git a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx index 014aed1633..e5bba7fad9 100644 --- a/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx +++ b/plugins/github-actions/src/components/Cards/RecentWorkflowRunsCard.tsx @@ -18,9 +18,9 @@ import { errorApiRef, useApi } from '@backstage/core-api'; import { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName'; import { useWorkflowRuns } from '../useWorkflowRuns'; import React, { useEffect } from 'react'; -import { Table } from '@backstage/core'; +import { EmptyState, Table } from '@backstage/core'; import { WorkflowRunStatus } from '../WorkflowRunStatus'; -import { Card, Link, TableContainer } from '@material-ui/core'; +import { Button, Card, Link, TableContainer } from '@material-ui/core'; import { generatePath, Link as RouterLink } from 'react-router-dom'; const firstLine = (message: string): string => message.split('\n')[0]; @@ -54,7 +54,22 @@ export const RecentWorkflowRunsCard = ({ } }, [error, errorApi]); - return ( + return !runs.length ? ( + + Create new Workflow + + } + /> + ) : ( Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]); export const Router = ({ entity }: { entity: Entity }) => - // TODO(shmidt-i): move warning to a separate standardized component !isPluginApplicableToEntity(entity) ? ( - -
{GITHUB_ACTIONS_ANNOTATION}
annotation is missing on the - entity. -
+ ) : ( { const { value: projectName, loading } = useProjectName(entity); const [owner, repo] = (projectName ?? '/').split('/'); - const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({ + const [ + { runs, ...tableProps }, + { retry, setPage, setPageSize }, + ] = useWorkflowRuns({ owner, repo, branch, }); - return ( + return !runs ? ( + + Create new Workflow + + } + /> + ) : (