UNPKG

@scott-the-programmer/backstage-plugin-spacelift

Version:

[![Maintainability](https://api.codeclimate.com/v1/badges/65206b49b30dfc4e2312/maintainability)](https://codeclimate.com/github/scott-the-programmer/backstage-plugin-spacelift/maintainability)

325 lines (315 loc) 8.7 kB
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