@backstage-community/plugin-github-actions 0.6.16 → 0.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/api/GithubActionsApi.esm.js +8 -0
- package/dist/api/GithubActionsApi.esm.js.map +1 -0
- package/dist/api/GithubActionsClient.esm.js +113 -0
- package/dist/api/GithubActionsClient.esm.js.map +1 -0
- package/dist/api/types.esm.js +10 -0
- package/dist/api/types.esm.js.map +1 -0
- package/dist/components/Cards/Cards.esm.js +78 -0
- package/dist/components/Cards/Cards.esm.js.map +1 -0
- package/dist/components/Cards/RecentWorkflowRunsCard.esm.js +71 -0
- package/dist/components/Cards/RecentWorkflowRunsCard.esm.js.map +1 -0
- package/dist/components/Cards/index.esm.js +3 -0
- package/dist/components/Cards/index.esm.js.map +1 -0
- package/dist/components/Router.esm.js +28 -0
- package/dist/components/Router.esm.js.map +1 -0
- package/dist/components/WorkflowRunDetails/WorkflowRunDetails.esm.js +128 -0
- package/dist/components/WorkflowRunDetails/WorkflowRunDetails.esm.js.map +1 -0
- package/dist/components/WorkflowRunDetails/useWorkflowRunJobs.esm.js +49 -0
- package/dist/components/WorkflowRunDetails/useWorkflowRunJobs.esm.js.map +1 -0
- package/dist/components/WorkflowRunDetails/useWorkflowRunsDetails.esm.js +27 -0
- package/dist/components/WorkflowRunDetails/useWorkflowRunsDetails.esm.js.map +1 -0
- package/dist/components/WorkflowRunLogs/WorkflowRunLogs.esm.js +106 -0
- package/dist/components/WorkflowRunLogs/WorkflowRunLogs.esm.js.map +1 -0
- package/dist/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.esm.js +26 -0
- package/dist/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.esm.js.map +1 -0
- package/dist/components/WorkflowRunStatus/WorkflowRunStatus.esm.js +61 -0
- package/dist/components/WorkflowRunStatus/WorkflowRunStatus.esm.js.map +1 -0
- package/dist/components/WorkflowRunsCard/WorkflowRunsCard.esm.js +296 -0
- package/dist/components/WorkflowRunsCard/WorkflowRunsCard.esm.js.map +1 -0
- package/dist/components/WorkflowRunsTable/WorkflowRunsTable.esm.js +139 -0
- package/dist/components/WorkflowRunsTable/WorkflowRunsTable.esm.js.map +1 -0
- package/dist/components/getHostnameFromEntity.esm.js +10 -0
- package/dist/components/getHostnameFromEntity.esm.js.map +1 -0
- package/dist/components/getProjectNameFromEntity.esm.js +5 -0
- package/dist/components/getProjectNameFromEntity.esm.js.map +1 -0
- package/dist/components/useWorkflowRuns.esm.js +122 -0
- package/dist/components/useWorkflowRuns.esm.js.map +1 -0
- package/dist/index.esm.js +8 -1237
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin.esm.js +55 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/routes.esm.js +13 -0
- package/dist/routes.esm.js.map +1 -0
- package/package.json +16 -12
- package/dist/esm/index-CRpdBPJi.esm.js +0 -50
- package/dist/esm/index-CRpdBPJi.esm.js.map +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
2
|
+
import { githubActionsApiRef } from '../../api/GithubActionsApi.esm.js';
|
|
3
|
+
import '@backstage/integration';
|
|
4
|
+
import '@octokit/rest';
|
|
5
|
+
import { buildRouteRef } from '../../routes.esm.js';
|
|
6
|
+
import { useApi, useRouteRefParams } from '@backstage/core-plugin-api';
|
|
7
|
+
|
|
8
|
+
const useWorkflowRunJobs = ({
|
|
9
|
+
hostname,
|
|
10
|
+
owner,
|
|
11
|
+
repo
|
|
12
|
+
}) => {
|
|
13
|
+
const api = useApi(githubActionsApiRef);
|
|
14
|
+
const { id } = useRouteRefParams(buildRouteRef);
|
|
15
|
+
return useAsync(async () => {
|
|
16
|
+
if (!repo || !owner) {
|
|
17
|
+
throw new Error("No repo/owner provided");
|
|
18
|
+
}
|
|
19
|
+
const jobs = await api.listJobsForWorkflowRun({
|
|
20
|
+
hostname,
|
|
21
|
+
owner,
|
|
22
|
+
repo,
|
|
23
|
+
id: parseInt(id, 10)
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
total_count: jobs.total_count,
|
|
27
|
+
jobs: jobs.jobs.map((job) => ({
|
|
28
|
+
html_url: job.html_url ?? void 0,
|
|
29
|
+
status: job.status,
|
|
30
|
+
conclusion: job.conclusion ?? void 0,
|
|
31
|
+
started_at: job.started_at,
|
|
32
|
+
completed_at: job.completed_at ?? void 0,
|
|
33
|
+
id: job.id,
|
|
34
|
+
name: job.name,
|
|
35
|
+
steps: job.steps?.map((step) => ({
|
|
36
|
+
name: step.name,
|
|
37
|
+
status: step.status,
|
|
38
|
+
conclusion: step.conclusion ?? void 0,
|
|
39
|
+
number: step.number,
|
|
40
|
+
started_at: step.started_at ?? void 0,
|
|
41
|
+
completed_at: step.completed_at ?? void 0
|
|
42
|
+
}))
|
|
43
|
+
}))
|
|
44
|
+
};
|
|
45
|
+
}, [repo, owner, id]);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export { useWorkflowRunJobs };
|
|
49
|
+
//# sourceMappingURL=useWorkflowRunJobs.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkflowRunJobs.esm.js","sources":["../../../src/components/WorkflowRunDetails/useWorkflowRunJobs.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport useAsync, { AsyncState } from 'react-use/esm/useAsync';\nimport { githubActionsApiRef, Job, Jobs, Step } from '../../api';\nimport { buildRouteRef } from '../../routes';\nimport { useApi, useRouteRefParams } from '@backstage/core-plugin-api';\n\nexport const useWorkflowRunJobs = ({\n hostname,\n owner,\n repo,\n}: {\n hostname?: string;\n owner: string;\n repo: string;\n}): AsyncState<Jobs> => {\n const api = useApi(githubActionsApiRef);\n const { id } = useRouteRefParams(buildRouteRef);\n\n return useAsync(async () => {\n if (!repo || !owner) {\n throw new Error('No repo/owner provided');\n }\n\n const jobs = await api.listJobsForWorkflowRun({\n hostname,\n owner,\n repo,\n id: parseInt(id, 10),\n });\n\n return {\n total_count: jobs.total_count,\n jobs: jobs.jobs.map<Job>(job => ({\n html_url: job.html_url ?? undefined,\n status: job.status,\n conclusion: job.conclusion ?? undefined,\n started_at: job.started_at,\n completed_at: job.completed_at ?? undefined,\n id: job.id,\n name: job.name,\n steps: job.steps?.map<Step>(step => ({\n name: step.name,\n status: step.status,\n conclusion: step.conclusion ?? undefined,\n number: step.number,\n started_at: step.started_at ?? undefined,\n completed_at: step.completed_at ?? undefined,\n })),\n })),\n };\n }, [repo, owner, id]);\n};\n"],"names":[],"mappings":";;;;;;;AAoBO,MAAM,qBAAqB,CAAC;AAAA,EACjC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AACF,CAIwB,KAAA;AACtB,EAAM,MAAA,GAAA,GAAM,OAAO,mBAAmB,CAAA,CAAA;AACtC,EAAA,MAAM,EAAE,EAAA,EAAO,GAAA,iBAAA,CAAkB,aAAa,CAAA,CAAA;AAE9C,EAAA,OAAO,SAAS,YAAY;AAC1B,IAAI,IAAA,CAAC,IAAQ,IAAA,CAAC,KAAO,EAAA;AACnB,MAAM,MAAA,IAAI,MAAM,wBAAwB,CAAA,CAAA;AAAA,KAC1C;AAEA,IAAM,MAAA,IAAA,GAAO,MAAM,GAAA,CAAI,sBAAuB,CAAA;AAAA,MAC5C,QAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,EAAA,EAAI,QAAS,CAAA,EAAA,EAAI,EAAE,CAAA;AAAA,KACpB,CAAA,CAAA;AAED,IAAO,OAAA;AAAA,MACL,aAAa,IAAK,CAAA,WAAA;AAAA,MAClB,IAAM,EAAA,IAAA,CAAK,IAAK,CAAA,GAAA,CAAS,CAAQ,GAAA,MAAA;AAAA,QAC/B,QAAA,EAAU,IAAI,QAAY,IAAA,KAAA,CAAA;AAAA,QAC1B,QAAQ,GAAI,CAAA,MAAA;AAAA,QACZ,UAAA,EAAY,IAAI,UAAc,IAAA,KAAA,CAAA;AAAA,QAC9B,YAAY,GAAI,CAAA,UAAA;AAAA,QAChB,YAAA,EAAc,IAAI,YAAgB,IAAA,KAAA,CAAA;AAAA,QAClC,IAAI,GAAI,CAAA,EAAA;AAAA,QACR,MAAM,GAAI,CAAA,IAAA;AAAA,QACV,KAAO,EAAA,GAAA,CAAI,KAAO,EAAA,GAAA,CAAU,CAAS,IAAA,MAAA;AAAA,UACnC,MAAM,IAAK,CAAA,IAAA;AAAA,UACX,QAAQ,IAAK,CAAA,MAAA;AAAA,UACb,UAAA,EAAY,KAAK,UAAc,IAAA,KAAA,CAAA;AAAA,UAC/B,QAAQ,IAAK,CAAA,MAAA;AAAA,UACb,UAAA,EAAY,KAAK,UAAc,IAAA,KAAA,CAAA;AAAA,UAC/B,YAAA,EAAc,KAAK,YAAgB,IAAA,KAAA,CAAA;AAAA,SACnC,CAAA,CAAA;AAAA,OACF,CAAA,CAAA;AAAA,KACJ,CAAA;AAAA,GACC,EAAA,CAAC,IAAM,EAAA,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AACtB;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
2
|
+
import { githubActionsApiRef } from '../../api/GithubActionsApi.esm.js';
|
|
3
|
+
import '@backstage/integration';
|
|
4
|
+
import '@octokit/rest';
|
|
5
|
+
import { buildRouteRef } from '../../routes.esm.js';
|
|
6
|
+
import { useApi, useRouteRefParams } from '@backstage/core-plugin-api';
|
|
7
|
+
|
|
8
|
+
const useWorkflowRunsDetails = ({
|
|
9
|
+
hostname,
|
|
10
|
+
owner,
|
|
11
|
+
repo
|
|
12
|
+
}) => {
|
|
13
|
+
const api = useApi(githubActionsApiRef);
|
|
14
|
+
const { id } = useRouteRefParams(buildRouteRef);
|
|
15
|
+
const details = useAsync(async () => {
|
|
16
|
+
return repo && owner ? api.getWorkflowRun({
|
|
17
|
+
hostname,
|
|
18
|
+
owner,
|
|
19
|
+
repo,
|
|
20
|
+
id: parseInt(id, 10)
|
|
21
|
+
}) : Promise.reject(new Error("No repo/owner provided"));
|
|
22
|
+
}, [repo, owner, id]);
|
|
23
|
+
return details;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { useWorkflowRunsDetails };
|
|
27
|
+
//# sourceMappingURL=useWorkflowRunsDetails.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWorkflowRunsDetails.esm.js","sources":["../../../src/components/WorkflowRunDetails/useWorkflowRunsDetails.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport useAsync from 'react-use/esm/useAsync';\nimport { githubActionsApiRef } from '../../api';\nimport { buildRouteRef } from '../../routes';\nimport { useApi, useRouteRefParams } from '@backstage/core-plugin-api';\n\nexport const useWorkflowRunsDetails = ({\n hostname,\n owner,\n repo,\n}: {\n hostname?: string;\n owner: string;\n repo: string;\n}) => {\n const api = useApi(githubActionsApiRef);\n const { id } = useRouteRefParams(buildRouteRef);\n const details = useAsync(async () => {\n return repo && owner\n ? api.getWorkflowRun({\n hostname,\n owner,\n repo,\n id: parseInt(id, 10),\n })\n : Promise.reject(new Error('No repo/owner provided'));\n }, [repo, owner, id]);\n return details;\n};\n"],"names":[],"mappings":";;;;;;;AAoBO,MAAM,yBAAyB,CAAC;AAAA,EACrC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AACF,CAIM,KAAA;AACJ,EAAM,MAAA,GAAA,GAAM,OAAO,mBAAmB,CAAA,CAAA;AACtC,EAAA,MAAM,EAAE,EAAA,EAAO,GAAA,iBAAA,CAAkB,aAAa,CAAA,CAAA;AAC9C,EAAM,MAAA,OAAA,GAAU,SAAS,YAAY;AACnC,IAAO,OAAA,IAAA,IAAQ,KACX,GAAA,GAAA,CAAI,cAAe,CAAA;AAAA,MACjB,QAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,EAAA,EAAI,QAAS,CAAA,EAAA,EAAI,EAAE,CAAA;AAAA,KACpB,CACD,GAAA,OAAA,CAAQ,OAAO,IAAI,KAAA,CAAM,wBAAwB,CAAC,CAAA,CAAA;AAAA,GACrD,EAAA,CAAC,IAAM,EAAA,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AACpB,EAAO,OAAA,OAAA,CAAA;AACT;;;;"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { LogViewer } from '@backstage/core-components';
|
|
2
|
+
import Accordion from '@material-ui/core/Accordion';
|
|
3
|
+
import AccordionSummary from '@material-ui/core/AccordionSummary';
|
|
4
|
+
import CircularProgress from '@material-ui/core/CircularProgress';
|
|
5
|
+
import Fade from '@material-ui/core/Fade';
|
|
6
|
+
import Modal from '@material-ui/core/Modal';
|
|
7
|
+
import Tooltip from '@material-ui/core/Tooltip';
|
|
8
|
+
import Typography from '@material-ui/core/Typography';
|
|
9
|
+
import Zoom from '@material-ui/core/Zoom';
|
|
10
|
+
import { makeStyles } from '@material-ui/core/styles';
|
|
11
|
+
import DescriptionIcon from '@material-ui/icons/Description';
|
|
12
|
+
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { getProjectNameFromEntity } from '../getProjectNameFromEntity.esm.js';
|
|
15
|
+
import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs.esm.js';
|
|
16
|
+
import { getHostnameFromEntity } from '../getHostnameFromEntity.esm.js';
|
|
17
|
+
|
|
18
|
+
const useStyles = makeStyles((theme) => ({
|
|
19
|
+
button: {
|
|
20
|
+
order: -1,
|
|
21
|
+
marginRight: 0,
|
|
22
|
+
marginLeft: "-20px"
|
|
23
|
+
},
|
|
24
|
+
modal: {
|
|
25
|
+
display: "flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
width: "85%",
|
|
28
|
+
height: "85%",
|
|
29
|
+
justifyContent: "center",
|
|
30
|
+
margin: "auto"
|
|
31
|
+
},
|
|
32
|
+
normalLogContainer: {
|
|
33
|
+
height: "75vh",
|
|
34
|
+
width: "100%"
|
|
35
|
+
},
|
|
36
|
+
modalLogContainer: {
|
|
37
|
+
height: "100%",
|
|
38
|
+
width: "100%"
|
|
39
|
+
},
|
|
40
|
+
log: {
|
|
41
|
+
background: theme.palette.background.default
|
|
42
|
+
}
|
|
43
|
+
}));
|
|
44
|
+
const WorkflowRunLogs = ({
|
|
45
|
+
entity,
|
|
46
|
+
runId,
|
|
47
|
+
inProgress
|
|
48
|
+
}) => {
|
|
49
|
+
const classes = useStyles();
|
|
50
|
+
const projectName = getProjectNameFromEntity(entity);
|
|
51
|
+
const hostname = getHostnameFromEntity(entity);
|
|
52
|
+
const [owner, repo] = projectName && projectName.split("/") || [];
|
|
53
|
+
const jobLogs = useDownloadWorkflowRunLogs({
|
|
54
|
+
hostname,
|
|
55
|
+
owner,
|
|
56
|
+
repo,
|
|
57
|
+
id: runId
|
|
58
|
+
});
|
|
59
|
+
const logText = jobLogs.value ? String(jobLogs.value) : void 0;
|
|
60
|
+
const [open, setOpen] = React.useState(false);
|
|
61
|
+
const handleOpen = () => {
|
|
62
|
+
setOpen(true);
|
|
63
|
+
};
|
|
64
|
+
const handleClose = () => {
|
|
65
|
+
setOpen(false);
|
|
66
|
+
};
|
|
67
|
+
return /* @__PURE__ */ React.createElement(Accordion, { TransitionProps: { unmountOnExit: true }, disabled: inProgress }, /* @__PURE__ */ React.createElement(
|
|
68
|
+
AccordionSummary,
|
|
69
|
+
{
|
|
70
|
+
expandIcon: /* @__PURE__ */ React.createElement(ExpandMoreIcon, null),
|
|
71
|
+
IconButtonProps: {
|
|
72
|
+
className: classes.button
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
/* @__PURE__ */ React.createElement(Typography, { variant: "button" }, jobLogs.loading ? /* @__PURE__ */ React.createElement(CircularProgress, null) : "Job Log"),
|
|
76
|
+
/* @__PURE__ */ React.createElement(Tooltip, { title: "Open Log", TransitionComponent: Zoom, arrow: true }, /* @__PURE__ */ React.createElement(
|
|
77
|
+
DescriptionIcon,
|
|
78
|
+
{
|
|
79
|
+
onClick: (event) => {
|
|
80
|
+
event.stopPropagation();
|
|
81
|
+
handleOpen();
|
|
82
|
+
},
|
|
83
|
+
style: { marginLeft: "auto" }
|
|
84
|
+
}
|
|
85
|
+
)),
|
|
86
|
+
/* @__PURE__ */ React.createElement(
|
|
87
|
+
Modal,
|
|
88
|
+
{
|
|
89
|
+
className: classes.modal,
|
|
90
|
+
onClick: (event) => event.stopPropagation(),
|
|
91
|
+
open,
|
|
92
|
+
onClose: handleClose
|
|
93
|
+
},
|
|
94
|
+
/* @__PURE__ */ React.createElement(Fade, { in: open }, /* @__PURE__ */ React.createElement("div", { className: classes.modalLogContainer }, /* @__PURE__ */ React.createElement(
|
|
95
|
+
LogViewer,
|
|
96
|
+
{
|
|
97
|
+
text: logText ?? "No Values Found",
|
|
98
|
+
classes: { root: classes.log }
|
|
99
|
+
}
|
|
100
|
+
)))
|
|
101
|
+
)
|
|
102
|
+
), logText && /* @__PURE__ */ React.createElement("div", { className: classes.normalLogContainer }, /* @__PURE__ */ React.createElement(LogViewer, { text: logText, classes: { root: classes.log } })));
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export { WorkflowRunLogs };
|
|
106
|
+
//# sourceMappingURL=WorkflowRunLogs.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowRunLogs.esm.js","sources":["../../../src/components/WorkflowRunLogs/WorkflowRunLogs.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { LogViewer } from '@backstage/core-components';\nimport Accordion from '@material-ui/core/Accordion';\nimport AccordionSummary from '@material-ui/core/AccordionSummary';\nimport CircularProgress from '@material-ui/core/CircularProgress';\nimport Fade from '@material-ui/core/Fade';\nimport Modal from '@material-ui/core/Modal';\nimport Tooltip from '@material-ui/core/Tooltip';\nimport Typography from '@material-ui/core/Typography';\nimport Zoom from '@material-ui/core/Zoom';\nimport { makeStyles } from '@material-ui/core/styles';\nimport DescriptionIcon from '@material-ui/icons/Description';\nimport ExpandMoreIcon from '@material-ui/icons/ExpandMore';\nimport React from 'react';\nimport { getProjectNameFromEntity } from '../getProjectNameFromEntity';\nimport { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs';\nimport { getHostnameFromEntity } from '../getHostnameFromEntity';\n\nconst useStyles = makeStyles(theme => ({\n button: {\n order: -1,\n marginRight: 0,\n marginLeft: '-20px',\n },\n modal: {\n display: 'flex',\n alignItems: 'center',\n width: '85%',\n height: '85%',\n justifyContent: 'center',\n margin: 'auto',\n },\n normalLogContainer: {\n height: '75vh',\n width: '100%',\n },\n modalLogContainer: {\n height: '100%',\n width: '100%',\n },\n log: {\n background: theme.palette.background.default,\n },\n}));\n\n/**\n * A component for Run Logs visualization.\n */\nexport const WorkflowRunLogs = ({\n entity,\n runId,\n inProgress,\n}: {\n entity: Entity;\n runId: number;\n inProgress: boolean;\n}) => {\n const classes = useStyles();\n const projectName = getProjectNameFromEntity(entity);\n\n const hostname = getHostnameFromEntity(entity);\n const [owner, repo] = (projectName && projectName.split('/')) || [];\n const jobLogs = useDownloadWorkflowRunLogs({\n hostname,\n owner,\n repo,\n id: runId,\n });\n const logText = jobLogs.value ? String(jobLogs.value) : undefined;\n const [open, setOpen] = React.useState(false);\n\n const handleOpen = () => {\n setOpen(true);\n };\n\n const handleClose = () => {\n setOpen(false);\n };\n\n return (\n <Accordion TransitionProps={{ unmountOnExit: true }} disabled={inProgress}>\n <AccordionSummary\n expandIcon={<ExpandMoreIcon />}\n IconButtonProps={{\n className: classes.button,\n }}\n >\n <Typography variant=\"button\">\n {jobLogs.loading ? <CircularProgress /> : 'Job Log'}\n </Typography>\n <Tooltip title=\"Open Log\" TransitionComponent={Zoom} arrow>\n <DescriptionIcon\n onClick={event => {\n event.stopPropagation();\n handleOpen();\n }}\n style={{ marginLeft: 'auto' }}\n />\n </Tooltip>\n <Modal\n className={classes.modal}\n onClick={event => event.stopPropagation()}\n open={open}\n onClose={handleClose}\n >\n <Fade in={open}>\n <div className={classes.modalLogContainer}>\n <LogViewer\n text={logText ?? 'No Values Found'}\n classes={{ root: classes.log }}\n />\n </div>\n </Fade>\n </Modal>\n </AccordionSummary>\n {logText && (\n <div className={classes.normalLogContainer}>\n <LogViewer text={logText} classes={{ root: classes.log }} />\n </div>\n )}\n </Accordion>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
2
|
+
import { githubActionsApiRef } from '../../api/GithubActionsApi.esm.js';
|
|
3
|
+
import '@backstage/integration';
|
|
4
|
+
import '@octokit/rest';
|
|
5
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
6
|
+
|
|
7
|
+
const useDownloadWorkflowRunLogs = ({
|
|
8
|
+
hostname,
|
|
9
|
+
owner,
|
|
10
|
+
repo,
|
|
11
|
+
id
|
|
12
|
+
}) => {
|
|
13
|
+
const api = useApi(githubActionsApiRef);
|
|
14
|
+
const details = useAsync(async () => {
|
|
15
|
+
return repo && owner ? api.downloadJobLogsForWorkflowRun({
|
|
16
|
+
hostname,
|
|
17
|
+
owner,
|
|
18
|
+
repo,
|
|
19
|
+
runId: id
|
|
20
|
+
}) : Promise.reject("No repo/owner provided");
|
|
21
|
+
}, [repo, owner, id]);
|
|
22
|
+
return details;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export { useDownloadWorkflowRunLogs };
|
|
26
|
+
//# sourceMappingURL=useDownloadWorkflowRunLogs.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDownloadWorkflowRunLogs.esm.js","sources":["../../../src/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport useAsync from 'react-use/esm/useAsync';\nimport { githubActionsApiRef } from '../../api';\nimport { useApi } from '@backstage/core-plugin-api';\n\nexport const useDownloadWorkflowRunLogs = ({\n hostname,\n owner,\n repo,\n id,\n}: {\n hostname?: string;\n owner: string;\n repo: string;\n id: number;\n}) => {\n const api = useApi(githubActionsApiRef);\n const details = useAsync(async () => {\n return repo && owner\n ? api.downloadJobLogsForWorkflowRun({\n hostname,\n owner,\n repo,\n runId: id,\n })\n : Promise.reject('No repo/owner provided');\n }, [repo, owner, id]);\n return details;\n};\n"],"names":[],"mappings":";;;;;;AAoBO,MAAM,6BAA6B,CAAC;AAAA,EACzC,QAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,EAAA;AACF,CAKM,KAAA;AACJ,EAAM,MAAA,GAAA,GAAM,OAAO,mBAAmB,CAAA,CAAA;AACtC,EAAM,MAAA,OAAA,GAAU,SAAS,YAAY;AACnC,IAAO,OAAA,IAAA,IAAQ,KACX,GAAA,GAAA,CAAI,6BAA8B,CAAA;AAAA,MAChC,QAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,KAAO,EAAA,EAAA;AAAA,KACR,CAAA,GACD,OAAQ,CAAA,MAAA,CAAO,wBAAwB,CAAA,CAAA;AAAA,GAC1C,EAAA,CAAC,IAAM,EAAA,KAAA,EAAO,EAAE,CAAC,CAAA,CAAA;AACpB,EAAO,OAAA,OAAA,CAAA;AACT;;;;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StatusPending, StatusOK, StatusError, StatusWarning, StatusAborted, StatusRunning } from '@backstage/core-components';
|
|
3
|
+
|
|
4
|
+
const WorkflowRunStatus = (props) => {
|
|
5
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(WorkflowIcon, { ...props }), getStatusDescription(props));
|
|
6
|
+
};
|
|
7
|
+
function WorkflowIcon({
|
|
8
|
+
status,
|
|
9
|
+
conclusion
|
|
10
|
+
}) {
|
|
11
|
+
if (status === void 0) return null;
|
|
12
|
+
switch (status.toLocaleLowerCase("en-US")) {
|
|
13
|
+
case "queued":
|
|
14
|
+
return /* @__PURE__ */ React.createElement(StatusPending, null);
|
|
15
|
+
case "in_progress":
|
|
16
|
+
return /* @__PURE__ */ React.createElement(StatusRunning, null);
|
|
17
|
+
case "completed":
|
|
18
|
+
switch (conclusion?.toLocaleLowerCase("en-US")) {
|
|
19
|
+
case "skipped":
|
|
20
|
+
case "cancelled":
|
|
21
|
+
return /* @__PURE__ */ React.createElement(StatusAborted, null);
|
|
22
|
+
case "timed_out":
|
|
23
|
+
return /* @__PURE__ */ React.createElement(StatusWarning, null);
|
|
24
|
+
case "failure":
|
|
25
|
+
return /* @__PURE__ */ React.createElement(StatusError, null);
|
|
26
|
+
default:
|
|
27
|
+
return /* @__PURE__ */ React.createElement(StatusOK, null);
|
|
28
|
+
}
|
|
29
|
+
default:
|
|
30
|
+
return /* @__PURE__ */ React.createElement(StatusPending, null);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function getStatusDescription({
|
|
34
|
+
status,
|
|
35
|
+
conclusion
|
|
36
|
+
}) {
|
|
37
|
+
if (status === void 0) return "";
|
|
38
|
+
switch (status.toLocaleLowerCase("en-US")) {
|
|
39
|
+
case "queued":
|
|
40
|
+
return "Queued";
|
|
41
|
+
case "in_progress":
|
|
42
|
+
return "In progress";
|
|
43
|
+
case "completed":
|
|
44
|
+
switch (conclusion?.toLocaleLowerCase("en-US")) {
|
|
45
|
+
case "skipped":
|
|
46
|
+
case "cancelled":
|
|
47
|
+
return "Aborted";
|
|
48
|
+
case "timed_out":
|
|
49
|
+
return "Timed out";
|
|
50
|
+
case "failure":
|
|
51
|
+
return "Error";
|
|
52
|
+
default:
|
|
53
|
+
return "Completed";
|
|
54
|
+
}
|
|
55
|
+
default:
|
|
56
|
+
return "Pending";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { WorkflowIcon, WorkflowRunStatus, getStatusDescription };
|
|
61
|
+
//# sourceMappingURL=WorkflowRunStatus.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowRunStatus.esm.js","sources":["../../../src/components/WorkflowRunStatus/WorkflowRunStatus.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport {\n StatusPending,\n StatusRunning,\n StatusOK,\n StatusWarning,\n StatusAborted,\n StatusError,\n} from '@backstage/core-components';\n\nexport const WorkflowRunStatus = (props: {\n status?: string;\n conclusion?: string;\n}) => {\n return (\n <>\n <WorkflowIcon {...props} />\n {getStatusDescription(props)}\n </>\n );\n};\n\nexport function WorkflowIcon({\n status,\n conclusion,\n}: {\n status?: string;\n conclusion?: string;\n}) {\n if (status === undefined) return null;\n switch (status.toLocaleLowerCase('en-US')) {\n case 'queued':\n return <StatusPending />;\n\n case 'in_progress':\n return <StatusRunning />;\n case 'completed':\n switch (conclusion?.toLocaleLowerCase('en-US')) {\n case 'skipped':\n case 'cancelled':\n return <StatusAborted />;\n\n case 'timed_out':\n return <StatusWarning />;\n case 'failure':\n return <StatusError />;\n default:\n return <StatusOK />;\n }\n default:\n return <StatusPending />;\n }\n}\n\nexport function getStatusDescription({\n status,\n conclusion,\n}: {\n status?: string;\n conclusion?: string;\n}) {\n if (status === undefined) return '';\n switch (status.toLocaleLowerCase('en-US')) {\n case 'queued':\n return 'Queued';\n case 'in_progress':\n return 'In progress';\n case 'completed':\n switch (conclusion?.toLocaleLowerCase('en-US')) {\n case 'skipped':\n case 'cancelled':\n return 'Aborted';\n case 'timed_out':\n return 'Timed out';\n case 'failure':\n return 'Error';\n default:\n return 'Completed';\n }\n default:\n return 'Pending';\n }\n}\n"],"names":[],"mappings":";;;AA0Ba,MAAA,iBAAA,GAAoB,CAAC,KAG5B,KAAA;AACJ,EACE,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,sCACG,YAAc,EAAA,EAAA,GAAG,OAAO,CACxB,EAAA,oBAAA,CAAqB,KAAK,CAC7B,CAAA,CAAA;AAEJ,EAAA;AAEO,SAAS,YAAa,CAAA;AAAA,EAC3B,MAAA;AAAA,EACA,UAAA;AACF,CAGG,EAAA;AACD,EAAI,IAAA,MAAA,KAAW,QAAkB,OAAA,IAAA,CAAA;AACjC,EAAQ,QAAA,MAAA,CAAO,iBAAkB,CAAA,OAAO,CAAG;AAAA,IACzC,KAAK,QAAA;AACH,MAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AAAA,IAExB,KAAK,aAAA;AACH,MAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AAAA,IACxB,KAAK,WAAA;AACH,MAAQ,QAAA,UAAA,EAAY,iBAAkB,CAAA,OAAO,CAAG;AAAA,QAC9C,KAAK,SAAA,CAAA;AAAA,QACL,KAAK,WAAA;AACH,UAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AAAA,QAExB,KAAK,WAAA;AACH,UAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AAAA,QACxB,KAAK,SAAA;AACH,UAAA,2CAAQ,WAAY,EAAA,IAAA,CAAA,CAAA;AAAA,QACtB;AACE,UAAA,2CAAQ,QAAS,EAAA,IAAA,CAAA,CAAA;AAAA,OACrB;AAAA,IACF;AACE,MAAA,2CAAQ,aAAc,EAAA,IAAA,CAAA,CAAA;AAAA,GAC1B;AACF,CAAA;AAEO,SAAS,oBAAqB,CAAA;AAAA,EACnC,MAAA;AAAA,EACA,UAAA;AACF,CAGG,EAAA;AACD,EAAI,IAAA,MAAA,KAAW,QAAkB,OAAA,EAAA,CAAA;AACjC,EAAQ,QAAA,MAAA,CAAO,iBAAkB,CAAA,OAAO,CAAG;AAAA,IACzC,KAAK,QAAA;AACH,MAAO,OAAA,QAAA,CAAA;AAAA,IACT,KAAK,aAAA;AACH,MAAO,OAAA,aAAA,CAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAQ,QAAA,UAAA,EAAY,iBAAkB,CAAA,OAAO,CAAG;AAAA,QAC9C,KAAK,SAAA,CAAA;AAAA,QACL,KAAK,WAAA;AACH,UAAO,OAAA,SAAA,CAAA;AAAA,QACT,KAAK,WAAA;AACH,UAAO,OAAA,WAAA,CAAA;AAAA,QACT,KAAK,SAAA;AACH,UAAO,OAAA,OAAA,CAAA;AAAA,QACT;AACE,UAAO,OAAA,WAAA,CAAA;AAAA,OACX;AAAA,IACF;AACE,MAAO,OAAA,SAAA,CAAA;AAAA,GACX;AACF;;;;"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import Typography from '@material-ui/core/Typography';
|
|
3
|
+
import Box from '@material-ui/core/Box';
|
|
4
|
+
import IconButton from '@material-ui/core/IconButton';
|
|
5
|
+
import Tooltip from '@material-ui/core/Tooltip';
|
|
6
|
+
import Button from '@material-ui/core/Button';
|
|
7
|
+
import Chip from '@material-ui/core/Chip';
|
|
8
|
+
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
|
9
|
+
import Grid from '@material-ui/core/Grid';
|
|
10
|
+
import TablePagination from '@material-ui/core/TablePagination';
|
|
11
|
+
import Select from '@material-ui/core/Select';
|
|
12
|
+
import MenuItem from '@material-ui/core/MenuItem';
|
|
13
|
+
import TextField from '@material-ui/core/TextField';
|
|
14
|
+
import CircularProgress from '@material-ui/core/CircularProgress';
|
|
15
|
+
import { makeStyles, createStyles } from '@material-ui/core/styles';
|
|
16
|
+
import { EmptyState, InfoCard, Link, MarkdownContent } from '@backstage/core-components';
|
|
17
|
+
import GitHubIcon from '@material-ui/icons/GitHub';
|
|
18
|
+
import RetryIcon from '@material-ui/icons/Replay';
|
|
19
|
+
import SyncIcon from '@material-ui/icons/Sync';
|
|
20
|
+
import ExternalLinkIcon from '@material-ui/icons/Launch';
|
|
21
|
+
import { useRouteRef } from '@backstage/core-plugin-api';
|
|
22
|
+
import { useWorkflowRuns } from '../useWorkflowRuns.esm.js';
|
|
23
|
+
import { WorkflowRunStatus } from '../WorkflowRunStatus/WorkflowRunStatus.esm.js';
|
|
24
|
+
import { buildRouteRef } from '../../routes.esm.js';
|
|
25
|
+
import { getProjectNameFromEntity } from '../getProjectNameFromEntity.esm.js';
|
|
26
|
+
import { getHostnameFromEntity } from '../getHostnameFromEntity.esm.js';
|
|
27
|
+
import Alert from '@material-ui/lab/Alert';
|
|
28
|
+
|
|
29
|
+
const useStyles = makeStyles(
|
|
30
|
+
(theme) => createStyles({
|
|
31
|
+
card: {
|
|
32
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
33
|
+
boxShadow: theme.shadows[2],
|
|
34
|
+
borderRadius: "4px",
|
|
35
|
+
overflow: "visible",
|
|
36
|
+
position: "relative",
|
|
37
|
+
margin: theme.spacing(4, 1, 1),
|
|
38
|
+
flex: "1",
|
|
39
|
+
minWidth: "0px"
|
|
40
|
+
},
|
|
41
|
+
externalLinkIcon: {
|
|
42
|
+
fontSize: "inherit",
|
|
43
|
+
verticalAlign: "middle"
|
|
44
|
+
},
|
|
45
|
+
bottomline: {
|
|
46
|
+
display: "flex",
|
|
47
|
+
justifyContent: "space-between",
|
|
48
|
+
alignItems: "center",
|
|
49
|
+
marginTop: "-5px"
|
|
50
|
+
},
|
|
51
|
+
pagination: {
|
|
52
|
+
width: "100%"
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
const statusColors = {
|
|
57
|
+
skipped: "warning",
|
|
58
|
+
canceled: "info",
|
|
59
|
+
timed_out: "error",
|
|
60
|
+
failure: "error",
|
|
61
|
+
success: "success"
|
|
62
|
+
};
|
|
63
|
+
const matchesSearchTerm = (run, searchTerm) => {
|
|
64
|
+
const lowerCaseSearchTerm = searchTerm.toLocaleLowerCase();
|
|
65
|
+
return run.workflowName?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || run.source.branchName?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || run.status?.toLocaleLowerCase().includes(lowerCaseSearchTerm) || run.id?.toLocaleLowerCase().includes(lowerCaseSearchTerm);
|
|
66
|
+
};
|
|
67
|
+
const WorkflowRunsCardView = ({
|
|
68
|
+
runs,
|
|
69
|
+
searchTerm,
|
|
70
|
+
loading,
|
|
71
|
+
onChangePageSize,
|
|
72
|
+
onChangePage,
|
|
73
|
+
page,
|
|
74
|
+
total,
|
|
75
|
+
pageSize
|
|
76
|
+
}) => {
|
|
77
|
+
const classes = useStyles();
|
|
78
|
+
const routeLink = useRouteRef(buildRouteRef);
|
|
79
|
+
const filteredRuns = runs?.filter((run) => matchesSearchTerm(run, searchTerm));
|
|
80
|
+
return /* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 3 }, filteredRuns && runs?.length !== 0 ? filteredRuns.map((run) => /* @__PURE__ */ React.createElement(Grid, { key: run.id, item: true, container: true, xs: 12, sm: 4, md: 4, xl: 4 }, /* @__PURE__ */ React.createElement(Box, { className: classes.card }, /* @__PURE__ */ React.createElement(
|
|
81
|
+
Box,
|
|
82
|
+
{
|
|
83
|
+
display: "flex",
|
|
84
|
+
flexDirection: "column",
|
|
85
|
+
m: 3,
|
|
86
|
+
alignItems: "center",
|
|
87
|
+
justifyContent: "center"
|
|
88
|
+
},
|
|
89
|
+
/* @__PURE__ */ React.createElement(Box, { pt: 2, sx: { width: "100%" }, textAlign: "center" }, /* @__PURE__ */ React.createElement(
|
|
90
|
+
Tooltip,
|
|
91
|
+
{
|
|
92
|
+
title: run.status ?? "No Status",
|
|
93
|
+
placement: "top-start"
|
|
94
|
+
},
|
|
95
|
+
/* @__PURE__ */ React.createElement(
|
|
96
|
+
Alert,
|
|
97
|
+
{
|
|
98
|
+
variant: "outlined",
|
|
99
|
+
severity: statusColors[run.conclusion],
|
|
100
|
+
style: { alignItems: "center" }
|
|
101
|
+
},
|
|
102
|
+
/* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, /* @__PURE__ */ React.createElement(Link, { to: routeLink({ id: run.id }) }, /* @__PURE__ */ React.createElement(Typography, { color: "primary", variant: "h6" }, run.workflowName)))
|
|
103
|
+
)
|
|
104
|
+
), /* @__PURE__ */ React.createElement(Tooltip, { title: run.message ?? "No run message" }, /* @__PURE__ */ React.createElement(
|
|
105
|
+
Typography,
|
|
106
|
+
{
|
|
107
|
+
variant: "body2",
|
|
108
|
+
component: "span",
|
|
109
|
+
style: { fontSize: "smaller" }
|
|
110
|
+
},
|
|
111
|
+
/* @__PURE__ */ React.createElement(
|
|
112
|
+
MarkdownContent,
|
|
113
|
+
{
|
|
114
|
+
content: `Commit ID : ${run.source.commit.hash}`
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
)), run.source.branchName && /* @__PURE__ */ React.createElement(
|
|
118
|
+
MarkdownContent,
|
|
119
|
+
{
|
|
120
|
+
content: `Branch : ${run.source.branchName}`
|
|
121
|
+
}
|
|
122
|
+
), /* @__PURE__ */ React.createElement(
|
|
123
|
+
Chip,
|
|
124
|
+
{
|
|
125
|
+
key: run.id,
|
|
126
|
+
size: "small",
|
|
127
|
+
label: `Workflow ID : ${run.id}`
|
|
128
|
+
}
|
|
129
|
+
), /* @__PURE__ */ React.createElement(
|
|
130
|
+
Chip,
|
|
131
|
+
{
|
|
132
|
+
size: "small",
|
|
133
|
+
label: /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(
|
|
134
|
+
WorkflowRunStatus,
|
|
135
|
+
{
|
|
136
|
+
status: run.status,
|
|
137
|
+
conclusion: run.conclusion
|
|
138
|
+
}
|
|
139
|
+
))
|
|
140
|
+
}
|
|
141
|
+
), /* @__PURE__ */ React.createElement("div", { className: classes.bottomline }, run.githubUrl && /* @__PURE__ */ React.createElement(Link, { to: run.githubUrl }, "Workflow runs on GitHub", " ", /* @__PURE__ */ React.createElement(
|
|
142
|
+
ExternalLinkIcon,
|
|
143
|
+
{
|
|
144
|
+
className: classes.externalLinkIcon
|
|
145
|
+
}
|
|
146
|
+
)), /* @__PURE__ */ React.createElement(ButtonGroup, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Rerun workflow" }, /* @__PURE__ */ React.createElement(
|
|
147
|
+
IconButton,
|
|
148
|
+
{
|
|
149
|
+
onClick: run.onReRunClick,
|
|
150
|
+
style: { fontSize: "12px" }
|
|
151
|
+
},
|
|
152
|
+
/* @__PURE__ */ React.createElement(RetryIcon, null)
|
|
153
|
+
)))))
|
|
154
|
+
)))) : /* @__PURE__ */ React.createElement(Box, { p: 2 }, loading ? /* @__PURE__ */ React.createElement(CircularProgress, null) : "No matching runs found."), /* @__PURE__ */ React.createElement("div", { className: classes.pagination }, /* @__PURE__ */ React.createElement(
|
|
155
|
+
TablePagination,
|
|
156
|
+
{
|
|
157
|
+
component: "div",
|
|
158
|
+
count: total,
|
|
159
|
+
page,
|
|
160
|
+
rowsPerPage: pageSize,
|
|
161
|
+
onPageChange: (_, newPage) => onChangePage(newPage),
|
|
162
|
+
onRowsPerPageChange: (event) => onChangePageSize(parseInt(event.target.value, 6)),
|
|
163
|
+
labelRowsPerPage: "Workflows per page",
|
|
164
|
+
rowsPerPageOptions: [6, 12, 18, { label: "All", value: -1 }]
|
|
165
|
+
}
|
|
166
|
+
)));
|
|
167
|
+
};
|
|
168
|
+
const WorkflowRunsCardSearch = ({
|
|
169
|
+
searchTerm,
|
|
170
|
+
handleSearch,
|
|
171
|
+
retry
|
|
172
|
+
}) => {
|
|
173
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }), /* @__PURE__ */ React.createElement(
|
|
174
|
+
TextField,
|
|
175
|
+
{
|
|
176
|
+
type: "search",
|
|
177
|
+
label: "Search",
|
|
178
|
+
value: searchTerm,
|
|
179
|
+
onChange: handleSearch,
|
|
180
|
+
"data-testid": "search-control",
|
|
181
|
+
style: { marginRight: "20px" }
|
|
182
|
+
}
|
|
183
|
+
), /* @__PURE__ */ React.createElement(ButtonGroup, null, /* @__PURE__ */ React.createElement(Tooltip, { title: "Reload workflow runs" }, /* @__PURE__ */ React.createElement(IconButton, { onClick: retry }, /* @__PURE__ */ React.createElement(SyncIcon, null)))));
|
|
184
|
+
};
|
|
185
|
+
const WorkflowRunsCard = ({ entity }) => {
|
|
186
|
+
const projectName = getProjectNameFromEntity(entity);
|
|
187
|
+
const hostname = getHostnameFromEntity(entity);
|
|
188
|
+
const [owner, repo] = (projectName ?? "/").split("/");
|
|
189
|
+
const [branch, setBranch] = useState("default");
|
|
190
|
+
const [runs, setRuns] = useState([]);
|
|
191
|
+
const [searchTerm, setSearchTerm] = useState("");
|
|
192
|
+
const handleSearch = (event) => {
|
|
193
|
+
setSearchTerm(event.target.value);
|
|
194
|
+
};
|
|
195
|
+
const [
|
|
196
|
+
{ runs: runsData, branches, defaultBranch, ...cardProps },
|
|
197
|
+
{ retry, setPage, setPageSize }
|
|
198
|
+
] = useWorkflowRuns({
|
|
199
|
+
hostname,
|
|
200
|
+
owner,
|
|
201
|
+
repo,
|
|
202
|
+
branch: branch === "all" ? void 0 : branch
|
|
203
|
+
});
|
|
204
|
+
const githubHost = hostname || "github.com";
|
|
205
|
+
const hasNoRuns = !cardProps.loading && !runsData;
|
|
206
|
+
const handleMenuChange = (event) => {
|
|
207
|
+
const selectedValue = event.target.value;
|
|
208
|
+
setBranch(selectedValue);
|
|
209
|
+
setPage(0);
|
|
210
|
+
retry();
|
|
211
|
+
};
|
|
212
|
+
useEffect(() => {
|
|
213
|
+
setRuns(runsData);
|
|
214
|
+
}, [runsData, branch]);
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
setBranch(defaultBranch);
|
|
217
|
+
}, [defaultBranch]);
|
|
218
|
+
return /* @__PURE__ */ React.createElement(Grid, { item: true }, hasNoRuns ? /* @__PURE__ */ React.createElement(
|
|
219
|
+
EmptyState,
|
|
220
|
+
{
|
|
221
|
+
missing: "data",
|
|
222
|
+
title: "No Workflow Data",
|
|
223
|
+
description: "This component has GitHub Actions enabled, but no data was found. Have you created any Workflows? Click the button below to create a new Workflow.",
|
|
224
|
+
action: /* @__PURE__ */ React.createElement(
|
|
225
|
+
Button,
|
|
226
|
+
{
|
|
227
|
+
variant: "contained",
|
|
228
|
+
color: "primary",
|
|
229
|
+
href: `https://${githubHost}/${projectName}/actions/new`
|
|
230
|
+
},
|
|
231
|
+
"Create new Workflow"
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
) : /* @__PURE__ */ React.createElement(
|
|
235
|
+
InfoCard,
|
|
236
|
+
{
|
|
237
|
+
title: /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, /* @__PURE__ */ React.createElement(GitHubIcon, null), /* @__PURE__ */ React.createElement(Box, { mr: 1 }), /* @__PURE__ */ React.createElement(Typography, { variant: "h6" }, projectName), /* @__PURE__ */ React.createElement(
|
|
238
|
+
Select,
|
|
239
|
+
{
|
|
240
|
+
value: branch,
|
|
241
|
+
key: branch,
|
|
242
|
+
label: "Branch",
|
|
243
|
+
onChange: handleMenuChange,
|
|
244
|
+
"data-testid": "menu-control",
|
|
245
|
+
style: {
|
|
246
|
+
marginLeft: "30px",
|
|
247
|
+
marginRight: "20px",
|
|
248
|
+
width: "230px"
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
branches.map((branchItem) => /* @__PURE__ */ React.createElement(MenuItem, { key: branchItem.name, value: branchItem.name }, branchItem.name === defaultBranch ? /* @__PURE__ */ React.createElement(Typography, { variant: "body2", component: "span" }, branchItem.name, " ", /* @__PURE__ */ React.createElement(
|
|
252
|
+
Typography,
|
|
253
|
+
{
|
|
254
|
+
variant: "body2",
|
|
255
|
+
component: "span",
|
|
256
|
+
style: { color: "lightgray", fontSize: "x-small" }
|
|
257
|
+
},
|
|
258
|
+
"(default)"
|
|
259
|
+
)) : branchItem.name)),
|
|
260
|
+
/* @__PURE__ */ React.createElement(
|
|
261
|
+
MenuItem,
|
|
262
|
+
{
|
|
263
|
+
value: "all",
|
|
264
|
+
key: "all",
|
|
265
|
+
style: { color: "lightGrey", fontSize: "small" }
|
|
266
|
+
},
|
|
267
|
+
"select all branches"
|
|
268
|
+
)
|
|
269
|
+
), /* @__PURE__ */ React.createElement(
|
|
270
|
+
WorkflowRunsCardSearch,
|
|
271
|
+
{
|
|
272
|
+
searchTerm,
|
|
273
|
+
handleSearch,
|
|
274
|
+
retry
|
|
275
|
+
}
|
|
276
|
+
))
|
|
277
|
+
},
|
|
278
|
+
/* @__PURE__ */ React.createElement(
|
|
279
|
+
WorkflowRunsCardView,
|
|
280
|
+
{
|
|
281
|
+
runs,
|
|
282
|
+
loading: cardProps.loading,
|
|
283
|
+
onChangePageSize: setPageSize,
|
|
284
|
+
onChangePage: setPage,
|
|
285
|
+
page: cardProps.page,
|
|
286
|
+
total: cardProps.total,
|
|
287
|
+
pageSize: cardProps.pageSize,
|
|
288
|
+
searchTerm,
|
|
289
|
+
projectName
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
));
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export { WorkflowRunsCard, WorkflowRunsCardView, WorkflowRunsCard as default };
|
|
296
|
+
//# sourceMappingURL=WorkflowRunsCard.esm.js.map
|