@immobiliarelabs/backstage-plugin-gitlab
Version:
<p align="center"> <img src="https://avatars.githubusercontent.com/u/10090828?s=200&v=4" width="200px" alt="logo"/> </p> <h1 align="center">Backstage Plugin GitLab</h1>
197 lines (194 loc) • 6.66 kB
JavaScript
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Typography, Grid, Link } from '@material-ui/core';
import LocalOfferOutlinedIcon from '@material-ui/icons/LocalOfferOutlined';
import Alert from '@material-ui/lab/Alert';
import { Progress, InfoCard } from '@backstage/core-components';
import { GitlabCIApiRef } from '../../../api/GitlabCIApi.esm.js';
import '../../utils.esm.js';
import '@gitbeaker/rest';
import 'dayjs';
import { useApi } from '@backstage/core-plugin-api';
import { useAsync } from 'react-use';
import { gitlabProjectId, gitlabProjectSlug, gitlabInstance } from '../../gitlabAppData.esm.js';
import { valid, rcompare, prerelease } from 'semver';
import Select from '@material-ui/core/Select';
import MenuItem from '@material-ui/core/MenuItem';
import SortIcon from '@material-ui/icons/Sort';
import { useTranslationRef } from '@backstage/core-plugin-api/alpha';
import { gitlabTranslationRef } from '../../../translation.esm.js';
const useStyles = makeStyles((theme) => ({
infoCard: {
marginBottom: theme.spacing(3),
"& + .MuiAlert-root": {
marginTop: theme.spacing(3)
}
},
releaseTitle: {
...theme.typography.h6,
margin: 0,
marginRight: "0.5rem"
},
releaseTagIcon: {
verticalAlign: "middle"
},
sortSelector: {
display: "flex",
width: "100%",
justifyContent: "flex-end",
alignItems: "center"
}
}));
const sortFunctions = {
// sort (e.g. v1.2.3 comes before v1.2.3-alpha-4.5) and walk through list of releases
// NOTE: rcompare sorts descending, but full release comes before release candidates (v1.2.3 before v1.2.3-alpha-4.5)
// use string comparison for non-compliant tags
releasedVersion: (a, b) => {
try {
return rcompare(a.tag_name, b.tag_name);
} catch (error) {
return a.tag_name > b.tag_name ? 1 : -1;
}
},
// sort by released date
releasedDate: (a, b) => {
const d1 = new Date(a.released_at || a.created_at);
const d2 = new Date(b.released_at || b.created_at);
return d1.getTime() > d2.getTime() ? -1 : 1;
}
};
function makeFilter(show) {
switch (show) {
case "patch":
return (value) => {
try {
return prerelease(value.tag_name) === null;
} catch (error) {
return true;
}
};
case "all":
default:
return () => true;
}
}
const ReleasesCard = (props) => {
const { t } = useTranslationRef(gitlabTranslationRef);
const {
title = t("releasesCard.title"),
show = "all",
limit = 6,
sort = "releasedDate",
showSortSelector = true
} = props;
const classes = useStyles();
const project_id = gitlabProjectId();
const project_slug = gitlabProjectSlug();
const gitlab_instance = gitlabInstance();
const [currentSortRule, setCurrentSortRule] = React.useState(sort);
const GitlabCIAPI = useApi(GitlabCIApiRef).build(
gitlab_instance || "gitlab.com"
);
const { value, loading, error } = useAsync(async () => {
const projectDetails = await GitlabCIAPI.getProjectDetails(
project_slug || project_id
);
if (!projectDetails)
throw new Error("wrong project_slug or project_id");
const releaseData = await GitlabCIAPI.getReleasesSummary(
projectDetails.id
);
if (!releaseData) throw new Error("Release data are undefined!");
return {
releases: releaseData,
projectDetails
};
}, []);
const project_web_url = value?.projectDetails.web_url;
if (loading) {
return /* @__PURE__ */ React.createElement(Progress, null);
} else if (error) {
return /* @__PURE__ */ React.createElement(Alert, { severity: "error", className: classes.infoCard }, error.message);
}
let releases = [];
if (value?.releases != null) {
value?.releases.filter(makeFilter(show)).sort(sortFunctions[currentSortRule]).forEach((release) => {
if (!valid(release.tag_name)) {
releases.push(release);
return;
}
const idx = releases.findIndex((value2) => {
return release.tag_name.startsWith(value2.tag_name);
});
if (idx < 0) releases.push(release);
});
}
releases = releases.slice(0, limit);
if (releases.length === 0) {
return /* @__PURE__ */ React.createElement(
InfoCard,
{
title,
deepLink: {
link: `${project_web_url}/-/releases`,
title: t("releasesCard.deepLinkTitle"),
onClick: (e) => {
e.preventDefault();
window.open(`${project_web_url}/-/releases`);
}
},
variant: props.variant,
className: classes.infoCard
},
/* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, t("releasesCard.noReleases"))
);
}
const handleSortChange = (event) => {
setCurrentSortRule(event.target.value);
};
return /* @__PURE__ */ React.createElement(
InfoCard,
{
title,
deepLink: {
link: `${project_web_url}/-/releases`,
title: t("releasesCard.deepLinkTitle"),
onClick: (e) => {
e.preventDefault();
window.open(`${project_web_url}/-/releases`);
}
},
variant: props.variant,
className: classes.infoCard
},
/* @__PURE__ */ React.createElement(Grid, { container: true, spacing: 2, justifyContent: "flex-start" }, showSortSelector && /* @__PURE__ */ React.createElement("div", { className: classes.sortSelector }, /* @__PURE__ */ React.createElement(
Select,
{
id: "release-sort-selector",
value: currentSortRule,
onChange: handleSortChange
},
/* @__PURE__ */ React.createElement(MenuItem, { value: "releasedDate" }, t("releasesCard.releasedDate")),
/* @__PURE__ */ React.createElement(MenuItem, { value: "releasedVersion" }, t("releasesCard.releasedVersion"))
), /* @__PURE__ */ React.createElement(SortIcon, null)), releases.map((release) => /* @__PURE__ */ React.createElement(Grid, { item: true, key: release.tag_name }, /* @__PURE__ */ React.createElement(
Link,
{
href: project_web_url + "/-/releases/" + encodeURIComponent(release.tag_name),
color: "inherit",
target: "_blank",
rel: "noopener noreferrer"
},
/* @__PURE__ */ React.createElement("div", { className: classes.releaseTitle }, release.name),
/* @__PURE__ */ React.createElement(
LocalOfferOutlinedIcon,
{
fontSize: "inherit",
className: classes.releaseTagIcon
}
),
release.tag_name
))))
);
};
export { ReleasesCard };
//# sourceMappingURL=ReleasesCard.esm.js.map