@scott-the-programmer/backstage-plugin-spacelift
Version:
[](https://codeclimate.com/github/scott-the-programmer/backstage-plugin-spacelift/maintainability)
325 lines (315 loc) • 8.7 kB
JavaScript
import { createApiRef, createRouteRef, createPlugin, createApiFactory, discoveryApiRef, createRoutableExtension, useApi } from '@backstage/core-plugin-api';
import { Table, Page, Header, Content } from '@backstage/core-components';
import React, { useState, useEffect } from 'react';
import { Link, Chip, Dialog, DialogTitle, DialogContent } from '@material-ui/core';
const spaceliftApiRef = createApiRef({
id: "plugin.spacelift.service"
});
class SpaceliftApiClient {
constructor(discoveryApi) {
this.discoveryApi = discoveryApi;
}
async getProjects() {
const url = await this.discoveryApi.getBaseUrl("spacelift");
try {
const response = await fetch(`${url}/projects`);
if (!response.ok) {
return [];
}
const res = await response.json();
return res;
} catch (error) {
return [];
}
}
async getUrl() {
const url = await this.discoveryApi.getBaseUrl("spacelift");
try {
const response = await fetch(`${url}/url`);
return (await response.json()).url;
} catch (error) {
return "";
}
}
async getRuns(stackId) {
const url = await this.discoveryApi.getBaseUrl("spacelift");
try {
const response = await fetch(`${url}/runs/${stackId}`);
if (!response.ok) {
return [];
}
const res = await response.json();
return res;
} catch (error) {
return [];
}
}
}
const rootRouteRef = createRouteRef({
id: "spacelift"
});
const spaceliftPlugin = createPlugin({
id: "spacelift",
apis: [
createApiFactory({
api: spaceliftApiRef,
deps: { discoveryApi: discoveryApiRef },
factory: ({ discoveryApi }) => new SpaceliftApiClient(discoveryApi)
})
],
routes: {
root: rootRouteRef
}
});
const SpaceliftPage = spaceliftPlugin.provide(
createRoutableExtension({
name: "SpaceliftPage",
component: () => Promise.resolve().then(function () { return Spacelift$1; }).then((m) => m.Spacelift),
mountPoint: rootRouteRef
})
);
const getStatusColor = (status) => {
let backgroundColor;
switch (status) {
case "FINISHED":
backgroundColor = "#00d474";
break;
case "FAILED":
case "DISCARDED":
case "STOPPED":
backgroundColor = "#fc2c03";
break;
case "NONE":
case "":
backgroundColor = "grey";
break;
case "INITIALIZING":
case "PLANNING":
case "UNCONFIRMED":
case "CONFIRMED":
case "APPLYING":
case "DESTROYING":
case "PREPARING":
case "PREPARING_APPLY":
default:
backgroundColor = "#fcca03";
break;
}
return backgroundColor;
};
const SpaceliftRuns = ({
stackId,
url
}) => {
const spaceliftApi = useApi(spaceliftApiRef);
const [runs, setRuns] = useState([]);
const [loading, setLoading] = useState(false);
const columns = [
{
title: "Run",
field: "createdAt",
render: (rowData) => /* @__PURE__ */ React.createElement(
Link,
{
href: `${url}/stack/${stackId}/run/${rowData.id}`,
target: "_blank",
rel: "noopener noreferrer"
},
new Date(rowData.createdAt * 1e3).toLocaleString()
)
},
{ title: "Branch", field: "branch" },
{
title: "Commit Hash",
field: "commit.hash",
render: (rowData) => /* @__PURE__ */ React.createElement(
Link,
{
href: rowData.commit.url,
target: "_blank",
rel: "noopener noreferrer"
},
rowData.commit.hash.slice(0, 7)
)
},
{ title: "Commit Author", field: "commit.authorName" },
{
title: "Commit Timestamp",
field: "commit.timestamp",
type: "datetime",
render: (rowData) => new Date(rowData.commit.timestamp * 1e3).toLocaleString()
},
{
title: "Status",
field: "state",
render: (rowData) => {
const color = getStatusColor(rowData.state);
return /* @__PURE__ */ React.createElement(
Chip,
{
label: rowData.state,
style: {
backgroundColor: color
}
}
);
}
}
];
useEffect(() => {
async function fetchRuns() {
setLoading(true);
const response = await spaceliftApi.getRuns(stackId);
setRuns(response);
setLoading(false);
}
fetchRuns();
}, [spaceliftApi, stackId]);
return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
Table,
{
title: "Runs",
isLoading: loading,
options: {
search: true,
paging: true,
pageSize: 5
},
columns,
data: runs
}
));
};
const StatusChip = ({ state }) => {
const color = getStatusColor(state);
return /* @__PURE__ */ React.createElement(
Chip,
{
label: state,
style: {
backgroundColor: color
}
}
);
};
const StackLink = ({
name,
onClick
}) => /* @__PURE__ */ React.createElement(Link, { component: "button", variant: "body2", onClick }, name);
const useFetchProjects = (spaceliftApi) => {
const [projects, setProjects] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
async function fetchProjects() {
setLoading(true);
const response = await spaceliftApi.getProjects();
const url = await spaceliftApi.getUrl();
const projectsWithUrls = response.map((project) => {
return { ...project, url };
});
setProjects(projectsWithUrls);
setLoading(false);
}
fetchProjects();
}, [spaceliftApi]);
return { projects, loading };
};
const SpaceliftStacks = () => {
const spaceliftApi = useApi(spaceliftApiRef);
const { projects, loading } = useFetchProjects(spaceliftApi);
const [selectedStack, setSelectedStack] = useState(null);
const [stackUrl, setStackUrl] = useState(null);
const [dialogOpen, setDialogOpen] = useState(false);
const columns = [
{
title: "Name",
field: "name",
render: (rowData) => /* @__PURE__ */ React.createElement(
StackLink,
{
name: rowData.name,
onClick: () => {
setSelectedStack(rowData.id);
setStackUrl(rowData.url || null);
setDialogOpen(true);
}
}
)
},
{
title: "Spacelift Url",
field: "url",
render: (rowData) => /* @__PURE__ */ React.createElement(
Link,
{
href: rowData.url ? `${rowData.url}/stack/${rowData.id}` : "",
target: "_blank",
rel: "noopener noreferrer"
},
rowData.url ? `${rowData.url}/stack/${rowData.id}` : ""
)
},
{ title: "Description", field: "description" },
{
title: "Source",
field: "repository",
render: (rowData) => /* @__PURE__ */ React.createElement(
Link,
{
href: `${rowData.apiHost}/${rowData.namespace}/${rowData.repository}/tree/${rowData.branch}`,
target: "_blank",
rel: "noopener noreferrer"
},
rowData.repository
)
},
{
title: "Status",
field: "state",
render: (rowData) => /* @__PURE__ */ React.createElement(StatusChip, { state: rowData.state })
}
];
return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
Table,
{
title: "Stacks",
isLoading: loading,
options: {
search: true,
paging: true,
pageSize: 5
},
columns,
data: projects,
style: {
margin: 20,
width: "100%"
}
}
), /* @__PURE__ */ React.createElement(
Dialog,
{
open: dialogOpen,
onClose: () => setDialogOpen(false),
fullWidth: true,
maxWidth: "md"
},
/* @__PURE__ */ React.createElement(DialogTitle, null, "Spacelift"),
/* @__PURE__ */ React.createElement(DialogContent, null, selectedStack && /* @__PURE__ */ React.createElement(SpaceliftRuns, { stackId: selectedStack, url: stackUrl || "" }))
));
};
const Spacelift = () => {
return /* @__PURE__ */ React.createElement(Page, { themeId: "tool" }, /* @__PURE__ */ React.createElement(
Header,
{
title: "Spacelift",
subtitle: "Spacelift is a platform for building, deploying, and managing infrastructure."
}
), /* @__PURE__ */ React.createElement(Content, null, /* @__PURE__ */ React.createElement(SpaceliftStacks, null)));
};
var Spacelift$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
Spacelift: Spacelift
});
export { Spacelift, SpaceliftPage, SpaceliftStacks, spaceliftPlugin };
//# sourceMappingURL=index.esm.js.map