diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json
index f306c03ff8..4ab0decfbe 100644
--- a/plugins/catalog/package.json
+++ b/plugins/catalog/package.json
@@ -23,6 +23,7 @@
"dependencies": {
"@backstage/catalog-model": "^0.1.1-alpha.16",
"@backstage/core": "^0.1.1-alpha.16",
+ "@backstage/plugin-github-actions": "^0.1.1-alpha.16",
"@backstage/plugin-scaffolder": "^0.1.1-alpha.16",
"@backstage/plugin-sentry": "^0.1.1-alpha.16",
"@backstage/theme": "^0.1.1-alpha.16",
diff --git a/plugins/catalog/src/components/EntityPage/EntityPage.tsx b/plugins/catalog/src/components/EntityPage/EntityPage.tsx
index 1c56924589..ce128777bd 100644
--- a/plugins/catalog/src/components/EntityPage/EntityPage.tsx
+++ b/plugins/catalog/src/components/EntityPage/EntityPage.tsx
@@ -28,6 +28,7 @@ import {
useApi,
} from '@backstage/core';
import { SentryIssuesWidget } from '@backstage/plugin-sentry';
+import { Widget as GithubActionsWidget } from '@backstage/plugin-github-actions';
import { Grid, Box } from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import React, { FC, useEffect, useState } from 'react';
@@ -192,6 +193,13 @@ export const EntityPage: FC<{}> = () => {
statsFor="24h"
/>
+ {entity.metadata?.annotations?.[
+ 'backstage.io/github-actions-id'
+ ] && (
+
+
+
+ )}
diff --git a/plugins/catalog/src/components/useEntityCompoundName.ts b/plugins/catalog/src/components/useEntityCompoundName.ts
new file mode 100644
index 0000000000..2be23cb6d9
--- /dev/null
+++ b/plugins/catalog/src/components/useEntityCompoundName.ts
@@ -0,0 +1,26 @@
+/*
+ * 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 { useParams } from 'react-router';
+
+/**
+ * Grabs entity kind and name + optional namespace from location
+ */
+export const useEntityCompoundName = () => {
+ const params = useParams();
+ const { kind, optionalNamespaceAndName = '' } = params;
+ const [name, namespace] = optionalNamespaceAndName.split(':').reverse();
+ return { kind, name, namespace };
+};
diff --git a/plugins/catalog/src/index.ts b/plugins/catalog/src/index.ts
index 701394df34..36fd69971d 100644
--- a/plugins/catalog/src/index.ts
+++ b/plugins/catalog/src/index.ts
@@ -18,3 +18,4 @@ export { plugin } from './plugin';
export * from './api/CatalogClient';
export * from './api/types';
export * from './routes';
+export { useEntityCompoundName } from './components/useEntityCompoundName';
diff --git a/plugins/github-actions/src/api/GithubActionsApi.ts b/plugins/github-actions/src/api/GithubActionsApi.ts
index bb54fae703..acdfb90cf3 100644
--- a/plugins/github-actions/src/api/GithubActionsApi.ts
+++ b/plugins/github-actions/src/api/GithubActionsApi.ts
@@ -33,12 +33,14 @@ export type GithubActionsApi = {
repo,
pageSize,
page,
+ branch,
}: {
token: string;
owner: string;
repo: string;
pageSize?: number;
page?: number;
+ branch?: string;
}) => Promise;
getWorkflow: ({
token,
diff --git a/plugins/github-actions/src/api/GithubActionsClient.ts b/plugins/github-actions/src/api/GithubActionsClient.ts
index a96f5341fd..72f65075e6 100644
--- a/plugins/github-actions/src/api/GithubActionsClient.ts
+++ b/plugins/github-actions/src/api/GithubActionsClient.ts
@@ -46,12 +46,14 @@ export class GithubActionsClient implements GithubActionsApi {
repo,
pageSize = 100,
page = 0,
+ branch,
}: {
token: string;
owner: string;
repo: string;
pageSize?: number;
page?: number;
+ branch?: string;
}): Promise {
const workflowRuns = await new Octokit({
auth: token,
@@ -60,6 +62,7 @@ export class GithubActionsClient implements GithubActionsApi {
repo,
per_page: pageSize,
page,
+ ...(branch ? { branch } : {}),
});
return workflowRuns.data;
}
diff --git a/plugins/github-actions/src/components/Widget/Widget.tsx b/plugins/github-actions/src/components/Widget/Widget.tsx
new file mode 100644
index 0000000000..031364c8ce
--- /dev/null
+++ b/plugins/github-actions/src/components/Widget/Widget.tsx
@@ -0,0 +1,110 @@
+/*
+ * 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, { useEffect } from 'react';
+import { useWorkflowRuns } from '../useWorkflowRuns';
+import { WorkflowRun } from '../WorkflowRunsTable';
+import { Entity } from '@backstage/catalog-model';
+import { WorkflowRunStatus } from '../WorkflowRunStatus';
+import {
+ Link,
+ Theme,
+ makeStyles,
+ LinearProgress,
+ Typography,
+} from '@material-ui/core';
+import {
+ InfoCard,
+ StructuredMetadataTable,
+ errorApiRef,
+ useApi,
+} from '@backstage/core';
+import ExternalLinkIcon from '@material-ui/icons/Launch';
+
+const useStyles = makeStyles({
+ externalLinkIcon: {
+ fontSize: 'inherit',
+ verticalAlign: 'bottom',
+ },
+});
+
+const WidgetContent = ({
+ error,
+ loading,
+ lastRun,
+ branch,
+}: {
+ error?: Error;
+ loading?: boolean;
+ lastRun: WorkflowRun;
+ branch: string;
+}) => {
+ const classes = useStyles();
+ if (error) return Couldn't fetch latest {branch} run;
+ if (loading) return ;
+ return (
+
+
+ >
+ ),
+ message: lastRun.message,
+ url: (
+
+ See more on GitHub{' '}
+
+
+ ),
+ }}
+ />
+ );
+};
+
+export const Widget = ({
+ entity,
+ branch = 'master',
+}: {
+ entity: Entity;
+ branch: string;
+}) => {
+ const errorApi = useApi(errorApiRef);
+ const [owner, repo] = (
+ entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '/'
+ ).split('/');
+ const [{ runs, loading, error }] = useWorkflowRuns({
+ owner,
+ repo,
+ branch,
+ });
+ const lastRun = runs?.[0] ?? ({} as WorkflowRun);
+ useEffect(() => {
+ if (error) {
+ errorApi.post(error);
+ }
+ }, [error, errorApi]);
+
+ return (
+
+
+
+ );
+};
diff --git a/plugins/github-actions/src/components/Widget/index.ts b/plugins/github-actions/src/components/Widget/index.ts
new file mode 100644
index 0000000000..2b34671ab5
--- /dev/null
+++ b/plugins/github-actions/src/components/Widget/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { Widget } from './Widget';
diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx
new file mode 100644
index 0000000000..8c445ca9f6
--- /dev/null
+++ b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx
@@ -0,0 +1,236 @@
+/*
+ * 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 { useEntityCompoundName } from '@backstage/plugin-catalog';
+import { useWorkflowRunsDetails } from './useWorkflowRunsDetails';
+import { useWorkflowRunJobs } from './useWorkflowRunJobs';
+import { useProjectName } from '../useProjectName';
+import {
+ makeStyles,
+ Box,
+ TableRow,
+ TableCell,
+ ListItemText,
+ ExpansionPanel,
+ ExpansionPanelSummary,
+ Typography,
+ ExpansionPanelDetails,
+ TableContainer,
+ Table,
+ Paper,
+ TableBody,
+ LinearProgress,
+ CircularProgress,
+ Theme,
+ Link,
+} from '@material-ui/core';
+import { Jobs, Job, Step } from '../../api';
+import moment from 'moment';
+import { WorkflowRunStatus } from '../WorkflowRunStatus';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ExternalLinkIcon from '@material-ui/icons/Launch';
+
+const useStyles = makeStyles(theme => ({
+ root: {
+ maxWidth: 720,
+ margin: theme.spacing(2),
+ },
+ title: {
+ padding: theme.spacing(1, 0, 2, 0),
+ },
+ table: {
+ padding: theme.spacing(1),
+ },
+ expansionPanelDetails: {
+ padding: 0,
+ },
+ button: {
+ order: -1,
+ marginRight: 0,
+ marginLeft: '-20px',
+ },
+ externalLinkIcon: {
+ fontSize: 'inherit',
+ verticalAlign: 'bottom',
+ },
+}));
+
+const JobsList = ({ jobs }: { jobs?: Jobs }) => {
+ const classes = useStyles();
+ return (
+
+ {jobs &&
+ jobs.total_count > 0 &&
+ jobs.jobs.map((job: Job) => (
+
+ ))}
+
+ );
+};
+
+const getElapsedTime = (start: string, end: string) => {
+ const diff = moment(moment(end || moment()).diff(moment(start)));
+ const timeElapsed = diff.format('m [minutes] s [seconds]');
+ return timeElapsed;
+};
+
+const StepView = ({ step }: { step: Step }) => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+const JobListItem = ({ job, className }: { job: Job; className: string }) => {
+ const classes = useStyles();
+ return (
+
+ }
+ aria-controls={`panel-${name}-content`}
+ id={`panel-${name}-header`}
+ IconButtonProps={{
+ className: classes.button,
+ }}
+ >
+
+ {job.name} ({getElapsedTime(job.started_at, job.completed_at)})
+
+
+
+
+
+ {job.steps.map((step: Step) => (
+
+ ))}
+
+
+
+
+ );
+};
+
+export const WorkflowRunDetails = () => {
+ let entityCompoundName = useEntityCompoundName();
+ if (!entityCompoundName.name) {
+ // TODO(shmidt-i): remove when is fully integrated
+ // into the entity view
+ entityCompoundName = {
+ kind: 'Component',
+ name: 'backstage',
+ namespace: 'default',
+ };
+ }
+ const projectName = useProjectName(entityCompoundName);
+
+ const [owner, repo] = projectName.value ? projectName.value.split('/') : [];
+ const details = useWorkflowRunsDetails(repo, owner);
+ const jobs = useWorkflowRunJobs(details.value?.jobs_url);
+
+ const error = projectName.error || (projectName.value && details.error);
+ const classes = useStyles();
+ if (error) {
+ return (
+
+ Failed to load build, {error.message}
+
+ );
+ } else if (projectName.loading || details.loading) {
+ return ;
+ }
+ return (
+
+
+
+
+
+
+ Branch
+
+ {details.value?.head_branch}
+
+
+
+ Message
+
+ {details.value?.head_commit.message}
+
+
+
+ Commit ID
+
+ {details.value?.head_commit.id}
+
+
+
+ Status
+
+
+
+
+
+
+
+ Author
+
+ {`${details.value?.head_commit.author.name} (${details.value?.head_commit.author.email})`}
+
+
+
+ Links
+
+
+ {details.value?.html_url && (
+
+ Workflow runs on GitHub{' '}
+
+
+ )}
+
+
+
+
+ Jobs
+ {jobs.loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+ );
+};
diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/index.ts b/plugins/github-actions/src/components/WorkflowRunDetails/index.ts
new file mode 100644
index 0000000000..2886a26740
--- /dev/null
+++ b/plugins/github-actions/src/components/WorkflowRunDetails/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { WorkflowRunDetails } from './WorkflowRunDetails';
diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts
similarity index 100%
rename from plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunJobs.ts
rename to plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunJobs.ts
diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts
similarity index 85%
rename from plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts
rename to plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts
index 623f55eea6..b38284d52f 100644
--- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/useWorkflowRunsDetails.ts
+++ b/plugins/github-actions/src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts
@@ -24,12 +24,14 @@ export const useWorkflowRunsDetails = (repo: string, owner: string) => {
const { id } = useParams();
const details = useAsync(async () => {
const token = await auth.getAccessToken(['repo']);
- return api.getWorkflowRun({
- token,
- owner,
- repo,
- id: parseInt(id, 10),
- });
+ return repo && owner
+ ? api.getWorkflowRun({
+ token,
+ owner,
+ repo,
+ id: parseInt(id, 10),
+ })
+ : Promise.reject('No repo/owner provided');
}, [repo, owner, id]);
return details;
};
diff --git a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx
index 283fd60ec6..ec9a3f484d 100644
--- a/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx
+++ b/plugins/github-actions/src/components/WorkflowRunDetailsPage/WorkflowRunDetailsPage.tsx
@@ -14,28 +14,7 @@
* limitations under the License.
*/
-import {
- Button,
- LinearProgress,
- makeStyles,
- Paper,
- Table,
- TableBody,
- TableCell,
- TableContainer,
- TableRow,
- Theme,
- Typography,
- Box,
- ExpansionPanelDetails,
- ExpansionPanel,
- ExpansionPanelSummary,
- ListItemText,
- CircularProgress,
- Grid,
- Breadcrumbs,
-} from '@material-ui/core';
-import moment from 'moment';
+import { Typography, Grid, Breadcrumbs } from '@material-ui/core';
import React from 'react';
import {
@@ -48,133 +27,13 @@ import {
SupportButton,
pageTheme,
} from '@backstage/core';
-import { Job, Step, Jobs } from '../../api/types';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
-import { useWorkflowRunsDetails } from './useWorkflowRunsDetails';
-import { useWorkflowRunJobs } from './useWorkflowRunJobs';
-import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon/WorkflowRunStatusIcon';
-import { useProjectName } from '../useProjectName';
-import GitHubIcon from '@material-ui/icons/GitHub';
-const useStyles = makeStyles(theme => ({
- root: {
- maxWidth: 720,
- margin: theme.spacing(2),
- },
- title: {
- padding: theme.spacing(1, 0, 2, 0),
- },
- table: {
- padding: theme.spacing(1),
- },
- expansionPanelDetails: {
- padding: 0,
- },
- button: {
- order: -1,
- marginRight: 0,
- marginLeft: '-20px',
- },
-}));
-
-const JobsList = ({ jobs }: { jobs?: Jobs }) => {
- const classes = useStyles();
- return (
-
- {jobs &&
- jobs.total_count > 0 &&
- jobs.jobs.map((job: Job) => (
-
- ))}
-
- );
-};
-
-const getElapsedTime = (start: string, end: string) => {
- const diff = moment(moment(end || moment()).diff(moment(start)));
- const timeElapsed = diff.format('m [minutes] s [seconds]');
- return timeElapsed;
-};
-
-const StepView = ({ step }: { step: Step }) => {
- return (
-
-
-
-
-
-
- {step.status}
-
-
- );
-};
-
-const JobListItem = ({ job, className }: { job: Job; className: string }) => {
- const classes = useStyles();
- return (
-
- }
- aria-controls={`panel-${name}-content`}
- id={`panel-${name}-header`}
- IconButtonProps={{
- className: classes.button,
- }}
- >
-
- {job.name} ({getElapsedTime(job.started_at, job.completed_at)})
-
-
-
-
-
- {job.steps.map((step: Step) => (
-
- ))}
-
-
-
-
- );
-};
+import { WorkflowRunDetails } from '../WorkflowRunDetails';
/**
* A component for Jobs visualization. Jobs are a property of a Workflow Run.
*/
export const WorkflowRunDetailsPage = () => {
- const [owner, repo] = (
- useProjectName({
- kind: 'Component',
- name: 'backstage',
- }) ?? '/'
- ).split('/');
- const details = useWorkflowRunsDetails(repo, owner);
- const jobs = useWorkflowRunJobs(details.value?.jobs_url);
-
- const classes = useStyles();
-
- if (details.loading) {
- return ;
- } else if (details.error) {
- return (
-
- Failed to load build, {details.error.message}
-
- );
- }
-
return (
{
-
-
-
-
-
-
- Branch
-
- {details.value?.head_branch}
-
-
-
- Message
-
-
- {details.value?.head_commit.message}
-
-
-
-
- Commit ID
-
- {details.value?.head_commit.id}
-
-
-
- Status
-
-
- {' '}
- {details.value?.status.toUpperCase()}
-
-
-
-
- Author
-
- {`${details.value?.head_commit.author.name} (${details.value?.head_commit.author.email})`}
-
-
-
- Links
-
-
- {details.value?.html_url && (
-
- }
- >
- Workflow runs on GitHub
-
-
- )}
-
-
-
-
- Jobs
- {jobs.loading ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
+
diff --git a/plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx b/plugins/github-actions/src/components/WorkflowRunStatus/WorkflowRunStatus.tsx
similarity index 71%
rename from plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx
rename to plugins/github-actions/src/components/WorkflowRunStatus/WorkflowRunStatus.tsx
index 645224ad24..089c319802 100644
--- a/plugins/github-actions/src/components/WorkflowRunStatusIcon/WorkflowRunStatusIcon.tsx
+++ b/plugins/github-actions/src/components/WorkflowRunStatus/WorkflowRunStatus.tsx
@@ -17,7 +17,7 @@
import { StatusPending, StatusRunning, StatusOK } from '@backstage/core';
import React from 'react';
-export const WorkflowRunStatusIcon = ({
+export const WorkflowRunStatus = ({
status,
}: {
status: string | undefined;
@@ -25,12 +25,28 @@ export const WorkflowRunStatusIcon = ({
if (status === undefined) return null;
switch (status.toLowerCase()) {
case 'queued':
- return ;
+ return (
+ <>
+ Queued
+ >
+ );
case 'in_progress':
- return ;
+ return (
+ <>
+ In progress
+ >
+ );
case 'completed':
- return ;
+ return (
+ <>
+ Completed
+ >
+ );
default:
- return ;
+ return (
+ <>
+ Pending
+ >
+ );
}
};
diff --git a/plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts b/plugins/github-actions/src/components/WorkflowRunStatus/index.ts
similarity index 90%
rename from plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts
rename to plugins/github-actions/src/components/WorkflowRunStatus/index.ts
index 05fff3f46d..8ebca32cbd 100644
--- a/plugins/github-actions/src/components/WorkflowRunStatusIcon/index.ts
+++ b/plugins/github-actions/src/components/WorkflowRunStatus/index.ts
@@ -14,4 +14,4 @@
* limitations under the License.
*/
-export { WorkflowRunStatusIcon } from './WorkflowRunStatusIcon';
+export { WorkflowRunStatus } from './WorkflowRunStatus';
diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx
index 313a51e28a..a2a6ead9b5 100644
--- a/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx
+++ b/plugins/github-actions/src/components/WorkflowRunsTable/WorkflowRunsTable.tsx
@@ -17,16 +17,20 @@ import React, { FC } from 'react';
import { Link, Typography, Box, IconButton, Tooltip } from '@material-ui/core';
import RetryIcon from '@material-ui/icons/Replay';
import GitHubIcon from '@material-ui/icons/GitHub';
-import { Link as RouterLink } from 'react-router-dom';
+import { Link as RouterLink, generatePath } from 'react-router-dom';
import { Table, TableColumn } from '@backstage/core';
-import { useWorkflowRuns } from './useWorkflowRuns';
-import { WorkflowRunStatusIcon } from '../WorkflowRunStatusIcon';
+import { useWorkflowRuns } from '../useWorkflowRuns';
+import { WorkflowRunStatus } from '../WorkflowRunStatus';
import SyncIcon from '@material-ui/icons/Sync';
+import { buildRouteRef } from '../../plugin';
+import { useEntityCompoundName } from '@backstage/plugin-catalog';
+import { useProjectName } from '../useProjectName';
export type WorkflowRun = {
id: string;
message: string;
url?: string;
+ githubUrl?: string;
source: {
branchName: string;
commit: {
@@ -52,7 +56,7 @@ const generatedColumns: TableColumn[] = [
render: (row: Partial) => (
{row.message}
@@ -69,13 +73,11 @@ const generatedColumns: TableColumn[] = [
},
{
title: 'Status',
+ width: '150px',
+
render: (row: Partial) => (
-
-
-
- {row.status}
-
+
),
},
@@ -104,7 +106,7 @@ type Props = {
onChangePageSize: (pageSize: number) => void;
};
-const WorkflowRunsTableView: FC = ({
+export const WorkflowRunsTableView: FC = ({
projectName,
loading,
pageSize,
@@ -145,10 +147,28 @@ const WorkflowRunsTableView: FC = ({
};
export const WorkflowRunsTable = () => {
- const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns();
+ let entityCompoundName = useEntityCompoundName();
+
+ if (!entityCompoundName.name) {
+ // TODO(shmidt-i): remove when is fully integrated
+ // into the entity view
+ entityCompoundName = {
+ kind: 'Component',
+ name: 'backstage',
+ namespace: 'default',
+ };
+ }
+
+ const { value: projectName, loading } = useProjectName(entityCompoundName);
+ const [owner, repo] = (projectName ?? '/').split('/');
+ const [tableProps, { retry, setPage, setPageSize }] = useWorkflowRuns({
+ owner,
+ repo,
+ });
return (
{
const catalogApi = useApi(catalogApiRef);
- const { value } = useAsync(async () => {
+ const { value, loading, error } = useAsync(async () => {
const entity = await catalogApi.getEntityByName(name);
return entity?.metadata.annotations?.['github.com/project-slug'] ?? '';
});
- return value;
+ return { value, loading, error };
};
diff --git a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts b/plugins/github-actions/src/components/useWorkflowRuns.ts
similarity index 81%
rename from plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts
rename to plugins/github-actions/src/components/useWorkflowRuns.ts
index 4f72f88de0..f935d57810 100644
--- a/plugins/github-actions/src/components/WorkflowRunsTable/useWorkflowRuns.ts
+++ b/plugins/github-actions/src/components/useWorkflowRuns.ts
@@ -15,13 +15,20 @@
*/
import { useState } from 'react';
import { useAsyncRetry } from 'react-use';
-import { WorkflowRun } from './WorkflowRunsTable';
-import { githubActionsApiRef } from '../../api/GithubActionsApi';
+import { WorkflowRun } from './WorkflowRunsTable/WorkflowRunsTable';
+import { githubActionsApiRef } from '../api/GithubActionsApi';
import { useApi, githubAuthApiRef, errorApiRef } from '@backstage/core';
import { ActionsListWorkflowRunsForRepoResponseData } from '@octokit/types';
-import { useProjectName } from '../useProjectName';
-export function useWorkflowRuns() {
+export function useWorkflowRuns({
+ owner,
+ repo,
+ branch,
+}: {
+ owner: string;
+ repo: string;
+ branch?: string;
+}) {
const api = useApi(githubActionsApiRef);
const auth = useApi(githubAuthApiRef);
@@ -31,19 +38,21 @@ export function useWorkflowRuns() {
const [page, setPage] = useState(0);
const [pageSize, setPageSize] = useState(5);
- const projectName = useProjectName({
- kind: 'Component',
- name: 'backstage',
- });
- const { loading, value: runs, retry } = useAsyncRetry<
+ const { loading, value: runs, retry, error } = useAsyncRetry<
WorkflowRun[]
>(async () => {
const token = await auth.getAccessToken(['repo']);
- const [owner, repo] = (projectName ?? '/').split('/');
return (
api
// GitHub API pagination count starts from 1
- .listWorkflowRuns({ token, owner, repo, pageSize, page: page + 1 })
+ .listWorkflowRuns({
+ token,
+ owner,
+ repo,
+ pageSize,
+ page: page + 1,
+ branch,
+ })
.then(
(
workflowRunsData: ActionsListWorkflowRunsForRepoResponseData,
@@ -77,11 +86,12 @@ export function useWorkflowRuns() {
},
status: run.status,
url: run.url,
+ githubUrl: run.html_url,
}));
},
)
);
- }, [page, pageSize, projectName]);
+ }, [page, pageSize, repo, owner]);
return [
{
@@ -89,8 +99,9 @@ export function useWorkflowRuns() {
pageSize,
loading,
runs,
- projectName: projectName ?? '',
+ projectName: `${owner}/${repo}`,
total,
+ error,
},
{
runs,
diff --git a/plugins/github-actions/src/index.ts b/plugins/github-actions/src/index.ts
index d67bc6a864..4a69c363cd 100644
--- a/plugins/github-actions/src/index.ts
+++ b/plugins/github-actions/src/index.ts
@@ -16,3 +16,4 @@
export { plugin } from './plugin';
export * from './api';
+export { Widget } from './components/Widget';